PHP at Brewless. Served by FrankenPHP.
Every release runs on the PHP version you choose, served by FrankenPHP, in a container in your own Scaleway project. This page says what that means, including what it does not do.
PHP versions
Name the version in brewless.yml. Without it, a release is built for 8.4. A version Brewless does not build is refused before anything is built, with the versions it does.
php: "8.4"
Built and run on one version
The build resolves your Composer dependencies on the version the release will run on. The same commit built for another version is another image.
Patched before it ships
The base image refuses to build on a PHP release that lacks the latest security fixes we know of, so an old patch version never reaches a container.
The usual extensions
pdo_pgsql, pdo_mysql, redis, intl, bcmath, pcntl, zip, gd, exif and OPcache, plus pg_dump and pdftotext for applications that shell out to them.
OPcache that never checks the disk
The code in an image never changes, so OPcache does not look for changed files. For a Laravel application, configuration, routes and views are cached when the container starts.
PHP 8.2 gets security fixes only until the end of 2026, and older versions get none. A new platform should not start on them. Upgrade to 8.3 or later before you move.
What FrankenPHP is
FrankenPHP is an application server for PHP, written in Go on top of the Caddy web server. PHP runs inside the server process itself: one program answers HTTP and runs your code, where the classic setup needs Nginx in front of a pool of PHP-FPM processes. It was started by Kévin Dunglas and is developed in the PHP project's own GitHub organisation.
Why Brewless uses it
One process per container
A serverless container runs one thing. Nginx with PHP-FPM is two processes, two configurations and a supervisor to keep both alive. FrankenPHP is one binary that starts in one step.
Your code needs no change
In its classic mode every request starts fresh, as with PHP-FPM. An application that runs on PHP-FPM today runs here without code that has to survive between requests.
One configuration file
The server is configured in a single Caddyfile. Ours compresses responses (zstd, Brotli, gzip) and caches built assets for a year. A docker/Caddyfile in your repository replaces it; the documentation says what yours has to keep.
Official images
The base image starts from the FrankenPHP project's own Docker image. It is open source, so you can build it yourself and keep running without us.
What FrankenPHP can do, and what Brewless uses
FrankenPHP can do more than Brewless switches on. This is the list, with the reason for each.
| Feature | At Brewless | Why |
|---|---|---|
| Classic mode | Used | Each request starts with a clean state, as with PHP-FPM. Every PHP application works as it is. |
| Compression | Used | zstd, Brotli and gzip, chosen per browser, by the server itself. |
| Worker mode | Never | Keeps the application booted between requests, and with it whatever a request leaves behind: in a multi-tenant application, one tenant's data for the next. On serverless containers it saves nothing, since a container that was scaled to zero starts cold anyway. A build that asks for it is refused. |
| Laravel Octane | Never | Octane runs Laravel in worker mode, with the same risk. A start script that starts Octane is refused. |
| Automatic HTTPS | At the edge | Off in the container on purpose. Visitors connect to bunny.net, or to Scaleway without bunny.net, and that is where the certificate lives. The container only ever talks to them, over their own connection. |
| HTTP/3 | At the edge | Which HTTP version a visitor gets is decided where the connection ends: at bunny.net, which serves HTTP/2 today. Scaleway passes plain HTTP to the container, so HTTP/3 in FrankenPHP would never be reached. |
| 103 Early Hints | Not used yet | FrankenPHP can send them, but we have not verified that bunny.net and Scaleway pass them on, so we do not promise it. |
The trade-offs
FrankenPHP is a good fit for serverless containers. It is not free of downsides, and you should know them.
It is younger
FrankenPHP has been stable since 2023. Nginx and PHP-FPM have run PHP for well over a decade, and some edge cases are only known there.
A smaller community
For an odd problem there are fewer answers to find than for Nginx and PHP-FPM, and fewer people who have hit it before.
Thread-safe PHP only
FrankenPHP runs PHP in threads, so it needs the thread-safe build. An extension that is not thread-safe cannot be loaded. The common ones are fine; the list above is what the image has.
A crash takes the process
When a C extension crashes, the whole server process stops, where PHP-FPM loses one child. Scaleway starts the container again, but requests in flight on it fail.
Compared to the alternatives
The common ways to serve PHP, and where each stands for a serverless container.
| Server | What it is | For Brewless |
|---|---|---|
| FrankenPHP | PHP inside a Go server built on Caddy. Classic mode like PHP-FPM, or a worker mode. | What Brewless runs, in classic mode only. |
| Nginx + PHP-FPM | The long-standing default: a web server in front of a pool of PHP processes. | Proven, but two processes and two configurations in one container. |
| Apache + mod_php | PHP loaded into Apache itself, one request per process. | Simple, but heavier per request, and rarely chosen for containers today. |
| Swoole / OpenSwoole | A PHP extension with its own event loop and coroutines. | Fast, but the application and its libraries have to be written for a long-running process. |
| RoadRunner | A Go server that hands requests to long-running PHP workers. | Fast, with the same caveats as any worker setup, and a separate worker script. |
| Laravel Octane | A Laravel package that runs the application in worker mode on FrankenPHP, Swoole or RoadRunner. | Refused: it runs in worker mode. |
Read more
Choosing the PHP version Your own Caddyfile, php.ini and start script The base image, on GitHub frankenphp.dev php.net: supported versions
The PHP logo is by Colin Viebrock (CC BY-SA 4.0). The FrankenPHP logo is the FrankenPHP project's own. Both are shown as their makers published them.