Self-hosted service
thecodingmachine/docker-images-php avatar
thecodingmachine/docker-images-php

docker-images-php makes the PHP image a build argument, not a file

A set of PHP Docker images

852 stars140 forksShellMIT

At a glance

What is it?
The thecodingmachine/docker-images-php repository publishes a matrix of PHP images where extensions, php.ini settings, cron jobs and the presence of Node are all chosen with environment variables at container start, and the fpm variant can now front PHP-FPM with Apache.
Who is it for?
docker-images-php suits a team that wants the same PHP runtime shape in local development, CI and production, with extension choices recorded in a compose file rather than a bespoke Dockerfile per project.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Two axes, three variants, and a Node switch on top

The image matrix in the README is built from a small number of orthogonal choices, and understanding them is enough to pick a tag. The first axis is fat versus slim, where the fat images bundle the most common PHP extensions and the slim ones preload no extensions, so you enable only what you need. The second is the variant, and there are three: CLI, apache and fpm. The third dimension is Node, since all variants can be installed with or without NodeJS for building static assets, which is why the tag list contains pairs such as 8.5-v5-apache and 8.5-v5-apache-node22, with node24 and node26 also published. PHP versions in the table run from 8.5.x downward, and the tags carry a major image revision, v5, so the naming is image generation, PHP version, image revision and optional Node version in one string.

The fpm variant grew an optional Apache

The newest feature in the README is the one worth understanding before anything else, because it changes what the fpm variant means. The fpm image can now run Apache in front of PHP-FPM in the same container, enabled with an environment variable, and it is described as a drop-in alternative to the apache variant with the same Apache features, including .htaccess, APACHE_DOCUMENT_ROOT and APACHE_EXTENSION_*, except that PHP runs in PHP-FPM rather than mod_php.

bash
$ docker run -p 80:80 -e PHP_FPM_WEB_SERVER=apache -v "$PWD":/var/www/html thecodingmachine/php:8.4-v5-fpm

The stated reason is memory and concurrency. The README reports that under the same load the container serves 2 to 3 times more traffic with 4 times less memory, 30 against 10 pages per second on 2 CPUs and roughly 90 against 380 MiB, and explains that mod_php makes Apache dedicate a whole process embedding PHP to each connection, including idle keep-alive connections and static file requests, whereas with PHP-FPM Apache uses its threaded mpm_event and only PHP requests reach the PHP workers. The constraint is in docs/fpm.md, and the README names one example: php_value directives are not supported in .htaccess files, so the apache variant is still there for applications that rely on them.

Extensions and php.ini are environment variables, not build steps

The central promise of the repository is that you can enable or disable extensions with environment variables, and modify php.ini settings with environment variables too. That means the same image tag serves a development container, a CI container and a production container, and the differences live in a compose file that can be reviewed. The fat images additionally bundle Supercronic, a Cron compatible task runner, so cron jobs can be configured through environment variables rather than by writing crontab files into the image, and Composer is installed in every image. There is a smaller detail that saves real friction: Composer binaries under vendor/bin, global binaries, and Node binaries under node_modules/.bin can be run without their path, including through docker exec and docker compose exec, so a command like docker compose exec app phpstan works as written.

The image set is generated from a blueprint, not hand written

The repository layout shows how the images are produced. There is a utils/ directory holding a README.blueprint.md file, and the top of the README opens with a do not edit this file notice pointing at it, which means the README itself is generated. The Makefile confirms the mechanism.

bash
blueprint: ## Generate all blueprints file
	@if ! type orbit >/dev/null 2>&1; then echo "Missing orbit dependency, please install from https://github.com/gulien/orbit/"; exit 1; fi
	orbit run generate

The tool is orbit, and the target fails early with a clear message if it is not installed. The consequence for a contributor is that editing the README directly is pointless, since the next blueprint run overwrites it, and the real source of truth for each of the many tags is the blueprint plus the Dockerfiles at the repository root, one per variant combination including Dockerfile.apache.node and Dockerfile.slim.fpm. The other root files describe the wider build, with a docker-bake.hcl for buildx bake, a CHANGELOG.md, a MIGRATING.md, a HELP.md, an orbit.yml with orbit-payload.yml and orbit-images.yml for the image definition, and a tests-suite/ directory.

Testing is a matrix driven from the Makefile

The Makefile has a target per PHP version and per group of versions, and the pattern is consistent. Each version target runs the variant matrix, and the quick targets run only the cli variant for a set of versions.

bash
test-8.5:  ## Test php8.5 build only
	VERSION=8.5 VARIANT=cli $(MAKE) _test-version
	VERSION=8.5 VARIANT=apache $(MAKE) _test-version
	VERSION=8.5 VARIANT=fpm $(MAKE) _test-version

There is also a test-hot target that builds for the host platform with docker buildx bake and then runs the built image to print the PHP version, and the prerequisite target pulls ubuntu:20.04, which the test path evidently needs. The pattern of setting VERSION and VARIANT as make variables and delegating to a shared internal target is what keeps the matrix manageable, since each new PHP release adds a target rather than new logic. The existence of a tests-suite/ directory and a benchmarks/ directory, with the latter holding the fpm-apache comparison the README cites, shows that the images are exercised rather than merely published.

What the images do not cover

The obvious limitation is that the extension set is fixed by the image build. The environment variable mechanism selects among the extensions the image knows about, and the extensions/ directory at the repository root is the list, so an application that needs a library outside that set cannot simply switch it on, and building a custom image on top of these is exactly the kind of per-project Dockerfile the project exists to avoid. The second limitation is size, and it is a deliberate trade rather than a defect. The fat variant bundles most common extensions, plus Supercronic, plus Composer, plus optionally Node, and on a machine where image pull time and disk space matter, the slim variant with a handful of enabled extensions is the better fit. The third is portability of the specific claims. The traffic and memory figures in the README come from a benchmark in the repository, on 2 CPUs, and they compare two Apache configurations inside these images rather than Apache against any other stack, so treat them as a reason to try the fpm variant rather than as a number to quote in a decision document.

Licence, branches and how the tags move

The repository is under the MIT licence with a LICENSE file at the root, and the default branch is v5, which is the same revision that appears in the image tags, so the branch name and the image generation line are kept in step. The recent release history is empty because there are no GitHub releases, the images are published by tag on a registry and the changelog lives in CHANGELOG.md in the repository. The last push was on 2026-10-19, so the images are being rebuilt regularly, and each rebuild of a tag for a new PHP point release is how a change to the base image propagates. A practical consequence for CI: a floating tag such as 8.4-v5-fpm will change under you when the image is rebuilt, so pinning by digest in a production compose file is the safer habit, and the README notes that the images are actively tested on Linux, Windows and MacOS, which matters because the permission handling and the entrypoint behaviour are where cross platform differences usually show up.

Editorial conclusion

docker-images-php suits a team that wants the same PHP runtime shape in local development, CI and production, with extension choices recorded in a compose file rather than a bespoke Dockerfile per project. It is the wrong tool when your build needs an extension the image does not ship and cannot be enabled through an environment variable, since the supported set is fixed, and it is the wrong tool when you want a minimal image, because the fat variant bundles most common extensions and Supercronic. Before adopting it, check the extension list in the docs/ directory against what your application actually loads, and read docs/fpm.md before switching the fpm variant to its built-in Apache, because the .htaccess php_value directives that work in the apache variant are not supported there. The last push was on 2026-10-19 and the repository publishes no GitHub releases.

Frequently asked questions

What is the difference between the fat and slim PHP Docker images?

The fat images bundle most common PHP extensions and Supercronic, while the slim images come with no extensions preloaded so you enable only what you need. Both come with Composer installed.

How do I enable PHP extensions in these Docker images?

Extensions are enabled or disabled with environment variables, and php.ini settings can be modified with environment variables too. That means the differences between environments live in a compose file rather than in separate Dockerfiles.

What does PHP_FPM_WEB_SERVER=apache do?

It makes the fpm variant run Apache in front of PHP-FPM inside the same container, which the README presents as a drop-in alternative to the apache variant with the same Apache features, except that PHP runs in PHP-FPM rather than mod_php. Note that php_value directives are not supported in .htaccess files in that mode.

Can I use Node.js inside these PHP images?

Yes. All variants can be installed with or without NodeJS, and the tag list includes node22, node24 and node26 variants for the apache, cli and fpm builds. Node binaries under node_modules/.bin can be run without their path, including through docker exec.

How are cron jobs configured in these images?

Fat images are bundled with Supercronic, a Cron compatible task runner, and cron jobs are configured using environment variables rather than by writing crontab files into the image.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. thecodingmachine/docker-images-php on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/thecodingmachine-docker-images-php.svg)](https://hysenlabs.com/projects/thecodingmachine-docker-images-php)

Was this useful?