Docker images for PHP 8.1 to 8.6 apps: Apache (Debian, with a Symfony variant), FrankenPHP (Debian or Alpine) and CI (Alpine). PHP 8.6 images are built from the upstream release candidate until 8.6.0 is released. Legacy images for PHP 5.6 to 8.0 are still available but are no longer rebuilt automatically.
- GitHub: https://github.com/silarhi/docker-php
- Demo: https://labs.silarhi.fr/php
- Demo (404): https://labs.silarhi.fr/php/notfound
- Docker image: https://hub.docker.com/r/silarhi/php-apache
- Blog post: https://blog.silarhi.fr/image-docker-php-apache-parfaite/
These tags were last pushed on 2024-12-19. They are not part of the CI matrix and are only rebuilt by hand with
make build-legacy, so they no longer receive OS or PHP security updates.
- Standard (
X.Y): Production-ready images with Apache and common PHP extensions (opcache, pdo_mysql) - CI (
X.Y-ci): Lightweight Alpine-based images optimized for CI/CD pipelines - Symfony (
X.Y-symfony): Enhanced images with additional extensions for Symfony applications (intl, zip) - FrankenPHP Alpine (
X.Y-frankenphp-alpine): Alpine-based images using FrankenPHP server for modern PHP apps - FrankenPHP Bookworm (
X.Y-frankenphp-bookworm): Debian-based images using FrankenPHP server for modern PHP apps
PHP settings of the Apache and FrankenPHP images live in conf/php.ini (installed as conf.d/app.ini).
| Environment variable | Default | Effect |
|---|---|---|
PHP_OPCACHE_VALIDATE_TIMESTAMPS |
0 |
opcache.validate_timestamps. With 0, PHP files are compiled once and never checked for changes: restart the container to deploy new code. Set it to 1 when the sources are mounted and edited in place (local development). |
The Apache and FrankenPHP images trust X-Forwarded-* headers from private networks (Docker, Traefik, load balancers)
and from Cloudflare's IP ranges, and resolve the proxy chain before PHP runs:
REMOTE_ADDRis the visitor IP, read right to left fromX-Forwarded-Forup to the first untrusted address (mod_remoteipon Apache,trusted_proxieson FrankenPHP).X-Forwarded-Foris not passed on to PHP.HTTPSisonwhen the request reached the proxy over HTTPS (X-Forwarded-Proto: https).
On FrankenPHP, CADDY_TRUSTED_PROXIES_RANGES replaces the trusted ranges. X-Forwarded-Proto is accepted from any
client, so only expose the containers through the proxy.
Cloudflare → Traefik → container: Traefik must trust Cloudflare as well. Otherwise it replaces X-Forwarded-For
with the Cloudflare edge address, and every visitor shows up with a Cloudflare IP.
[entryPoints.websecure.forwardedHeaders]
trustedIPs = ["173.245.48.0/20", "103.21.244.0/22", "..."] # every range from https://www.cloudflare.com/ips/Symfony: the chain is already resolved, so leave framework.trusted_proxies empty or set it to private_ranges.
Don't use REMOTE_ADDR: it is now the visitor, and Symfony would trust the visitor's own X-Forwarded-Port header
when generating URLs.