This repository contains the Dockerfiles used to build the multi-arch (AMD64 +
ARM64) images found at https://hub.docker.com/u/curatorium, for PHP 8.0
through 8.5 (the older neurony/php-$PHPVS images remain, frozen).
They aim to:
- be compatible with Symfony & Laravel basic requirements
- support commonly used extensions (
gd,mysql,redis, etc.) - be useful in ci/cd pipelines to run tests and quality gates
- include useful PHP tools (
composer,phpunit,phpstan, etc.)
PHP packages come from the deb.sury.org repository
(the Debian counterpart of the ondrej/php PPA). Images are built and
published by GitHub Actions on native per-architecture runners.
Six roles in two lineages off base:
base (debian:bookworm-slim)
├── ci ── az-ci (PHP-free tooling)
└── php-base ── php-qa ── php-fs (PHP + nginx)
PHP-free roles publish without a PHP version; PHP roles carry it in the repo:
curatorium/<role>:<version>[-<arch>] role = base|ci|az-ci
curatorium/php-<PHPVS>:<role>-<version>[-<arch>] role = base|qa|fs, PHPVS = 8.0 ... 8.5
- Version: a
YY.MMtimestamp orlatest - Per-arch tags carry an
-amd64/-arm64suffix; the bare tag is a manifest combining both
As a server:
docker run -v "$PWD:/app" curatorium/php-8.5:base # will start nginx + php-fpm (+ crond + var-dump; if enabled)or
# docker-compose.yml
services:
backend:
image: curatorium/php-8.5:base
ports:
- 80:80 # served by NGINX by defaultAs a command runner:
docker run -v "$PWD:/app" curatorium/php-8.5:base php /app/command.php # will execute your command & exitAs a pipeline runner:
# .github/workflows/ci.yml
jobs:
qa:
runs-on: ubuntu-latest
container: curatorium/php-8.5:qa
steps:
- uses: actions/checkout@v4
- run: phpstanEach role owns a directory (<role>/Dockerfile + <role>/Stewardfile +
<role>/files/). ./generate-dockerfile concatenates the per-role Dockerfiles
into the root multi-stage Dockerfile, so each role is a build target and a
published tag.
ex.: curatorium/base or curatorium/base-26.07 or curatorium/base-26.07-amd64
Built on debian:bookworm-slim -- the OS foundation shared by every role. No
PHP, no nginx (those start at php-base). Tools:
tini(PID 1 / init)cronwait-untilbash-import,bash-test,steward- the runtime scripts:
entrypoint,service,daemonize,healthcheck,clean-tmp,envsubst-only-prefix,add-debug,add-forensics jq,gnupg,nano,less,patch,sudo,unzip,locales,tzdata
Services are managed by the service script (init.d + start-stop-daemon, no
systemd). $ENABLED_SERVICES is empty here and defaults to "php-fpm nginx" in
php-base.
ex.: curatorium/ci or curatorium/ci-26.07 or curatorium/ci-26.07-amd64
Extends the base image with PHP-free CLI tooling for pipelines -- preparing deployments, rendering configuration, building images:
docker(CLI +composeplugin +buildxplugin)kubectl,kubelogin,kubectl-krew(+ plugins:grep,exec-cronjob,krew,slice,split-yaml,sort-manifests)node,npm,yarnejson,ez-cfg(easy-config),skeema,yq,pup,gron,http(HTTPie)q-- AMD64 only (upstream ships no ARM64 package)newrelic-cligit,openssh-clientmariadb-client,redis-tools,libmemcached-tools7zip,bzip2,tar,xz-utils,zip,unzip
ex.: curatorium/az-ci or curatorium/az-ci-26.07 or curatorium/az-ci-26.07-amd64
Extends the CI image with az (Azure CLI).
ex.: curatorium/php-8.5:base or curatorium/php-8.5:base-26.07 or curatorium/php-8.5:base-26.07-amd64
Extends the base image with PHP + nginx. PHP extensions:
amqp,apcu,bcmath,curl,gd,http,igbinary,imagick,intl,mbstring,mongodb,msgpack,mysql,odbc,pgsql,protobuf,raphf,readline,redis,soap,sqlite3,ssh2,stomp,xml,xsl,yaml,ziptimezonedb-- via peclgrpc,memcached,opcache,zmq-- best-effort; skipped where sury has no package (e.g. 8.5)newrelic-- AMD64 only, disabled unless$NEWRELIC_ENABLEDis set
Tools:
composernginx(apt +gettext-basefor envsubst)php-fpm- image optimisers:
ghostscript,imagemagick,jpegoptim,optipng,pngquant,gifsicle
$ENABLED_SERVICES defaults to "php-fpm nginx" here and to "" in
php-qa/php-fs; var-dump is available but off by default.
ex.: curatorium/php-8.5:qa or curatorium/php-8.5:qa-26.07 or curatorium/php-8.5:qa-26.07-amd64
Extends the php-base image with PHP extensions:
pcov-- installed, disabled by defaultxdebug-- installed, disabled by defaultphpdbg
Security scanners:
gitleaks-- secret scannersnyklocal-php-security-checker
...and PHP tools, each installed into its own /opt/<tool>/:
codecept(codeception)composer-require-checkercomposer-unusedeasy-configinfectionphp-cs-fixerphpdcdphpinsightsphplintphpmndphpstan+phpat,ekino/phpstan-banned-code,larastan,phpstan-symfony,phpstan-doctrine,phpstan-dba,phpstan-deprecation-rules,phpstan-beberlei-assert,phpstan-todo-by,shipmonk/dead-code-detectorphpunit+paratestpsalm+plugin-laravel,plugin-symfony,doctrine-psalm-pluginpsysh-- a much improved PHP interactive shell (+laravel/tinker,psysh-bundle)var-dumpergit,openssh-client
ex.: curatorium/php-8.5:fs or curatorium/php-8.5:fs-26.07 or curatorium/php-8.5:fs-26.07-amd64
Extends the php-qa image with nodejs, npm, npx, yarn, and front-end
framework CLIs:
@angular/cli@vue/clireact-cli@ionic/cli@symfony/webpack-encorelaravel-mixgrunt-cli
Installers are steward Stewardfiles (primitives apt/key/src/deb/bin/
tar/zip/ext/npm/composer, defer for the rest) -- one per role. Steward
is ADDed in base/Dockerfile (bootstrap), then runs each role's Stewardfile.
The root Dockerfile is GENERATED from the per-role <role>/Dockerfile files by
./generate-dockerfile; edit the per-role files, then regenerate. Set your
environment (.env.sample is the template), regenerate, and build:
git clone git@github.com:curatorium/php-dockerfiles.git;
cd php-dockerfiles/;
cp .env.sample .env
nano .env # specify a PHP version ($PHPVS), a Node version ($NODEVS), a tag timestamp ($TS)
./generate-dockerfile # regenerate the root Dockerfile
export X_ARCH=$(dpkg --print-architecture) # part of the image tag; not in .env.sample
docker compose build
# or a specific PHP version, Node version and timestamp
PHPVS=8.5 NODEVS=25 TS=`date +%y.%m` X_ARCH=amd64 docker compose build
# or a single role
docker compose build php-qaBuild args: PHPVS (8.0-8.5), NODEVS (Node major), TS (YY.MM or
latest), X_ARCH (amd64/arm64). docker-compose.override.yml mounts the
per-role files/ and tests/ into the containers, so they can be edited without
rebuilding.
bash-test suites under tests/,
run against built images -- one per role:
tests/service.test-- service manager + entrypoint behaviour; re-execs itself INSIDE the base imagetests/<role>.test(base/ci/az-ci/php-base/php-qa/php-fs) -- each probes only that role's increment over its parent (binaries on PATH + Runs, PHP extensions loaded;php-basealso checks PHP version + nginx serving). The image under test is$IMAGE(a digest in CI, or the host-arch image from.envlocally)
Reports are committed under tests/*.test[.$PHPVS].md. .githooks/pre-commit
regenerates them from the locally built images (the PHPVS in .env) and fails
the commit if a report is stale or a suite fails.
.github/workflows/build.yml -- manual workflow_dispatch (with a selectable PHP-version subset):
- two families off the generated
Dockerfile: infra (base/ci/az-ci, no PHP axis) →curatorium/<role>, and PHP (base/qa/fs× PHPVS) →curatorium/php-<PHPVS>:<role> - each job builds its stage on native
amd64/arm64runners (no qemu), runs that role'stests/<role>.testagainst the pushed digest, and pushes by digest with build provenance + an SBOM attestation - a merge job joins
-amd64+-arm64withdocker buildx imagetoolsinto:role-$TSand the rolling:role, then attests the merged index
A GitHub Actions workflow runs Docker Scout against the published images and uploads the results to the repository's Security → Code scanning tab. Scout analysis is free, and as an MIT-licensed open-source project this repository is eligible for the Docker-Sponsored Open Source program, which grants unlimited Scout analysis and removes image pull rate limits for everyone pulling these images.
Each qa image also carries gitleaks for secret scanning and
local-php-security-checker for auditing a project's Composer dependencies.
Pull requests welcome