A 40MB Nginx and PHP-FPM Image That Doesn't Run as Root
You've probably built a PHP container before. You start from a base image, install Nginx and PHP-FPM, wire them together with supervisor or an entrypoint script, and end up with something that weighs half a gigabyte and runs everything as root. It works, but it's not exactly tidy. The docker-php-nginx project takes a different approach: a single image that's around 40MB, runs as an unprivileged user, and stays simple enough that you can actually read the config and understand what's happening.
What It Does
This is an example Docker image combining PHP-FPM 8.5 and Nginx 1.28 on top of Alpine Linux. It's multi-platform, supporting AMD64, ARMv6, ARMv7, and ARM64, so you can run it on a laptop, a Raspberry Pi, or an ARM-based server without hunting for a different tag.
Architecturally, it's what you'd expect from a classic Nginx-plus-PHP-FPM setup: Nginx handles incoming requests and passes PHP files to PHP-FPM over the socket, with supervisord keeping both services alive. The interesting part is how it's configured. PHP-FPM uses the on-demand process manager, so worker processes only spin up when there's actual traffic. The image is tuned for around 100 concurrent users, capping how many requests can be served for PHP files at once. Logs from all three services — Nginx, PHP-FPM, and supervisord — get redirected to the container's stdout, so docker logs -f <container name> shows you everything without digging into files.
Why It's Cool
It runs as nobody. Nginx, PHP-FPM, and supervisord all run under the non-privileged nobody user. That's a meaningful security default for a container that's going to sit in front of the internet. Most quick-start PHP images don't bother, and you end up patching it yourself later — or not.
The size is genuinely small. Around 40MB for a full Nginx and PHP-FPM stack is lean. Alpine gets you part of the way, but the image also avoids the usual bloat that creeps into hand-rolled PHP containers.
It idles cheaply. The on-demand process manager means PHP-FPM isn't holding a pool of workers open waiting for requests that never come. On a low-traffic service, that translates to a lower memory footprint and less CPU churn. It's a small config decision with a real operational payoff.
The KISS principle is stated, and it shows. The README is explicit that the goal is an example you can understand and adjust, not a black box. Configuration files for Nginx, PHP, and PHP-FPM live in a config/ directory, and you override them by mounting your own files into the right paths. No custom build system, no DSL, no magic.
Versioning follows semver properly. You get latest (updated weekly with Alpine patches), full major.minor.patch tags for immutable pinning, and major.minor and major tags if you want to float within a range. That's the kind of tag discipline you want when you're deciding what goes into production.
How to Try It
The fastest path is a single docker run:
docker run -p 80:8080 trafex/php-nginx
Then hit http://localhost for the PHP info page, or http://localhost/test.html for the static HTML page. To serve your own code, mount it into /var/www/html:
docker run -p 80:8080 -v ~/my-codebase:/var/www/html trafex/php-nginx
Customizing config is just a matter of mounting files over the defaults. For Nginx:
docker run -v "`pwd`/nginx-server.conf:/etc/nginx/conf.d/server.conf" trafex/php-nginx
For PHP settings, mount into /etc/php85/conf.d/, and for PHP-FPM, into /etc/php85/php-fpm.d/. The README notes that -v needs absolute paths, which is why the examples use pwd.
If you need more than the basics, there are dedicated docs for adding xdebug, adding composer, getting the real client IP behind a load balancer, and sending email. Those are the four things people usually end up googling when they run PHP in a container, so it's a sensible list.
The repository is at github.com/trafex/docker-php-nginx.
Final Thoughts
This isn't trying to be a framework or a platform. It's a well-configured starting point — a reference image for people who want Nginx and PHP-FPM in a container without inheriting a pile of decisions they didn't make. If you're running a small-to-medium PHP app and you care about image size and running as non-root, it's worth a look. If you need a lot of extensions baked in or heavy customization, you'll likely end up forking it — which, given the KISS goal, is probably exactly what the author expects.