Skip to content

Commit c02169d

Browse files
authored
Update FrankenPHP to version 1.13 and adjust Mercure settings for compatibility (#715)
1 parent cd5b8a1 commit c02169d

4 files changed

Lines changed: 33 additions & 30 deletions

File tree

‎docs/content/docs/2.image-variations/frankenphp.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ The format follows Caddy's default as well. Caddy [writes human-readable `consol
344344
- `CADDY_LOG_FORMAT=console` if you read logs by eye with `docker compose logs` or `docker service logs` and want the colored, human-readable lines whether or not a terminal is attached.
345345
- `CADDY_LOG_FORMAT=json` if a container runs with a terminal attached but you still want structured logs.
346346

347-
In both formats the request log redacts the `authorization` query parameter, so the JWT that [Mercure subscribers pass in the URL](https://mercure.rocks/spec#authorization){target="_blank"} never lands in your logs. This is the same filter that [FrankenPHP's own Caddyfile](https://github.com/php/frankenphp/blob/main/caddy/frankenphp/Caddyfile){target="_blank"} recommends.
347+
In both formats the request log redacts the `authorization` query parameter, so the JWT that Mercure 0.x subscribers pass in the URL never lands in your logs. This is the same filter that [FrankenPHP's own Caddyfile](https://github.com/php/frankenphp/blob/main/caddy/frankenphp/Caddyfile){target="_blank"} recommends.
348348

349349
::warning
350350
Laravel Octane only relays FrankenPHP's `stderr` and only understands JSON, so leave `CADDY_LOG_OUTPUT` and `CADDY_LOG_FORMAT` at their defaults when you run Octane. See [Logging with Octane](/docs/framework-guides/laravel/octane#logging).

‎docs/content/docs/3.framework-guides/1.laravel/octane.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ Octane also decides the log level. It sets `CADDY_SERVER_LOG_LEVEL` to `INFO` wh
163163
If you want request logs in production, pass `--log-level=INFO` to `octane:start`. You get one JSON object per request on `stderr`, ready for your log collector.
164164
::
165165

166-
The request log redacts the `authorization` query parameter, so the JWT that [Mercure subscribers pass in the URL](https://mercure.rocks/spec#authorization){target="_blank"} never lands in your logs. This is the same filter that [FrankenPHP's own Caddyfile](https://github.com/php/frankenphp/blob/main/caddy/frankenphp/Caddyfile){target="_blank"} recommends.
166+
The request log redacts the `authorization` query parameter, so the JWT that Mercure 0.x subscribers pass in the URL never lands in your logs. This is the same filter that [FrankenPHP's own Caddyfile](https://github.com/php/frankenphp/blob/main/caddy/frankenphp/Caddyfile){target="_blank"} recommends.
167167

168168
## PHP Settings Still Apply
169169
Octane does not change how PHP loads its configuration. FrankenPHP reads the same `php.ini` files from `/usr/local/etc/php/conf.d/` in every mode, so all of the `PHP_*` environment variables (like `PHP_MEMORY_LIMIT` and `PHP_OPCACHE_ENABLE`) work exactly as they do in classic mode. Any custom `.ini` files you mount into that directory apply as well.

‎docs/content/docs/5.guide/5.major-version-migrations.md‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,15 @@ Octane also needs the Caddy admin API and sets `CADDY_GLOBAL_OPTIONS` for itself
140140
#### FrankenPHP: `REMOTE_ADDR` is now the client IP resolved from trusted proxies
141141
Version 4 set `$_SERVER['REMOTE_ADDR']` to the TCP peer on FrankenPHP, even when Caddy had already worked out the real client IP for the access log. It now matches what Caddy resolved, the same as NGINX and Apache, and Caddy runs in strict mode so a client behind a trusted proxy cannot forge it. You are affected if anything in your app compares `REMOTE_ADDR` to a proxy's address. [Read the trusted proxies guide →](/docs/guide/configuring-trusted-proxies)
142142

143+
#### FrankenPHP: Mercure 1.0 rejects `publisher_jwt` and `subscriber_jwt`
144+
Version 5 ships FrankenPHP 1.13, which includes Mercure 1.0. If you enable the Mercure hub with `publisher_jwt` or `subscriber_jwt`, including through the `mercure` array in `config/octane.php`, FrankenPHP now fails to start. Move the keys into an `issuer` block as shown in [FrankenPHP's Laravel guide](https://frankenphp.dev/docs/laravel/#mercure-support){target="_blank"}, or add `protocol_version_compatibility 8` to keep your current settings while you migrate. The [Mercure 1.0 upgrade guide](https://github.com/dunglas/mercure/blob/v1.0.3/docs/UPGRADE.md){target="_blank"} covers the client changes.
145+
146+
#### FrankenPHP: Caddy limits request headers
147+
FrankenPHP 1.13 includes [Caddy 2.11.7](https://github.com/caddyserver/caddy/releases/tag/v2.11.7){target="_blank"}. Requests with more than 16 KiB of headers now get a `431 Request Header Fields Too Large` response, where Version 4 allowed 1 MB. Large cookies are the usual cause. Headers with a `.` in their name are now dropped, like headers with a `_`, because PHP reads both as `-` and a client could use them to spoof headers like `X-Forwarded-For`.
148+
149+
#### FrankenPHP: `num_threads` no longer includes worker threads
150+
If you set `num_threads` in `FRANKENPHP_CONFIG` while running workers, including Laravel Octane, FrankenPHP now starts that many threads on top of the worker threads, and fails to start if `max_threads` is lower than the total. Lower `num_threads` to the number of threads you want for regular requests.
151+
143152
### Fixes
144153
- `PHP_OPCACHE_FORCE_RESTART_TIMEOUT` existed in Version 4 but never reached `php.ini`. It now works. The default of `180` matches PHP's own default, so nothing changes unless you had set it to something else.
145154

@@ -182,7 +191,7 @@ The OPcache values apply only when `PHP_OPCACHE_ENABLE=1`, and the memory is onl
182191
- **Trusted proxies on every web server** - `TRUSTED_PROXY` gives `fpm-nginx`, `fpm-apache`, and `frankenphp` the same Cloudflare, Sucuri, local, or off behavior, and all three resolve the client IP through more than one Docker hop. [Read the trusted proxies guide →](/docs/guide/configuring-trusted-proxies)
183192
- **Short-lived and IP-address certificates** - FrankenPHP can request Let's Encrypt's short-lived profile with `CADDY_ACME_PROFILE`. [Read about short-lived certificates →](/docs/deployment-and-production/configuring-ssl#short-lived--ip-address-certificates)
184193
- **Laravel Nightwatch health check** - `healthcheck-nightwatch` runs `php artisan nightwatch:status` so Docker can watch the agent. [Read the Nightwatch guide →](/docs/framework-guides/laravel/nightwatch)
185-
- **FrankenPHP redacts the `authorization` query parameter** - Request logs never contain the JWT that Mercure subscribers pass in the URL, in every log format. [Read about FrankenPHP logging →](/docs/image-variations/frankenphp#logging)
194+
- **FrankenPHP redacts the `authorization` query parameter** - Request logs never contain the JWT that Mercure 0.x subscribers pass in the URL, in every log format. [Read about FrankenPHP logging →](/docs/image-variations/frankenphp#logging)
186195
- **Every image is tested before it is published** - Each image is started on `amd64` and `arm64` and checked before it reaches Docker Hub. If one image fails, nothing from that build is published. [Read what happens when you open a pull request →](/docs/getting-started/contributing#what-happens-when-you-open-a-pull-request)
187196

188197
### V5 Migration Checklist
@@ -195,6 +204,7 @@ The OPcache values apply only when `PHP_OPCACHE_ENABLE=1`, and the memory is onl
195204
- If your app calls `session_start()` itself and reads the session cookie from JavaScript, add `PHP_SESSION_COOKIE_HTTPONLY=Off`
196205
- If you run FrankenPHP and something reads only `stdout`, add `CADDY_LOG_OUTPUT=stdout`. If something parses the `console` lines, or you prefer them when reading logs by eye, add `CADDY_LOG_FORMAT=console`. Skip both if you run Laravel Octane
197206
- If you run Laravel Octane, add `--caddyfile=/etc/frankenphp/Caddyfile` to your `octane:start` command and remove any `FRANKENPHP_CONFIG` worker block or `CADDY_PHP_SERVER_OPTIONS` you added to make Octane work
207+
- If you run the Mercure hub on FrankenPHP, move `publisher_jwt` and `subscriber_jwt` into an `issuer` block, or add `protocol_version_compatibility 8`
198208

199209
#### Dockerfile
200210
- If you append to `/etc/s6-overlay/s6-rc.d/<service>/dependencies` for `php-fpm`, `nginx`, or `apache2`, move each line to an empty file in that service's `dependencies.d/` directory

‎src/variations/frankenphp/Dockerfile‎

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
ARG BASE_OS_VERSION='trixie'
33
ARG PHP_VERSION='8.5'
44
ARG BASE_IMAGE="php:${PHP_VERSION}-zts-${BASE_OS_VERSION}"
5-
ARG FRANKENPHP_VERSION='1.12.7'
6-
ARG CADDY_VERSION='v2.11.4'
7-
ARG GOLANG_VERSION='1.26'
5+
ARG FRANKENPHP_VERSION='1.13.0'
6+
ARG GOLANG_VERSION='1.27'
87

98
########################
109
# Common
@@ -52,7 +51,6 @@ FROM golang:${GOLANG_VERSION} AS golang-image
5251
####################
5352
FROM common AS frankenphp-build
5453
ARG FRANKENPHP_VERSION
55-
ARG CADDY_VERSION
5654
ARG GOLANG_VERSION
5755
ARG BUILD_DEPENDENCY_PACKAGES_ALPINE="\
5856
argon2-dev \
@@ -95,9 +93,6 @@ COPY --from=golang-image /usr/local/go /usr/local/go
9593
ENV PATH="/usr/local/go/bin:${PATH}"
9694
ENV GOTOOLCHAIN="local"
9795

98-
# Copy xcaddy in the builder image
99-
COPY --from=caddy:builder /usr/bin/xcaddy /usr/bin/xcaddy
100-
10196
# Install dependencies & Download FrankenPHP
10297
RUN docker-php-serversideup-dep-install-alpine "$PHPIZE_DEPS ${BUILD_DEPENDENCY_PACKAGES_ALPINE}" && \
10398
docker-php-serversideup-dep-install-debian "${BUILD_DEPENDENCY_PACKAGES_DEBIAN}"
@@ -119,33 +114,31 @@ RUN WATCHER_TARBALL_URL=$(docker-php-serversideup-download https://api.github.co
119114
ldconfig; \
120115
fi
121116

122-
# Download and build FrankenPHP
117+
# Build FrankenPHP the way the official images do. go install takes every module
118+
# version from caddy/go.sum and applies the PGO profile in caddy/frankenphp,
119+
# while xcaddy resolves the latest Caddy release at build time (see #712)
123120
WORKDIR /go/src/app
124121
ENV GOBIN=/usr/local/bin
125122

123+
RUN git clone --depth 1 --branch "v${FRANKENPHP_VERSION}" \
124+
https://github.com/php/frankenphp.git .
125+
126+
WORKDIR /go/src/app/caddy/frankenphp
126127
RUN if cat /etc/os-release | grep -q 'debian'; then \
127-
export ADDITIONAL_BUILD_FLAGS=''; \
128+
export ADDITIONAL_LDFLAGS=''; \
128129
elif cat /etc/os-release | grep -q 'alpine'; then \
129-
export ADDITIONAL_BUILD_FLAGS="-extldflags '-Wl,-z,stack-size=0x80000'"; \
130+
export ADDITIONAL_LDFLAGS="-extldflags '-Wl,-z,stack-size=0x80000'"; \
130131
fi; \
131-
git clone --depth 1 --branch v${FRANKENPHP_VERSION} \
132-
https://github.com/php/frankenphp.git .; \
133132
CGO_ENABLED=1 \
134-
XCADDY_SETCAP=1 \
135-
XCADDY_GO_BUILD_FLAGS="-ldflags='-w -s' -tags=nobadger,nomysql,nopgx" \
136-
CGO_CFLAGS="-DFRANKENPHP_VERSION=${FRANKENPHP_VERSION} $(php-config --includes) $ADDITIONAL_BUILD_FLAGS" \
137-
CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \
138-
# CADDY_VERSION and the plugin versions must match caddy/go.mod at the pinned
139-
# FRANKENPHP_VERSION tag, otherwise xcaddy resolves the latest release, which
140-
# may need a newer Go or ship a regression upstream never tested against
141-
xcaddy build "${CADDY_VERSION}" \
142-
--output /usr/local/bin/frankenphp \
143-
--with github.com/dunglas/frankenphp=./ \
144-
--with github.com/dunglas/frankenphp/caddy=./caddy/ \
145-
--with github.com/dunglas/caddy-cbrotli@v1.0.1 \
146-
# Mercure and Vulcain are included in the official build, but feel free to remove them
147-
--with github.com/dunglas/mercure/caddy@v0.24.2 \
148-
--with github.com/dunglas/vulcain/caddy@v1.4.2
133+
CGO_CFLAGS="-DFRANKENPHP_VERSION=v${FRANKENPHP_VERSION} ${PHP_CFLAGS}" \
134+
CGO_CPPFLAGS="${PHP_CPPFLAGS}" \
135+
CGO_LDFLAGS="-L/usr/local/lib -lssl -lcrypto -lreadline -largon2 -lcurl -lonig -lz ${PHP_LDFLAGS}" \
136+
../../go.sh install \
137+
-ldflags "-w -s ${ADDITIONAL_LDFLAGS} -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP v${FRANKENPHP_VERSION} PHP ${PHP_VERSION} Caddy' -X 'github.com/caddyserver/caddy/v2.CustomBinaryName=frankenphp' -X 'github.com/caddyserver/caddy/v2/modules/caddyhttp.ServerHeader=FrankenPHP Caddy'" \
138+
-buildvcs=true && \
139+
setcap cap_net_bind_service=+ep /usr/local/bin/frankenphp && \
140+
frankenphp version && \
141+
frankenphp build-info
149142

150143
####################
151144
# FrankenPHP Final

0 commit comments

Comments
 (0)