Closes#4942
- Explain in *How to update* that data and extensions stay in the Docker volumes, so updating only means running a newer image with the same volumes, and recommend a back-up first.
- Add the Docker Compose variant (`pull` then `up` with the same `-f` files).
- Warn to keep the same major version of the PostgreSQL image when updating FreshRSS (a new major version refuses to start with older data), pointing to *Migrate database*, and to check `.env` variable names when replacing Compose files with newer copies.
* Update documentation of TRUSTED_PROXY syntax and document limitations.
Single IPs are now supported as of #9301.
Document the existing limitation of domain names, see #9210.
For IPs without `/`, I manually tested the behavior and found requests got rejected on my server before #9301. After #9301 is merged, I've tested again and found that requests are now authorized as expected. So I've updated the corresponding documentation to say "_IPs or_ ranges" where applicable.
Domain names are still silently ignored as of writing. I looked at the code, as described in #9210 investigation steps, and concluded that they are WAI (working as _implemented_ , not sure if _intended_ ). I don't particularly like the existing behavior (failures with no debuggable warnings or logs) but I try to document it as-is without judgement.
* Update TRUSTED_PROXY comments accordingly for Docker usage.
Single IPs are now supported as of #9301.
Document the existing limitation of domain names, see #9210.
* Reword explanations for edge/latest channels
Highlight the fact that we do not backport bug fixes or security fixes to previous releases.
Simplify also a slightly obsolte MySQL doc to favour SQLite
* Merge i18n: az
* Update Polish translations to specify rolling/versioned releases
Co-authored-by: Inverle <inverle@proton.me>
* Update 05_Release_new_version.md
---------
Co-authored-by: Inverle <inverle@proton.me>
* Dev updates: composer, hadolint, typos...
Composer compatibility PHP 8.6.
Manual updates not supported by Dependabot
* Fix hadolint
* Update lib/Minz/Url.php
Co-authored-by: Frans de Jonge <fransdejonge@gmail.com>
* Add sha256sum for composer
---------
Co-authored-by: Frans de Jonge <fransdejonge@gmail.com>
* Add Docker access log toggle
Allow container operators to disable Apache access logging with DISABLE_ACCESS_LOG=1 while preserving the existing default.
* Use positive access log toggle
* Include dev container
* Better POSIX compatibility
```
-E, -r, --regexp-extended
use extended regular expressions in the script
(for portability use POSIX -E).
```
Note: we should probably replace the other `sed -r` by `sed -E` elsewhere
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
## Problem
With OIDC on the official Docker image, interactive SSO logins intermittently return `HTTP 400` at the `/i/oidc/` callback. The failure tracks login duration. `mod_auth_openidc` sets an anti-CSRF state cookie bounded by `OIDCStateTimeout` (default 300 s). If a login through an external IdP takes longer than that (MFA, a slow provider screen, the user stepping away), the cookie is already gone when the callback returns. The image does not set `OIDCDefaultURL`, so the module has no fallback and returns an error instead of restarting the login.
Apache log:
```
oidc_response_proto_state_restore: state has expired
oidc_response_process: invalid authorization response state and
no default SSO URL is set, sending an error...
→ GET /i/oidc/?code=…&state=… 400
```
This is [documented mod_auth_openidc behaviour](https://github.com/OpenIDC/mod_auth_openidc/blob/72c9f479c2d228477ff0a9518964f61879c83fb6/auth_openidc.conf#L723-L733) when `OIDCDefaultURL` is unset. Both `OIDCDefaultURL` and `OIDCStateTimeout` are `RSRC_CONF` (server config only), so the `./FreshRSS/p/i/.htaccess` escape hatch cannot set them and the fix has to live in the image.
Reproduce: log out, start SSO, wait more than 5 minutes on the IdP screen, complete.
## Fix
Add `OIDC_DEFAULT_URL`, wired through the existing `${OIDC_*}` env pattern, defaulting to `/i/` (the index, consistent with `OIDCRedirectURI /i/oidc/`). On an expired or unmatchable state the module now redirects to `/i/`, which is protected and starts a fresh login against the existing IdP session. `OIDCStateTimeout` stays at 300 s; the window is fine, the missing fallback was the bug.
`OIDC_STATE_TIMEOUT` is intentionally not exposed. It can be added the same way if there is a reason to tune the window.
* Docker/OIDC: redirect to a default URL on expired auth state instead of 400-ing
Adds OIDC_DEFAULT_URL (default /i/), wired through the existing ${OIDC_*} env
pattern, so an expired or unmatchable mod_auth_openidc state redirects to the
FreshRSS index and restarts the login instead of returning HTTP 400.
* git commit update
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
The Docker Quick Run / cron examples use single-quoted `-e 'CRON_MIN=1,31'`. This works on Linux/macOS shells and PowerShell, but not on Windows `cmd.exe`, which does not strip single quotes from arguments — they end up included literally in the variable, so the cron job never gets scheduled correctly. Using `-e CRON_MIN=*/20` (no quotes) works, which was the original report.
Fixes#4818
* Docs: remove CRON_MIN quoting
---------
Co-authored-by: Gerard Alvear <gerard.alvear@logiqd.me>
* Add SSRF mitigations using `filter_var` and `CURLOPT_RESOLVE`
The idea is to prevent FreshRSS from sending any HTTP requests to internal services, except for the ones that are explicitly allowed in the config.
Based on https://github.com/moodle/moodle/blob/6e82b46a480826d1a85394d9e5087f7d82d1dd52/lib/filelib.php#L3818 and https://github.com/symfony/symfony/blob/8.1/src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.phphttps://github.com/FreshRSS/simplepie/pull/76https://github.com/FreshRSS/simplepie/pull/78
* Add allowlist setting in Web UI
* make readme
* Update app/i18n/fr/admin.php
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* make readme again
* make readme
* Further work
Still WIP and needs testing etc.
* Readd previous if check for domain combination allowlist
* Turn POST to GET after redirect
* Improve
* Update config.default.php
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* make readme
* Skip SSRF check if `CURLOPT_PROXY` is set
* make readme
* Fix `!empty()` mistake
* Respect max redirects feed option when fetching with `httpGet()`
* Respect max redirects during SimplePie fetching + fix bypass
bypass fix: `CURLOPT_FOLLOWLOCATION` was moved below so that emulated redirects are enforced.
* Avoid FreshRSS and Minz code in SimplePie
https://github.com/FreshRSS/FreshRSS/pull/8400#discussion_r2935375980
* Corrected hook code
* phpdoc wrong return type
* Add CIDR support in allowlist
* Implement simple DNS caching
* Suppress `dns_get_record()` warnings
* A bit of proof-reading
* Minor typo
* Fix proxy logic
* Fix HTTP POST redirect logic
* Proofread checkCIDR
Add fixes for several situations
* Remove credentials from URL in logs
* Ensure `CURLOPT_FOLLOWLOCATION` is `false` by setting it at the end
* Fix codesniffer long line
* Fix potential bypass due to wrong return value
If there were no records returned by `dns_get_record()`, no overrides to `CURLOPT_RESOLVE` would get passed,
and a potential bypass could occur, when cURL would try to resolve the domain by itself.
* Put the URL at the end in logs
* Add documentation and environment variable support
* make readme
* Fix wrong behavior in case of IP
* Fix duplicate selector in CSS
* Minor type check change
* i18n fr, en
* Minor type check change
* Fix whitespace i18n fr
* make fix-all
* Fix `$ips_ok` not being returned after domain records were cached
* make readme
* PHPStan fix
* make readme
* Minor syntax in SimplePie
* Only return `null` if no allowed IPs were found
* Add wildcard *, help message
* Consistent docs with help message
* i18n: pl
* SimplePie compatibility PHP 7.2
* make fix-all
* Sync SimplePie
* https://github.com/FreshRSS/simplepie/pull/76
* 💥 Breaking change in the Changelog
* Document `INTERNAL_HOST_ALLOWLIST` in Docker docs
* Remove `Cookie` and `Authorization` headers in `httpGet()` during cross-origin redirect
* Minor whitespace
And same comment convention than below
* Remove authentication headers and change POST to GET on redirect in SimplePie
* Remove .local in Docker example
* Fill in default ports when comparing URL origins
* Remove .local from other places than the Docker example
* Rewrite WebSub subscribe to use `httpGet()`
* make fix-all
* Also unset `CURLOPT_USERPWD` during redirects
* phpcs fix
* Always unset `CURLOPT_FOLLOWLOCATION`
* Bump SimplePie
https://github.com/FreshRSS/simplepie/pull/78
* Update logic for CURLOPT_FOLLOWLOCATION
* Fix PHPStan
* Changelog fix security section
* Update most common RSS Bridge case
https://hub.docker.com/r/rssbridge/rss-bridge
* Replace misleading 127.0.0.1:8080 example for Docker
This does not make sense for a Docker container
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* Better comments in our Docker images
* Make `cli/access-permissions.sh` compatible with other Apache groups such as `http` for Linux Arch
* Better `/Docker/entrypoint.sh` supporting various Apache configuration paths (and slightly faster).
* Add test image for Linux Arch (not sure we will keep it)
See
* https://github.com/FreshRSS/FreshRSS/pull/8279#issuecomment-3620674818
Better fix instead of https://github.com/FreshRSS/FreshRSS/pull/8216
Based on error message:
Error: in 18+, these Docker images are configured to store database data in a
format which is compatible with "pg_ctlcluster" (specifically, using
major-version-specific directory names). This better reflects how
PostgreSQL itself works, and how upgrades are to be performed.
See also https://github.com/docker-library/postgres/pull/1259
Counter to that, there appears to be PostgreSQL data in:
/var/lib/postgresql/data (unused mount/volume)
This is usually the result of upgrading the Docker image without
upgrading the underlying database using "pg_upgrade" (which requires both
versions).
The suggested container configuration for 18+ is to place a single mount
at /var/lib/postgresql which will then place PostgreSQL data in a
subdirectory, allowing usage of "pg_upgrade --link" without mount point
boundary issues.
See https://github.com/docker-library/postgres/issues/37 for a (long)
discussion around this process, and suggestions for how to do so.
* Rename tls.yml to tls.yaml
Rename tls.yaml so it will be align to the entry in docker-compose-proxy.yml:
volumes:
- ./tls.yaml:/etc/traefik/tls.yaml
To prevent error:
error="error reading configuration file: /etc/traefik/tls.yaml - read /etc/traefik/tls.yaml: is a directory"
* Update example.env
Added option for SERVER_URL
To prevent warning:
WARN[0000] The "SERVER_DNS" variable is not set. Defaulting to a blank string.
* Update example.env
Change SERVER_URL to SERVER_DNS
* Use .yml consistently
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
Force our Alpine-based Docker image to PHP 8.4 (default is still PHP 8.3).
Related to the fact that we may have to [revert our Debian image to Debian 12 with PHP 8.2 instead of Debian 13 with PHP 8.4](https://github.com/FreshRSS/FreshRSS/pull/7805), so for the next FreshRSS release, we can offer at least one image with PHP 8.4.
* Optimize how much data needs to be `chown`/`chmod`ed on container startup
This works around an issue where `chmod`/`chown` operations inside a
container can be extremely slow when using the `overlay2` storage
driver, resulting in 10min+ container startup times.
It modifies the owner of the webapp when building the container so that
only the `data` and `extensions` directories (which are commonly mapped
as volumes into the container) have to be modified by the
`access-permissions.sh` script at container startup.
When not running via docker the behaviour of the `access-permissions.sh`
script is unchanged.
* Take DATA_PATH environment variable into account when fixing permissions
* Revert change to using bash for arrays
(the alpine image doesn't include `bash`)
* A few more improvements
* Slightly tweak reapply permissions variable
- lowercase to indicate it's not an env variable
- use 0/1 to address potentially-irrational paranoia about unset variables
* Remove conditional logic to skip reapplying permissions
Also documents why in a comment so it's not missed in the future.
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* Adds BASE_URL to example .env file
I found without specifying a BASE_URL then the installation command gets confused
❌ FreshRSS error during installation!
FreshRSS error: invalid input: default-user cannot be empty
The provided example base url may not be desired, but the readme should be updated with 'something' to make first use more user friendly.
* Update Docker/README.md
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* Apache protect more non-public folders
* Also protect root
* Do the same for /p/
* Simplify Require all denied
In case of Apache 2.2, it will just make an error 500 instead of 403
* .htaccess.dist
* Simplify
* Better comment
* Fix OIDC session params definition
- standardize environment variable names
- group all in the same configuration file
- use mod_auth_openidc default values
- fix `OIDCSessionMaxDuration` because it was not set with the previous
code
- add documentation
* Add double quoting to prevent globbing and word splitting
* Revert line deleted by mistake