These images vs others
The official PHP images are a clean starting point. Before one can serve a web app in production, you add a non-root user, a web server, Composer, and the extensions your app needs. serversideup/php starts from the same source and ships with those parts in place.
Same PHP, production defaults
We compile PHP from the same docker-library/php Dockerfiles as the official images. Your code runs the same way. The defaults are what change.
Official php | serversideup/php | |
|---|---|---|
| Default user | root | www-data (UID 33 on Debian, 82 on Alpine) |
| Web server ports | 80 | 8080 and 8443 (fpm: 9000) |
| PHP settings from environment variables | ❌ | ✅ |
Composer and install-php-extensions | ❌ | ✅ |
pcntl, pdo_mysql, pdo_pgsql, redis, zip | ❌ | ✅ |
| NGINX + PHP-FPM image | ❌ | ✅ |
| Apache image | mod_php | PHP-FPM |
| FrankenPHP image | ❌ | ✅ |
| Built-in health check | ❌ | ✅ (all but cli) |
| Real client IPs behind Cloudflare | ❌ | ✅ |
| Laravel automations at startup | ❌ | ✅ (opt-in) |
Debian, Alpine, amd64, arm64 | ✅ | ✅ |
| Registries | Docker Hub | Docker Hub, GitHub Packages |
New PHP patches without waiting for a base image
We build PHP from php.net ourselves instead of waiting for a new base image on Docker Hub. We check php.net every hour, and a new patch release starts a build right away. The images publish once that build passes its tests.
The floating tags, such as 8.5-fpm-nginx, also rebuild each Tuesday to pick up operating system security fixes. How images are built has the details.
Images you can verify
Every image is signed and carries an SBOM and build provenance. Check them with cosign before you deploy. Verifying images shows the commands.
Requests for .env get a 403
NGINX, Apache, and Caddy refuse requests for dotfiles such as .env and for files ending in .log, .sql, or .bak. Your app's responses get X-Frame-Options, X-Content-Type-Options, and Referrer-Policy headers.
FrankenPHP with the same defaults
Our frankenphp variation builds FrankenPHP on our PHP base. It shares every default above. It runs as www-data on 8080 and 8443 and serves /var/www/html/public.
Caddy's automatic HTTPS and admin API start off (CADDY_AUTO_HTTPS=off, CADDY_ADMIN=off). That fits a container behind a reverse proxy. Turn HTTPS on when you need it; the FrankenPHP variation page explains how.
Switch an existing project
Moving from the official image takes a few changes: the port, the document root, and how you install extensions. The migration guide lists each one.
Follow the migration guideDefault configurations lists every package, extension, and startup script we add.