From 9eab456c3b1e4b91ef5077f03bc8e970b9fc8aa9 Mon Sep 17 00:00:00 2001 From: Ashley Date: Thu, 22 Oct 2026 02:03:28 +1030 Subject: [PATCH 1/7] Revert "Merge pull request #7878 from pixelfed/revert/docker-serversideup-v5-hardening" This reverts commit e17c93a8b95f7ce670159c4e90738217aaadf87c, reversing changes made to 1b9c1780b1c8ecd643dac57a6ed86e5463100a0a. --- .env.docker.example | 14 +++++++- Dockerfile | 4 +++ bootstrap/app.php | 1 + docker-compose.yml | 32 ++++++++++++++----- .../max-header-size.caddyfile | 3 ++ 5 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile diff --git a/.env.docker.example b/.env.docker.example index 75b14692e..bbdf6492e 100644 --- a/.env.docker.example +++ b/.env.docker.example @@ -25,7 +25,7 @@ MAX_PHOTO_SIZE="15000" MAX_CAPTION_LENGTH="500" MAX_ALBUM_LENGTH="4" MEDIA_TYPES="image/jpeg,image/jpg,image/png,image/gif" # Accepted upload mime types. -MODERN_MEDIA_TYPES="image/avif,image/jxl,image/webp" # webp/avif/jxl require the vips driver. +MODERN_MEDIA_TYPES="image/heic,image/heif,image/avif,image/jxl,image/webp" # webp/avif/jxl require the vips driver. # Instance URL Configuration # IMPORTANT: Update these with your actual domain @@ -33,6 +33,18 @@ APP_URL="https://yourdomain.com" APP_DOMAIN="yourdomain.com" ADMIN_DOMAIN="yourdomain.com" SESSION_DOMAIN=null # Keep as null unless required for sharing session cookies with subdomains like SSO + +# TRUSTED_PROXY (Required) +# Read by the serversideup FrankenPHP image. +# cloudflare (default) - trust Cloudflare ranges (CF-Connecting-IP) + Docker networks +# sucuri - trust Sucuri WAF ranges (X-Forwarded-For) + Docker networks +# local - trust only private/Docker network ranges (X-Forwarded-For) +# off - disable trusted proxy handling +TRUSTED_PROXY="local" + +# Trusted Proxies (Don't touch) +# TRUST_PROXIES is read by Laravel's TrustProxies middleware. The serversideup +# web server (Caddy) already validates the proxy before the request reaches PHP. TRUST_PROXIES="*" # Database Configuration diff --git a/Dockerfile b/Dockerfile index 37803ea18..86212c847 100644 --- a/Dockerfile +++ b/Dockerfile @@ -239,6 +239,10 @@ RUN tee /usr/local/etc/php/conf.d/zz-pixelfed.ini > /dev/null <<'EOF' ffi.enable=true EOF +# Caddy 2.11 caps request headers at 16KiB and returns 431 above that. Raise the +# limit so large cookies don't break requests, while staying well under the old 1MB. +COPY docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile /etc/frankenphp/caddyfile-global.d/max-header-size.caddyfile + COPY --from=ffmpeg /usr/local/ffmpeg/bin/ffmpeg /usr/bin/ffmpeg COPY --from=ffmpeg /usr/local/ffmpeg/bin/ffprobe /usr/bin/ffprobe COPY --from=ffmpeg /usr/local/ffmpeg/lib /usr/local/lib diff --git a/bootstrap/app.php b/bootstrap/app.php index 10e4c6f5c..551ead683 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -69,6 +69,7 @@ return Application::configure(basePath: dirname(__DIR__)) }, channels: __DIR__.'/../routes/channels.php', commands: __DIR__.'/../routes/console.php', + health: '/up', ) ->withMiddleware(function (Middleware $middleware) { $middleware->use([ diff --git a/docker-compose.yml b/docker-compose.yml index ac7e9b10f..a568a692d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -62,6 +62,8 @@ services: PHP_POST_MAX_SIZE: "500M" PHP_UPLOAD_MAX_FILE_SIZE: "500M" PHP_OPCACHE_ENABLE: "1" + PHP_OPCACHE_VALIDATE_TIMESTAMPS: "0" + HEALTHCHECK_PATH: "/up" # Laravel Auto-run Configuration AUTORUN_ENABLED: "true" @@ -72,12 +74,17 @@ services: AUTORUN_LARAVEL_ROUTE_CACHE: "true" AUTORUN_LARAVEL_VIEW_CACHE: "true" AUTORUN_LARAVEL_CONFIG_CACHE: "true" - volumes: - ./storage:/var/www/html/storage depends_on: - db - redis + healthcheck: + test: ["CMD", "healthcheck-frankenphp"] + interval: 10s + timeout: 5s + retries: 3 + start_period: 30s networks: - pixelfed-network @@ -91,6 +98,12 @@ services: env_file: - .env environment: + # PHP Configuration + PHP_POST_MAX_SIZE: "500M" + PHP_UPLOAD_MAX_FILE_SIZE: "500M" + PHP_OPCACHE_ENABLE: "1" + PHP_OPCACHE_VALIDATE_TIMESTAMPS: "0" + # Laravel Auto-run Configuration AUTORUN_ENABLED: "false" AUTORUN_LARAVEL_MIGRATION: "false" @@ -100,16 +113,13 @@ services: AUTORUN_LARAVEL_ROUTE_CACHE: "false" AUTORUN_LARAVEL_VIEW_CACHE: "false" AUTORUN_LARAVEL_CONFIG_CACHE: "true" - PHP_POST_MAX_SIZE: "500M" - PHP_UPLOAD_MAX_FILE_SIZE: "500M" - PHP_OPCACHE_ENABLE: "1" volumes: - ./storage:/var/www/html/storage depends_on: - db - redis healthcheck: - test: ["CMD", "php", "artisan", "horizon:status"] + test: ["CMD", "healthcheck-horizon"] interval: 10s timeout: 5s retries: 3 @@ -127,6 +137,12 @@ services: env_file: - .env environment: + # PHP Configuration + PHP_POST_MAX_SIZE: "500M" + PHP_UPLOAD_MAX_FILE_SIZE: "500M" + PHP_OPCACHE_ENABLE: "1" + PHP_OPCACHE_VALIDATE_TIMESTAMPS: "0" + # Laravel Auto-run Configuration AUTORUN_ENABLED: "false" AUTORUN_LARAVEL_MIGRATION: "false" @@ -136,9 +152,6 @@ services: AUTORUN_LARAVEL_ROUTE_CACHE: "false" AUTORUN_LARAVEL_VIEW_CACHE: "false" AUTORUN_LARAVEL_CONFIG_CACHE: "true" - PHP_POST_MAX_SIZE: "500M" - PHP_UPLOAD_MAX_FILE_SIZE: "500M" - PHP_OPCACHE_ENABLE: "1" volumes: - ./storage:/var/www/html/storage depends_on: @@ -146,6 +159,9 @@ services: - redis healthcheck: test: ["CMD", "healthcheck-schedule"] + interval: 10s + timeout: 5s + retries: 3 start_period: 10s networks: - pixelfed-network diff --git a/docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile b/docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile new file mode 100644 index 000000000..85352bb4d --- /dev/null +++ b/docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile @@ -0,0 +1,3 @@ +servers { + max_header_size 128KiB +} From 29cd115944628cfa36dc0b2aa43e206516eb7760 Mon Sep 17 00:00:00 2001 From: Shlee Date: Thu, 22 Oct 2026 02:07:06 +1030 Subject: [PATCH 2/7] Update comments in .env.docker.example Clarified comments regarding TRUSTED_PROXY and TRUST_PROXIES settings. --- .env.docker.example | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.env.docker.example b/.env.docker.example index bbdf6492e..e71a24c05 100644 --- a/.env.docker.example +++ b/.env.docker.example @@ -36,15 +36,15 @@ SESSION_DOMAIN=null # Keep as null unless required for sharing session cookies w # TRUSTED_PROXY (Required) # Read by the serversideup FrankenPHP image. -# cloudflare (default) - trust Cloudflare ranges (CF-Connecting-IP) + Docker networks +# local (default) - trust only private/Docker network ranges (X-Forwarded-For) +# cloudflare - trust Cloudflare ranges (CF-Connecting-IP) + Docker networks # sucuri - trust Sucuri WAF ranges (X-Forwarded-For) + Docker networks -# local - trust only private/Docker network ranges (X-Forwarded-For) # off - disable trusted proxy handling TRUSTED_PROXY="local" # Trusted Proxies (Don't touch) -# TRUST_PROXIES is read by Laravel's TrustProxies middleware. The serversideup -# web server (Caddy) already validates the proxy before the request reaches PHP. +# TRUST_PROXIES is read by Laravel's TrustProxies middleware. The serversideup web server (Caddy) +# already validates the proxy before the request reaches PHP via the TRUSTED_PROXY value. TRUST_PROXIES="*" # Database Configuration From 82fa7c63b6f0d33ee3ba492289814086acf0ffcc Mon Sep 17 00:00:00 2001 From: Ashley Date: Thu, 22 Oct 2026 02:17:32 +1030 Subject: [PATCH 3/7] Target the 8080 listener for max_header_size to avoid duplicate servers block --- docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile b/docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile index 85352bb4d..7e81b7332 100644 --- a/docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile +++ b/docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile @@ -1,3 +1,3 @@ -servers { +servers :8080 { max_header_size 128KiB } From 6fddf8f0f49378eb91fe2a8472991c409453b54c Mon Sep 17 00:00:00 2001 From: Ashley Date: Thu, 22 Oct 2026 02:27:20 +1030 Subject: [PATCH 4/7] Follow CADDY_HTTP_PORT for the max_header_size listener --- docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile b/docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile index 7e81b7332..04a4c138d 100644 --- a/docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile +++ b/docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile @@ -1,3 +1,3 @@ -servers :8080 { +servers :{$CADDY_HTTP_PORT:8080} { max_header_size 128KiB } From 15f8701698fb456892206b67453ec26e4c35db23 Mon Sep 17 00:00:00 2001 From: Ashley Date: Thu, 22 Oct 2026 02:31:34 +1030 Subject: [PATCH 5/7] Apply max_header_size to both HTTP and HTTPS listeners --- docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile b/docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile index 04a4c138d..c3304e224 100644 --- a/docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile +++ b/docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile @@ -1,3 +1,6 @@ servers :{$CADDY_HTTP_PORT:8080} { max_header_size 128KiB } +servers :{$CADDY_HTTPS_PORT:8443} { + max_header_size 128KiB +} From 08777005070c6420f54c5df533f87757e626cd55 Mon Sep 17 00:00:00 2001 From: Ashley Date: Thu, 22 Oct 2026 02:40:21 +1030 Subject: [PATCH 6/7] Drop unused max-header-size caddyfile and its COPY --- Dockerfile | 4 ---- .../frankenphp/caddyfile-global.d/max-header-size.caddyfile | 6 ------ 2 files changed, 10 deletions(-) delete mode 100644 docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile diff --git a/Dockerfile b/Dockerfile index 86212c847..37803ea18 100644 --- a/Dockerfile +++ b/Dockerfile @@ -239,10 +239,6 @@ RUN tee /usr/local/etc/php/conf.d/zz-pixelfed.ini > /dev/null <<'EOF' ffi.enable=true EOF -# Caddy 2.11 caps request headers at 16KiB and returns 431 above that. Raise the -# limit so large cookies don't break requests, while staying well under the old 1MB. -COPY docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile /etc/frankenphp/caddyfile-global.d/max-header-size.caddyfile - COPY --from=ffmpeg /usr/local/ffmpeg/bin/ffmpeg /usr/bin/ffmpeg COPY --from=ffmpeg /usr/local/ffmpeg/bin/ffprobe /usr/bin/ffprobe COPY --from=ffmpeg /usr/local/ffmpeg/lib /usr/local/lib diff --git a/docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile b/docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile deleted file mode 100644 index c3304e224..000000000 --- a/docker/frankenphp/caddyfile-global.d/max-header-size.caddyfile +++ /dev/null @@ -1,6 +0,0 @@ -servers :{$CADDY_HTTP_PORT:8080} { - max_header_size 128KiB -} -servers :{$CADDY_HTTPS_PORT:8443} { - max_header_size 128KiB -} From acdd8f2ae4853871964ca869db99e8db0df1d400 Mon Sep 17 00:00:00 2001 From: Shlee Date: Thu, 22 Oct 2026 02:55:51 +1030 Subject: [PATCH 7/7] Update docker-compose.yml --- docker-compose.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index a568a692d..4f0c48290 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,9 +50,12 @@ services: env_file: - .env environment: + HEALTHCHECK_PATH: "/up" + LOG_OUTPUT_LEVEL: "error" + # SSL Configuration (handled by reverse proxy) SSL_MODE: "off" - LOG_OUTPUT_LEVEL: "error" + # TODO: Once the new webui is completed, we will try to handle the service worker cache on that side. CADDY_SERVER_EXTRA_DIRECTIVES: | @service_worker path /sw.js @@ -63,7 +66,6 @@ services: PHP_UPLOAD_MAX_FILE_SIZE: "500M" PHP_OPCACHE_ENABLE: "1" PHP_OPCACHE_VALIDATE_TIMESTAMPS: "0" - HEALTHCHECK_PATH: "/up" # Laravel Auto-run Configuration AUTORUN_ENABLED: "true" @@ -98,6 +100,13 @@ services: env_file: - .env environment: + #HORIZON_SUPERVISOR_MEMORY: 64 # MB per queue worker + #HORIZON_MAX_PROCESSES: 10 # User-facing federation delivery (follows, deletes, DMs), inbox processing, and push notifications. + #HORIZON_DELIVER_MAX_PROCESSES: 6 # ? + #HORIZON_MEDIA_MAX_PROCESSES: 4 # Image/video optimization, resizing, and thumbnail generation (the `mmo` queue). + #HORIZON_FANOUT_MAX_PROCESSES: 6 # Timeline/story/group fanout writes triggered by posts, likes, and follows. + #HORIZON_BACKGROUND_MAX_PROCESSES: 4 # Imports, instance crawling, account deletion/migration, and other maintenance work that isn't user-facing time-sensitive. + # PHP Configuration PHP_POST_MAX_SIZE: "500M" PHP_UPLOAD_MAX_FILE_SIZE: "500M"