Repository navigation
Releases: serversideup/docker-php
Release list
v5.0.0
🤩 What's new
Short-lived & IP address certificates for FrankenPHP
FrankenPHP can now request Let's Encrypt's new short-lived (~6-day) certificate profile through the new `CADDY_ACME_PROFILE` variable. Short-lived certificates skip revocation entirely, and the same profile is what lets you issue certificates for raw IP addresses, which is handy for services that don't have a domain in front of them.
Configure short-lived & IP certificates →
Native Laravel Octane support with a hardened and optimized Caddyfile (#604)
Add --caddyfile=/etc/frankenphp/Caddyfile to octane:start and FrankenPHP switches into worker mode with the same trusted proxies, security headers, asset caching, SSL modes, and health check as classic mode. Octane's --workers, --watch, --max-requests, octane:status, and octane:reload all work. No wrapper script, no second Caddyfile.
command: ["php", "artisan", "octane:start", "--server=frankenphp", "--port=8080", "--caddyfile=/etc/frankenphp/Caddyfile"]Thanks to @aSeriousDeveloper for opening the original PR and coolio85 on Discord for the workaround that started it.
Expanded OPcache support and better defaults (#704)
OPcache is still off by default to save your hair when you're in development. When you set PHP_OPCACHE_ENABLE=1, you now get the settings from Symfony's performance guide instead of PHP's stock values: more memory, room for more files, and no filesystem checks per request. Preloading is available with PHP_OPCACHE_PRELOAD. This is a breaking change if you mount your code as a volume with OPcache enabled (see below).
Read the production performance tuning guide →
Trusted proxy support for every variation (#643)
TRUSTED_PROXY now works the same way across all variations (FrankenPHP, NGINX, and Apache), so your app sees the real client IP whether it's behind Cloudflare, a load balancer, or your own reverse proxy. The version in the v4.6.0 betas returned the wrong IP in multi-hop Docker setups (#703). That's fixed, and FrankenPHP's REMOTE_ADDR now matches what Caddy resolves. FrankenPHP users also get /etc/frankenphp/caddyfile-global.d/ for global Caddy config without escaping CADDY_GLOBAL_OPTIONS.
Native Laravel Nightwatch support (#572)
Added a native health check for Laravel Nightwatch, complete with documentation to wire it up.
Laravel Nightwatch with Docker →
CI improvements: Every image is tested before it's published (#700)
Build and publish used to be one step. Now every image is built for amd64 and arm64, pulled on native runners, and checked before anything ships: it starts, runs unprivileged, loads the default extensions, passes its health check, and serves PHP through its web server. If one image fails, nothing from that run is published. Read more about how this works in #700.
New environment variables
All of them are documented in the environment variable specification.
| Variable | Default | Applies to | What it does | Learn more |
|---|---|---|---|---|
TRUSTED_PROXY |
cloudflare |
fpm-nginx, fpm-apache, frankenphp | Which proxy IPs are trusted to pass the real client IP. Options: cloudflare, sucuri, local, or off. |
#643 |
CADDY_ACME_PROFILE |
off |
frankenphp | Select a Let's Encrypt certificate profile: shortlived (~6-day certs, required for IP-address certificates), tlsserver, classic, or off. |
Configuring SSL |
LARAVEL_OCTANE |
unset | frankenphp | Set by Octane, not by you. The Caddyfile uses it to switch into worker mode. | #604 |
AUTORUN_LARAVEL_SKIP_IF_NOT_FOUND |
false |
all | When true, Laravel automations exit gracefully if Laravel is not found in APP_BASE_DIR instead of failing the container. Requires AUTORUN_ENABLED=true. |
Laravel automations |
PHP_OPCACHE_ENABLE_CLI |
1 |
all | Whether CLI commands use OPcache when PHP_OPCACHE_ENABLE=1. 1 is what v4 did. Set to 0 to keep OPcache on for the web server only. |
#704 |
PHP_OPCACHE_PRELOAD |
"" |
all | Path to a preload script. | #704 |
PHP_OPCACHE_PRELOAD_USER |
"" |
all | The user to preload as when the container runs as root. | #704 |
PHP_FILE_UPLOADS |
On |
all | Whether to allow HTTP file uploads. Set to Off to harden apps that never accept uploads. |
#697 |
PHP_MAX_FILE_UPLOADS |
20 |
all | Maximum number of files that can be uploaded in a single request. | #697 |
PHP_DISABLE_FUNCTIONS |
"" |
all | Comma-separated list of PHP functions to disable, such as exec,shell_exec. Empty because Laravel, Composer, and Symfony Process rely on proc_open. |
#692 |
PHP_HTML_ERRORS |
On |
all | Format on-screen errors as HTML when PHP_DISPLAY_ERRORS is on. Never affects logged errors, and PHP forces it off for the CLI. |
#692 |
PHP_REALPATH_CACHE_SIZE |
4096K |
all | Size of PHP's realpath cache. Apps with a large vendor/ directory may benefit from raising it. |
#692 |
PHP_SESSION_COOKIE_HTTPONLY |
On |
all | Adds the HttpOnly flag to the native PHP session cookie so browser scripts cannot read it. See the note below. |
#692 |
Changed defaults
The PHP_OPCACHE_* values only apply when PHP_OPCACHE_ENABLE=1. CADDY_* applies to FrankenPHP only.
| Variable | v4 | v5 |
|---|---|---|
PHP_OPCACHE_VALIDATE_TIMESTAMPS |
1 |
0 |
PHP_OPCACHE_MEMORY_CONSUMPTION |
128 |
256 |
PHP_OPCACHE_INTERNED_STRINGS_BUFFER |
8 |
32 |
PHP_OPCACHE_MAX_ACCELERATED_FILES |
10000 |
32531 |
PHP_REALPATH_CACHE_TTL |
120 |
600 |
CADDY_LOG_OUTPUT |
stdout |
stderr |
CADDY_LOG_FORMAT |
console |
auto |
Add your own Caddyfile rules from a folder
FrankenPHP users can now drop a .caddyfile into /etc/frankenphp/caddyfile-server.d/ to add headers, redirects, or request matchers to their app's site. Before, the only way to do that was CADDY_SERVER_EXTRA_DIRECTIVES, which gets awkward past one line and is replaced when Laravel Octane starts FrankenPHP. The folder works in classic mode and with Octane.
# embed-cache.caddyfile
@embed path /embed.js
header @embed >Cache-Control "public, max-age=3600"volumes:
- ./embed-cache.caddyfile:/etc/frankenphp/caddyfile-server.d/embed-cache.caddyfileEach level of the Caddyfile now has an environment variable for one-liners and a folder for files:
| Level | Environment variable | Folder |
|---|---|---|
| Global options | CADDY_GLOBAL_OPTIONS |
/etc/frankenphp/caddyfile-global.d/ |
| Your app's site | CADDY_SERVER_EXTRA_DIRECTIVES |
/etc/frankenphp/caddyfile-server.d/ (new) |
| Extra sites | none | /etc/frankenphp/caddyfile.d/ |
Rules in caddyfile-server.d/ apply on every listener SSL_MODE creates, and Docker's health check goes through them too. If you add a catch-all rule like basic_auth, leave /healthcheck out of it. The docs show how.
Add your own Caddyfile rules →
⚠️ Breaking changes
The v4 → v5 migration guide walks through each of these with a checklist. To stay on v4 while you review, pin your tag to v4.5.1 (for example serversideup/php:8.4-fpm-nginx-v4.5.1).
Dropped PHP 7.4 and 8.0 (#699)
Debian 11 (Bullseye) LTS ended on 2026-08-31, and the following week Debian removed the Bullseye packages from its mirrors, so we can no longer install anything inside the build. PHP 7.4 and 8.0 only ever shipped on Bullseye and Alpine 3.16, which reached EOL in 2024, so both go with it. PHP 8.1 is EOL too, but stays built (pinned to 8.1.34) on bookworm, trixie, and alpine3.22 because those bases still receive security updates.
PHP 8.1 also drops alpine3.21. Alpine 3.21 is supported until 2026-11-01, but 8.1 is EOL and only needs one Alpine base, so 8.1 on Alpine now means alpine3.22. Change 8.1-*-alpine3.21 tags to 8.1-*-alpine3.22.
Your existing tags still work. Every 7.4, 8.0, and 8.1 alpine3.21 tag stays pullable, frozen at its last successful build. If you need to install a package on one while you migrate, the migration guide has an unsupported recipe.
Our supported matrix is now PHP 8.2 – 8.5 on bookworm, trixie, alpine3.23, and alpine3.24, plus PHP 8.1 on bookworm, trixie, and alpine3.22. SECURITY.md now states the rule: we build an image while its official base image exists and the operating system still receives security updates.
v5.0.0-beta5
🤩 What's new
FrankenPHP: add your own Caddyfile rules from a folder
Drop a .caddyfile into /etc/frankenphp/caddyfile-server.d/ to add headers, redirects, or request matchers to your app's site. Before, the only way to do that was CADDY_SERVER_EXTRA_DIRECTIVES, which gets awkward past one line and is replaced when Laravel Octane starts FrankenPHP. The folder works in classic mode and with Octane.
This example gives one JavaScript file a short cache, overriding the year-long cache the image sets for static assets:
# embed-cache.caddyfile
@embed path /embed.js
header @embed >Cache-Control "public, max-age=3600"volumes:
- ./embed-cache.caddyfile:/etc/frankenphp/caddyfile-server.d/embed-cache.caddyfileEach level of the Caddyfile now has an environment variable for one-liners and a folder for files:
| Level | Environment variable | Folder |
|---|---|---|
| Global options | CADDY_GLOBAL_OPTIONS |
/etc/frankenphp/caddyfile-global.d/ |
| Your app's site | CADDY_SERVER_EXTRA_DIRECTIVES |
/etc/frankenphp/caddyfile-server.d/ (new) |
| Extra sites | none | /etc/frankenphp/caddyfile.d/ |
If you tried putting a header rule in caddyfile.d/ and got "request matchers may not be defined globally", this is the folder you wanted. caddyfile.d/ sits outside your app's site and only takes whole site blocks.
Rules in caddyfile-server.d/ apply on every listener SSL_MODE creates, and Docker's health check goes through them too. If you add a catch-all rule like basic_auth, leave /healthcheck out of it or the container will be marked unhealthy.
Add your own Caddyfile rules →
Full Changelog: v5.0.0-beta4...v5.0.0-beta5
v5.0.0-beta4
🤩 What's new
FrankenPHP turns on Mercure with environment variables
FrankenPHP 1.13 ships Mercure 1.0, which moved the JWT keys into a new issuer block. You don't need to write that Caddyfile syntax yourself (or put it in a PHP heredoc in config/octane.php). Set a few environment variables and the hub answers at /.well-known/mercure:
environment:
MERCURE_ENABLED: "true"
MERCURE_TRUSTED_ISSUERS: "https://example.com"
MERCURE_PUBLISHER_JWT_KEY: "${MERCURE_JWT_SECRET}"
MERCURE_SUBSCRIBER_JWT_KEY: "${MERCURE_JWT_SECRET}"This works in classic mode and with Laravel Octane. If you run Octane, leave the mercure array out of config/octane.php. With SSL_MODE=mixed or full, that array creates more than one Mercure hub, and Mercure 1.0 refuses to start.
FrankenPHP 1.13 (#715)
We're now on FrankenPHP 1.13.0 with Caddy 2.11.7. It fixes the HTTP/2 crash from beta3 and four security advisories that affect our images (see below).
We also build FrankenPHP the same way the official dunglas/frankenphp image does now, with go install from FrankenPHP's own go.mod. We used to build with xcaddy, which grabbed the latest Caddy at build time. That's how Caddy 2.11.6 got into beta3 without a single change in this repo. Now the binary only changes when we bump FRANKENPHP_VERSION.
frankenphp version also prints the full version now: FrankenPHP v1.13.0 PHP 8.4.26 Caddy v2.11.7.
New environment variables
These apply to frankenphp only. All of them are in the environment variable specification.
| Variable | Default | What it does |
|---|---|---|
MERCURE_ENABLED |
false |
Set to true to turn on the Mercure hub. |
MERCURE_TRUSTED_ISSUERS |
https://localhost |
The iss claim your tokens carry, usually your app's URL. |
MERCURE_PUBLISHER_JWT_KEY |
unset | Secret or PEM public key that verifies publisher tokens. Required when the hub is on. |
MERCURE_PUBLISHER_JWT_ALG |
HS256 |
Algorithm for the publisher key. |
MERCURE_SUBSCRIBER_JWT_KEY |
unset | Secret or PEM public key that verifies subscriber tokens. Required when the hub is on. |
MERCURE_SUBSCRIBER_JWT_ALG |
HS256 |
Algorithm for the subscriber key. |
MERCURE_EXTRA_DIRECTIVES |
"" |
More Mercure directives, one per line, like anonymous or cors_origins. |
⚠️ Breaking changes
These come from FrankenPHP 1.13 and only affect the frankenphp variation. The migration guide has the details.
Mercure 1.0 rejects publisher_jwt and subscriber_jwt
If you turned on the Mercure hub with publisher_jwt or subscriber_jwt, including through the mercure array in config/octane.php, FrankenPHP now fails to start. Switch to the MERCURE_* variables above. If your app still signs Mercure 0.x tokens, set MERCURE_EXTRA_DIRECTIVES="protocol_version_compatibility 8" while you migrate. The Mercure 1.0 upgrade guide covers the client changes.
Caddy limits request headers
Requests with more than 16 KiB of headers now get a 431 Request Header Fields Too Large. Large cookies are the usual cause. Headers with a . in their name are dropped now too, because PHP turns X.Forwarded.For into the same HTTP_X_FORWARDED_FOR as X-Forwarded-For.
num_threads no longer includes worker threads
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. It fails to start if max_threads is lower than the total. Lower num_threads to the number of threads you want for regular requests.
🔐 Security
FrankenPHP 1.13 fixes these advisories in our images (#715):
- A client could spoof headers like
X-Forwarded-Forby sending them with a.in the name (GHSA-qcrp-8483-f2f2) - A request for
/uploads/a.php.txt/b.phpranuploads/a.php(GHSA-xxjp-cjxr-2x6m) putenv()leaked values between requests and threads (GHSA-996f-w38m-f574)- A crafted array passed to
frankenphp_log()crashed the whole server (GHSA-4prg-hv4r-g6mv)
🐛 Bug fixes
FrankenPHP
- FrankenPHP crashed on HTTP/2 when PHP kept running after
fastcgi_finish_request(), which Laravel and Symfony do on every response. This hitSSL_MODE=fulland proxies like Traefik that use HTTP/2 to reach port 8443. This only affectedv5.0.0-beta3(#713, #715, fixes #712) - Our image tests now send a request that finishes before PHP does, over HTTP/1.1 and HTTP/2, on every web server variation. A crash like this one now fails the build instead of reaching a release (#713)
⏫ Dependency updates
- FrankenPHP 1.12.7 → 1.13.0 (Caddy 2.11.7, Mercure 1.0.3)
Full Changelog: v5.0.0-beta3...v5.0.0-beta4
v5.0.0-beta3
🤩 What's new
Package install commands accept line continuations (#708)
docker-php-serversideup-dep-install-debian and docker-php-serversideup-dep-install-alpine now take packages as separate arguments, so you can list one package per line in your Dockerfile:
RUN docker-php-serversideup-dep-install-debian \
git \
nano \
zipSpace-separated and comma-separated lists like "git, zip" still work.
🐛 Bug fixes
All variations
docker-php-serversideup-dep-install-*only installed the first package when packages were passed as separate arguments, likegit zip. The rest were skipped without an error (#708)- A package pattern like
"php*"on Alpine could expand to file names in the working directory before reachingapk(#708)
NGINX
- Font files that don't exist on disk now pass to PHP like CSS, JS, and images already do. Symfony Asset Mapper serves fonts through PHP in development, and NGINX was answering those requests with a 404 (#710)
⏫ Dependency updates
- PHP extension installer 2.11.27 → 2.12.0
🙏 Thanks
Thanks to @ryanjbonnell and @ricardomm85 for the PRs.
Full Changelog: v5.0.0-beta2...v5.0.0-beta3
v5.0.0-beta2
CI Fix
- Improve retry fix when images fail to publish
v5.0.0-beta1
🤩 What's new
Short-lived & IP address certificates for FrankenPHP
FrankenPHP can now request Let's Encrypt's new short-lived (~6-day) certificate profile through the new `CADDY_ACME_PROFILE` variable. Short-lived certificates skip revocation entirely, and the same profile is what lets you issue certificates for raw IP addresses, which is handy for services that don't have a domain in front of them.
Configure short-lived & IP certificates →
Native Laravel Octane support with a hardened and optimized Caddyfile (#604)
Add --caddyfile=/etc/frankenphp/Caddyfile to octane:start and FrankenPHP switches into worker mode with the same trusted proxies, security headers, asset caching, SSL modes, and health check as classic mode. Octane's --workers, --watch, --max-requests, octane:status, and octane:reload all work. No wrapper script, no second Caddyfile.
command: ["php", "artisan", "octane:start", "--server=frankenphp", "--port=8080", "--caddyfile=/etc/frankenphp/Caddyfile"]Thanks to @aSeriousDeveloper for opening the original PR and coolio85 on Discord for the workaround that started it.
Expanded OPcache support and better defaults (#704)
OPcache is still off by default to save your hair when you're in development. When you set PHP_OPCACHE_ENABLE=1, you now get the settings from Symfony's performance guide instead of PHP's stock values: more memory, room for more files, and no filesystem checks per request. Preloading is available with PHP_OPCACHE_PRELOAD. This is a breaking change if you mount your code as a volume with OPcache enabled (see below).
Read the production performance tuning guide →
Trusted proxy support for every variation (#643)
TRUSTED_PROXY now works the same way across all variations (FrankenPHP, NGINX, and Apache), so your app sees the real client IP whether it's behind Cloudflare, a load balancer, or your own reverse proxy. The version in the v4.6.0 betas returned the wrong IP in multi-hop Docker setups (#703). That's fixed, and FrankenPHP's REMOTE_ADDR now matches what Caddy resolves. FrankenPHP users also get /etc/frankenphp/caddyfile-global.d/ for global Caddy config without escaping CADDY_GLOBAL_OPTIONS.
Native Laravel Nightwatch support (#572)
Added a native health check for Laravel Nightwatch, complete with documentation to wire it up.
Laravel Nightwatch with Docker →
CI improvements: Every image is tested before it's published (#700)
Build and publish used to be one step. Now every image is built for amd64 and arm64, pulled on native runners, and checked before anything ships: it starts, runs unprivileged, loads the default extensions, passes its health check, and serves PHP through its web server. If one image fails, nothing from that run is published. Read more about how this works in #700.
New environment variables
All of them are documented in the environment variable specification.
| Variable | Default | Applies to | What it does | Learn more |
|---|---|---|---|---|
TRUSTED_PROXY |
cloudflare |
fpm-nginx, fpm-apache, frankenphp | Which proxy IPs are trusted to pass the real client IP. Options: cloudflare, sucuri, local, or off. |
#643 |
CADDY_ACME_PROFILE |
off |
frankenphp | Select a Let's Encrypt certificate profile: shortlived (~6-day certs, required for IP-address certificates), tlsserver, classic, or off. |
Configuring SSL |
LARAVEL_OCTANE |
unset | frankenphp | Set by Octane, not by you. The Caddyfile uses it to switch into worker mode. | #604 |
AUTORUN_LARAVEL_SKIP_IF_NOT_FOUND |
false |
all | When true, Laravel automations exit gracefully if Laravel is not found in APP_BASE_DIR instead of failing the container. Requires AUTORUN_ENABLED=true. |
Laravel automations |
PHP_OPCACHE_ENABLE_CLI |
1 |
all | Whether CLI commands use OPcache when PHP_OPCACHE_ENABLE=1. 1 is what v4 did. Set to 0 to keep OPcache on for the web server only. |
#704 |
PHP_OPCACHE_PRELOAD |
"" |
all | Path to a preload script. | #704 |
PHP_OPCACHE_PRELOAD_USER |
"" |
all | The user to preload as when the container runs as root. | #704 |
PHP_FILE_UPLOADS |
On |
all | Whether to allow HTTP file uploads. Set to Off to harden apps that never accept uploads. |
#697 |
PHP_MAX_FILE_UPLOADS |
20 |
all | Maximum number of files that can be uploaded in a single request. | #697 |
PHP_DISABLE_FUNCTIONS |
"" |
all | Comma-separated list of PHP functions to disable, such as exec,shell_exec. Empty because Laravel, Composer, and Symfony Process rely on proc_open. |
#692 |
PHP_HTML_ERRORS |
On |
all | Format on-screen errors as HTML when PHP_DISPLAY_ERRORS is on. Never affects logged errors, and PHP forces it off for the CLI. |
#692 |
PHP_REALPATH_CACHE_SIZE |
4096K |
all | Size of PHP's realpath cache. Apps with a large vendor/ directory may benefit from raising it. |
#692 |
PHP_SESSION_COOKIE_HTTPONLY |
On |
all | Adds the HttpOnly flag to the native PHP session cookie so browser scripts cannot read it. See the note below. |
#692 |
Changed defaults
The PHP_OPCACHE_* values only apply when PHP_OPCACHE_ENABLE=1. CADDY_* applies to FrankenPHP only.
| Variable | v4 | v5 |
|---|---|---|
PHP_OPCACHE_VALIDATE_TIMESTAMPS |
1 |
0 |
PHP_OPCACHE_MEMORY_CONSUMPTION |
128 |
256 |
PHP_OPCACHE_INTERNED_STRINGS_BUFFER |
8 |
32 |
PHP_OPCACHE_MAX_ACCELERATED_FILES |
10000 |
32531 |
PHP_REALPATH_CACHE_TTL |
120 |
600 |
CADDY_LOG_OUTPUT |
stdout |
stderr |
CADDY_LOG_FORMAT |
console |
auto |
⚠️ Breaking changes
The v4 → v5 migration guide walks through each of these with a checklist. To stay on v4 while you review, pin your tag to v4.5.1 (for example serversideup/php:8.4-fpm-nginx-v4.5.1).
Dropped PHP 7.4 and 8.0 (#699)
Debian 11 (Bullseye) LTS ended on 2026-08-31, and the following week Debian removed the Bullseye packages from its mirrors, so we can no longer install anything inside the build. PHP 7.4 and 8.0 only ever shipped on Bullseye and Alpine 3.16, which reached EOL in 2024, so both go with it. PHP 8.1 is EOL too, but stays built (pinned to 8.1.34) on bookworm, trixie, and alpine3.22 because those bases still receive security updates.
PHP 8.1 also drops alpine3.21. Alpine 3.21 is supported until 2026-11-01, but 8.1 is EOL and only needs one Alpine base, so 8.1 on Alpine now means alpine3.22. Change 8.1-*-alpine3.21 tags to 8.1-*-alpine3.22.
Your existing tags still work. Every 7.4, 8.0, and 8.1 alpine3.21 tag stays pullable, frozen at its last successful build. If you need to install a package on one while you migrate, the migration guide has an unsupported recipe.
Our supported matrix is now PHP 8.2 – 8.5 on bookworm, trixie, alpine3.23, and alpine3.24, plus PHP 8.1 on bookworm, trixie, and alpine3.22. SECURITY.md now states the rule: we build an image while its official base image exists and the operating system still receives security updates.
- Full detail on what changed and why (#699) →
- EOL versions and the legacy-modernization path →
- Choosing an image →
OPcache no longer checks for file changes (#704)
PHP_OPCACHE_VALIDATE_TIMESTAMPS now defaults to 0, so with OPcache enabled, PHP files are cached until the container restarts. You are affected if you set PHP_OPCACHE_ENABLE=1 and mount your code as a volume, update WordPress on a volume outside the admin, or run docker exec ... artisan optimize against a live container. Restart the container after code changes, or set PHP_OPCACHE_VALIDATE_TIMESTAMPS=1 to keep the v4 behavior. Nothing changes with PHP_OPCACHE_ENABLE=0.
FrankenPHP logs go to stderr and default to JSON (#604)
| Variable | v4 | v5 |
|---|---|---|
CADDY_LOG_OUTPUT |
stdout |
stderr |
CADDY_LOG_FORMAT |
console |
auto (Caddy's default: console on a terminal, json otherwise) |
docker logs, Compose, and Kubernetes capture both streams, so most setups only notice the format. You are affected if you read the two streams separately or parse the console lines. Set CADDY_LOG_FORMAT=console and CADDY_LOG_OUTPUT=stdout to get the v4 behavior back, unless you run Octane, which needs the new defaults. These are Caddy's own defaults. Fixing both in the same major release means one upgrade instead of two.
PHP_SESSION_COOKIE_HTTPONLY now defaults to On (#692)
PHP [recommends](https://www.php.net/manual/en/session.secur...
v4.6.0-beta2
⏫ Dependency Update
- Upgrade FrankenPHP to v1.12.7
v4.6.0-beta1
🤩 What's new
Short-lived & IP address certificates for FrankenPHP
FrankenPHP can now request Let's Encrypt's new short-lived (~6-day) certificate profile through the new CADDY_ACME_PROFILE variable. Short-lived certificates skip revocation entirely, and the same profile is what lets you issue certificates for raw IP addresses — handy for services that don't have a domain in front of them.
Configure short-lived & IP certificates →
Trusted proxy support for every variation (#643)
TRUSTED_PROXY now works the same way across all variations — FrankenPHP, NGINX, and Apache — so your app sees the real client IP whether it's behind Cloudflare, a load balancer, or your own reverse proxy. FrankenPHP users also get Caddy global imports, making it easy to layer in your own global configuration.
Native Laravel Nightwatch support (#572)
Added a native health check for Laravel Nightwatch, complete with documentation to wire it up.
New AUTORUN_LARAVEL_SKIP_IF_NOT_FOUND variable
A new opt-in for shared images: when AUTORUN_ENABLED=true but Laravel isn't present yet (for example, before your first composer install), the container now exits gracefully instead of failing.
👨💻 DX improvements
- Cleaned up logging to make it cleaner and less noisy — especially when running "one off" commands like
composer install(#671)
🐛 Bug fixes
All variations
- Refactored the Laravel migration script to prevent an issue with older versions of Laravel that attempt to run migration isolation (#628 & #627)
- Added the DB Facade import for
LARAVEL_AUTORUNon modern Laravel versions (#673, fixes #672)
All web servers (FrankenPHP, NGINX, Apache)
- Fixed a bug where duplicate SEO content was possible (#646)
- Don't generate SSL if
DISABLE_DEFAULT_CONFIGis true (#644)
Apache
⏫ Dependency Updates
- Upgraded PHP Extension installer to v2.11.12
- Upgraded S6 Overlay to v3.2.3.2
v4.5.1
🔐 Security updates
- Updates NGINX to 1.30.4 (fixing a 9.2/10 vulnerability https://github.com/nginx/nginx/releases/tag/release-1.30.4)
- Update FrankenPHP version to 1.12.6 by @m-fi in #688
New Contributors
Full Changelog: v4.5.0...v4.5.1
v4.5.1-beta1
🔐 Security updates
- Updates NGINX to 1.30.4 (fixing a 9.2/10 vulnerability https://github.com/nginx/nginx/releases/tag/release-1.30.4)
- Update FrankenPHP version to 1.12.6 by @m-fi in #688
New Contributors
Full Changelog: v4.5.0...v4.5.1-beta1