php-fpm, batteries included
50K+
PHP-FPM with the extensions you'd end up installing anyway, already in. Tune it with env vars instead of baking your own ini files. PHP 5.3 through 8.5.
Built at the byte0.org lab for internal use at Pantera, a web studio. Public because there's no reason not to be.
docker run -d -v $(pwd):/var/www/html winterhearted/php-fpm:8.4
Listens on 9000, serves from /var/www/html. Point nginx at it, done.
8.5 8.4 8.3 8.2 8.1 — pick one.
8.0 7.4 7.3 7.2 7.1 7.0 5.6 5.5 5.4 5.3 — EOL, kept for old projects. The 5.x ones are built from source.
Each has a -latest alias and exact patches too (8.4.23). amd64, arm64, riscv64.
-vips8.5-vips 8.4-vips 8.3-vips 8.2-vips — same image plus libvips and FFI turned on. Also as 8.4-latest-vips, 8.4.23-vips, etc.
Use it with php-vips 2.x, which talks to the library over FFI. The old pecl vips extension has been dead since PHP 8.0, so it's not here.
libvips isn't small and most projects don't need it, hence the separate tag — the plain images stay lean.
8.6-rc — experimental8.6-rc tracks the upstream PHP 8.6 alpha/RC images and is rebuilt weekly. Also 8.6-rc-vips, and dated snapshots like 8.6-rc-20260805 if you want to pin something that won't move under you mid-debug.
For seeing what breaks ahead of the release, nothing more. The feature set isn't frozen, so things will change between rebuilds and some of them will change under you. There's deliberately no 8.6 or 8.6-latest tag — those stay empty until 8.6 actually ships.
One difference worth knowing: imagick is built from its git master here, because the last released version doesn't compile against 8.6 yet. amd64, arm64, riscv64, same as everything else.
| Var | Sets |
|---|---|
PHP_DATE_TIMEZONE | date.timezone |
PHP_MEMORY_LIMIT | memory_limit, e.g. 256M |
PHP_MAX_EXECUTION_TIME | seconds |
PHP_MAX_INPUT_TIME | seconds |
PHP_POST_MAX_SIZE | e.g. 100M |
PHP_UPLOAD_MAX_FILESIZE | e.g. 100M |
PHP_ENABLE_OPCACHE | 1/0, CLI included |
PHP_ENABLE_JIT | 1/0, 8.0+ |
PHP_DISPLAY_ERRORS | 1/0, 8.2+. 0 keeps errors out of responses and only logs them |
PHP_ERROR_LOG | error_log, a file path, 8.2+ |
Leave one unset and you get PHP's default. Each just drops a file into conf.d/, nothing clever going on.
There's no php.ini in the image, so out of the box errors are printed into the response. FPM always logs them too, to docker logs or to the PHP_ERROR_LOG file if set; PHP_DISPLAY_ERRORS=0 leaves them only in the log. The CLI just prints, so nothing is doubled in stderr. The file's directory must be writable by www-data; if it isn't, PHP falls back to docker logs, so nothing gets lost.
FPM pool, 8.2+:
| Var | Sets | Default |
|---|---|---|
PHP_FPM_PM | pm: dynamic, ondemand, static | dynamic |
PHP_FPM_MAX_CHILDREN | pm.max_children | 12 |
PHP_FPM_START_SERVERS | pm.start_servers | 3 |
PHP_FPM_MIN_SPARE_SERVERS | pm.min_spare_servers | 2 |
PHP_FPM_MAX_SPARE_SERVERS | pm.max_spare_servers | 5 |
PHP_FPM_MAX_REQUESTS | pm.max_requests | 500 |
Set only PHP_FPM_MAX_CHILDREN and the spare counts scale with it, so PHP_FPM_MAX_CHILDREN=4 just works instead of failing on max_spare_servers > max_children. These go to php-fpm.d/zz-env.conf; a config you mount there under a name that sorts later (zz-mysite.conf) still wins.
The official image is tuned for nothing in particular — 5 workers, interrupted requests on reload. These images ship defaults that sit at ~15 MB idle on a laptop and still hold a mid-traffic site: a corporate site during an ad campaign, a local shop during a sale.
process_control_timeout = 10s lets in-flight requests finish on a reload (USR2). If 10 workers segfault within a minute, FPM restarts itself. log_errors is on, so errors are logged even when they're displayed.expose_php = Off. Opcache gets interned_strings_buffer = 16 and max_accelerated_files = 20000; the stock 8 / 10000 runs out on anything with a real vendor/.They live in conf.d/00-defaults.ini and php-fpm.d/zz-defaults.conf. Env vars and your own files override them.
pdo (mysql / pgsql / sqlite), mysqli, gd with jpeg/png/webp/avif/freetype, imagick, opcache, intl, zip, bcmath, exif, soap, mbstring, curl, openssl, sodium, and the usual dom/xml set.
Run php -m if you want the exact list for a given tag.
8.2–8.5 are built in two stages: extensions get compiled in a throwaway builder, the final image is plain Debian plus the finished PHP. Much smaller, but no compiler in there — docker-php-ext-install in a derived image won't work. Everything you'd normally add is already baked in; if something's genuinely missing, open an issue.
riscv64 sometimes trails the other arches by a patch. Moving tags like 8.4 don't wait for it — you may get a slightly older build there.
MIT.
Content type
Image
Digest
sha256:26fa43bd8…
Size
147.5 MB
Last updated
about 16 hours ago
docker pull winterhearted/php-fpm:8.5-latest-vips