php-fpm
rollogi/php-fpm:{version} is the php image plus PHP-FPM and nothing else. Use it when the web server runs in its own container: an nginx or Caddy service in Docker Compose, a sidecar in the same Kubernetes pod, or an ingress that speaks FastCGI. If you want one container that does both, use php-nginx.
Quick start
The web server and PHP-FPM must see your application at the same path, because the web server sends PHP-FPM the file name to run. Both containers below mount it at /var/www/html.
services:
php:
image: rollogi/php-fpm:8.4
volumes:
- ./:/var/www/html:ro
web:
image: nginx:1.30-alpine
ports:
- "8080:80"
volumes:
- ./:/var/www/html:ro
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
server {
listen 80;
root /var/www/html/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass php:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
In Kubernetes the same applies inside one pod: nginx and php-fpm share a volume with the code, and nginx passes to 127.0.0.1:9000.
What you get
- PHP-FPM on port 9000 on every interface, so a web server in another container can reach it.
EXPOSE 9000is declared; never publish the port to the internet. FastCGI has no authentication. - The same configuration surface as php-nginx. Every
PHP_*variable,php.<setting>,fpm.pool.<setting>andfpm.global.<setting>works, and the pool is rendered from the same template, so moving between the two images changes nothing about PHP. - A FastCGI healthcheck. The image's
HEALTHCHECKrunsphp-fpm-healthcheck, which asks the pool's/fpm-pingpath over FastCGI and expectspong. It followsPHP_FPM_LISTEN, including a unix socket. - Pool status at
/fpm-statusfor a FastCGI exporter such asphp-fpm_exporter. - Optional client allowlist.
PHP_FPM_LISTEN_ALLOWED_CLIENTSsetslisten.allowed_clients.127.0.0.1is always added so the healthcheck keeps working. - Startup commands and cron as in the other images:
APP_INSTALLruns in/var/www/htmlbefore PHP-FPM starts, andCRON_SCHEDULEwithCRON_COMMAND, or a crontab atCRONTAB_FILE, runs alongside PHP-FPM through supercronic. - Tagged logs for
[php-fpm],[entrypoint],[install]and[cron].
Variables
The PHP-FPM variables are shared with php-nginx. Two defaults differ here:
| Variable | Default | Description |
|---|---|---|
PHP_FPM_LISTEN | 0.0.0.0:9000 | Listen address. A path such as /run/php/php-fpm.sock listens on a unix socket in a shared volume instead. |
PHP_FPM_LISTEN_ALLOWED_CLIENTS | (any) | Comma-separated addresses allowed to connect, for example 10.0.0.5,10.0.0.6. |
APP_INSTALL_DIR | /var/www/html | Where APP_INSTALL runs. |
PHP_SESSION_COOKIE_SECURE defaults to Off because TLS terminates in the web server container. Set it to On when the site is served over HTTPS.
Users and read-only root
php-fpm runs as UID 1000 by default and works under any --user. In root mode the master runs as root and the pool workers drop to nobody. The read-only recipe needs tmpfs mounts on /run, /tmp and /var/log:
docker run --rm --read-only \
--tmpfs /run:uid=1000,gid=1000 --tmpfs /tmp --tmpfs /var/log:uid=1000,gid=1000 \
--cap-drop ALL --security-opt no-new-privileges \
-v $(pwd):/var/www/html:ro rollogi/php-fpm:8.4
Running other commands
serve is the default command. Anything else runs instead of PHP-FPM, with the configuration rendered first, so the same image works for one-off tasks:
docker run --rm -v $(pwd):/var/www/html -w /var/www/html rollogi/php-fpm:8.4 php artisan migrate --force