This repository builds and publishes PHP images optimized for both CLI and FPM use cases, tailored for various PHP versions and their minor releases. Our images are compatible with both ARM64 and x86_64 host architectures and integrate seamlessly with Laravel and other PHP frameworks.
To get a specific version of our PHP image, use:
docker pull mxmd/php:<VERSION>-<TYPE>Where:
<VERSION>is the desired PHP major version with the latest minor release (e.g.,7.4), or you can specify a minor version (e.g.,7.1.33,8.1.13).<TYPE>is eithercliorfpm.
For example, to pull the PHP 7.4.33 FPM image:
docker pull mxmd/php:7.4.33-fpmAvailable versions of our images along with their Docker Hub links:
- 7.1-cli, 7.1-fpm
- 7.2-cli, 7.2-fpm
- 7.3-cli, 7.3-fpm
- 7.4-cli, 7.4-fpm
- 8.0-cli, 8.0-fpm
- 8.1-cli, 8.1-fpm
- 8.2-cli, 8.2-fpm
- 8.3-cli, 8.3-fpm
- 8.4-cli, 8.4-fpm
For production workloads where PHP-FPM handles public web traffic, use the hardened variants. Unlike CLI images (which run internal jobs with no public exposure), FPM directly handles inbound HTTP requests — so a reduced attack surface matters.
The hardened images use the CIS Docker Hardened Image (DHI) FPM runtime:
- Non-root by default — runs as DHI's
nonrootuser; if you need host UID/GID mapping, setuser:explicitly in Compose - Read-only root filesystem —
read_only: true; writable scratch space viatmpfsat/tmpand/run - No Composer — build tooling is excluded from the runtime image
- Minimal attack surface — only runtime artifacts copied from the builder stage; no build-deps remain
docker pull mxmd/php:fpm-hardened-8.4
docker pull mxmd/php:fpm-hardened-8.3
docker pull mxmd/php:fpm-hardened-8.2Note: Building locally requires
docker login dhi.ioto pull the DHI base image.
See per-version READMEs for full Compose examples:
You can integrate our PHP images into your Docker Compose workflows:
services:
php74-fpm:
platform: linux/arm64/v8
image: mxmd/php:7.4.33-fpm
ports:
- "9000:9000"
volumes:
# real time sync for app php files
- .:/app
# cache laravel libraries dir
- ./vendor:/app/vendor:cached
# logs and sessions should be authorative inside docker
- ./storage:/app/storage:delegated
# cache static assets bc fpm doesn't need to update css or js
- ./public:/app/public:cached
# additional php config
- ./docker-conf/php-ini:/usr/local/etc/php/custom.d
env_file:
- .env
environment:
# tell PHP to scan for our mounted custom ini files - preferabbly mount with zz-custom.ini
- PHP_INI_SCAN_DIR=/usr/local/etc/php/conf.d/:/usr/local/etc/php/custom.d
# composer
- COMPOSER_AUTH=${COMPOSER_AUTH}
# these are CRITICAL for linux hosts - our entrypoint will skip these for macOS if they conflict with GID:20 on the container
- HOST_USER_UID=${HOST_USER_UID:-1000}
- HOST_USER_GID=${HOST_USER_GID:-1000}
# production flag will enable opcache and production php.ini settings
- HOST_ENV=${HOST_ENV:-production}
# our entrypoint uses the www-data user for cmd entry that's not php-fpm - swap to EXEC_AS_ROOT=1 if you wanna exec as the root user
- EXEC_AS_ROOT=0
...
php74-cli:
image: mxmd/php:7.4.33-cli
...Note: Adjust volume paths or environment variables as per your project's requirements.
Ensure these environment variables exist on your host machine:
HOST_USER_GID
HOST_USER_UIDOn macOS, you can set them in ~/.extra or ~/.bash_profile.
To get HOST_USER_UID:
id -uTo get HOST_USER_GID:
id -gTo set these on your host machine:
echo "export HOST_USER_GID=$(id -g)" >> ~/.bash_profile && echo "export HOST_USER_UID=$(id -u)" >> ~/.bash_profile && echo "export DOCKER_USER=$(id -u):$(id -g)" >> ~/.bash_profileEnabling the following environment variable activates the opcache and uses php.ini production settings:
HOST_ENV=productionBoth local scripts support the following flags:
-
--force: Forces the building of the Docker image regardless of its creation date. -
--all: Commands the script to construct Docker images for all predefined types and versions. -
--proof-dir [DIR]: Exports an OCI artifact tarball withprovenance=mode=maxandsbom=trueinto the given directory after the local image build finishes.
This script leverages Docker's standard build process, constructing images specifically for the architecture of the host machine.
Internally it now uses docker buildx build --load with a shared local docker-container builder named local-buildkit.
If DOCKER_HOST is set, the script creates a dedicated Docker context for that host so Buildx can reuse its TLS configuration for remote daemons.
If --proof-dir is set, the script runs a second Buildx export to write an OCI artifact tarball with attestations to disk.
To build a Docker image for a specific type and version:
./local-single-arch.sh --type [TYPE] --version [VERSION]To also export local proof artifacts:
./local-single-arch.sh --type [TYPE] --version [VERSION] --proof-dir ./out/proof--load builds do not keep attestations in the local Docker image store, so --proof-dir writes them as OCI artifacts on disk instead.
For building all available types and versions:
./local-single-arch.sh --allBuildx is a Docker CLI plugin that offers extended features for building images. It is especially valuable for creating multi-architecture images.
These local builds use --load, so they do not attach Buildx provenance attestations; the release workflow still publishes provenance.
If DOCKER_HOST is set by Docker Machine, the script creates a dedicated Docker context for that host so Buildx can reuse its TLS configuration for remote daemons.
If --proof-dir is set, the script runs a second Buildx export to write an OCI artifact tarball with attestations to disk.
For a specific type and version:
./buildx-local.sh --type [TYPE] --version [VERSION]To also export local proof artifacts:
./buildx-local.sh --type [TYPE] --version [VERSION] --proof-dir ./out/proofFor all available types and versions:
./buildx-local.sh --allTrigger:
- Activates on
pushevents to themasterbranch.
Jobs:
-
create-release-and-build:
- Environment: Runs on the latest Ubuntu.
- Matrix Strategy: Sets combinations of PHP versions from '7.1' to '8.2' for both 'cli' and 'fpm' images.
Steps:
- Checkout repository: Pulls the latest code from the repository.
- Setup GitHub CLI: Initializes the GitHub CLI and logs in using the provided GitHub token.
- Create Releases: If a
.envfile exists in the specified directory and a GitHub release for the given tag doesn't already exist, it creates a new release for the specific PHP version and type. - Set up environment variables: Sources the
.envfile from the specified directory and sets PHP_VERSION and ALPINE_VERSION as environment variables. - Set up QEMU: A tool to run code made for one machine on another, useful for multi-architecture builds.
- Set up Docker Buildx: Initializes Buildx, an extended builder with additional features.
- Log in to Docker Hub: Uses the provided secrets to log into Docker Hub.
- Build Docker images: Constructs Docker images for both amd64 and arm64 platforms without pushing them.
- Push Docker images (if new tag): If a new release tag was created in the "Create Releases" step, this step pushes the built images to Docker Hub.
-
Matrix Builds: The workflow is designed to run builds for multiple PHP versions and types concurrently, maximizing efficiency.
-
Conditional Releases: Only creates a new GitHub release if one for the specific PHP version and type doesn't already exist. This ensures that Docker images are only pushed when necessary.
-
Multi-Architecture: Utilizes Docker's Buildx and QEMU to build images suitable for both amd64 and arm64 architectures.
The workflow requires the following secrets:
-
GITHUB_TOKEN: A token provided by GitHub to authenticate and gain required permissions. This is automatically available in GitHub Actions and does not need manual setup. -
DOCKER_HUB_USERNAME: Your Docker Hub username. -
DOCKER_HUB_ACCESS_TOKEN: A token or password for Docker Hub to authenticate and push images.