Skip to content

PHP-FPM Image

Complete web stack with separate PHP-FPM and Nginx images, for web apps, REST APIs and SPAs. Security headers, gzip compression, static asset caching, FPM pool tuning. All configurable via ENV.

Overview

The project provides two companion images: headgent/phpfpm (PHP-FPM with a complete extension stack) and headgent/nginx (pre-configured reverse proxy with security hardening). Both are multi-arch, multi-stage and configurable via environment variables without rebuilding.

GitHub: jardisOps/phpfpm

ImageTag formatSize
headgent/phpfpm8.2, 8.3, 8.4, latest~130 MB
headgent/nginx1.28~25 MB
PropertyValue
PHP versions8.2, 8.3, 8.4
Nginx version1.28
Architectureslinux/amd64, linux/arm64
BaseAlpine 3.23

Installation

bash
docker pull headgent/phpfpm:8.4
docker pull headgent/nginx:1.28

Quick Start

yaml
# docker-compose.yml
services:
  app:
    image: headgent/phpfpm:8.4
    volumes:
      - ./:/app
    environment:
      PHP_MEMORY_LIMIT: 256M
      XDEBUG_MODE: "off"
      FPM_PM_MAX_CHILDREN: 10

  webserver:
    image: headgent/nginx:1.28
    ports:
      - "80:80"
    environment:
      APP_ROOT: /app
      DOCUMENT_ROOT: /public
      INDEX_FILE: index.php
      PHP_PORT: 9000
    depends_on:
      - app

PHP-FPM Image

Extensions

The PHP-FPM image includes the same extension stack as the CLI image, except for pcntl (not relevant for FPM processes):

Database: pdo, pdo_mysql, mysqli, pdo_pgsql Messaging: amqp (2.2.0), rdkafka (6.0.5) Caching: apcu (5.1.28), redis (6.3.0), opcache Web/I/O: curl, soap, sockets, dom, zip Text: mbstring, intl, bcmath Media: gd (FreeType + JPEG), exif Debugging: xdebug (3.5.1), pcov (1.0.12)

PHP Configuration

Identical to the CLI image, with these differences:

VariableCLI DefaultFPM Default
PHP_MAX_EXECUTION_TIME0 (unlimited)30 (seconds)
XDEBUG_MODEdebugoff
OPCACHE_VALIDATE_TIMESTAMPS0 (production)
OPCACHE_REVALIDATE_FREQ20 (production)

FPM Pool Configuration

VariableDefaultDescription
FPM_PMdynamicProcess manager (static, dynamic, ondemand)
FPM_PM_MAX_CHILDREN5Max worker processes
FPM_PM_START_SERVERS2Initial workers
FPM_PM_MIN_SPARE_SERVERS1Min idle workers
FPM_PM_MAX_SPARE_SERVERS3Max idle workers
FPM_PM_MAX_REQUESTS500Requests per worker before restart

Pool Tuning for Production

For production loads: FPM_PM=static with FPM_PM_MAX_CHILDREN = available RAM ÷ ~40 MB per worker. A server with 4 GB RAM → FPM_PM_MAX_CHILDREN=80 (minus OS + Nginx + Redis).

Health Check

The image has a built-in health check via the FPM ping endpoint:

cgi-fcgi -bind -connect 127.0.0.1:9000 /ping → "pong"

Status endpoint: /status (FPM pool statistics).

Nginx Image

Features

  • Gzip compression — level 6, for JS, JSON, XML, CSS, text, SVG
  • Security headers — HSTS, CSP, X-Frame-Options, X-Content-Type-Options, X-XSS-Protection
  • Static asset caching — 1 year for CSS, JS, images, fonts, icons
  • FastCGI optimization — 128k buffer, 600s timeout, correct PATH_INFO handling
  • Real IP support — Docker networks and private networks
  • Security — blocks .htaccess, .svn, .git, .env

Configuration

VariableDefaultDescription
APP_ROOT/appApplication base directory
DOCUMENT_ROOT/publicRelative document root
INDEX_FILEindex.phpFront controller
HOSTlocalhostServer name
PHP_PORT9000PHP-FPM port

The Nginx configuration is generated at startup via envsubst from a template. Variables are substituted at runtime.

Security Headers

Referrer-Policy: no-referrer-when-downgrade
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Strict-Transport-Security: max-age=31536000; includeSubDomains
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'

Blocked Paths

/.htaccess  → 403
/.svn       → 403
/.git       → 403
/.env       → 403

Security

  • Non-root execution — both images run as appuser (configurable via PUID/PGID)
  • Automatic UID/GID adaptation — FPM image adapts to volume owner
  • No Xdebug in production — default XDEBUG_MODE=off
  • expose_php = Off — PHP version not exposed
  • Server tokens disabled — Nginx version not exposed
  • Health check — FPM ping on port 9000

Makefile

TargetDescription
make phpfpm-buildBuild PHP-FPM locally
make phpfpm-build-allBuild all PHP versions locally
make nginx-buildBuild Nginx locally
make build-allBuild all images locally
make phpfpm-pushBuild PHP-FPM multi-arch and push
make phpfpm-push-allPush all PHP versions multi-arch
make nginx-pushPush Nginx multi-arch
make build-and-push-allBuild and push everything
make build-cache-deleteDelete buildx cache
make infoShow build configuration

Use Cases

  • Web frameworks — Laravel, Symfony, Slim, custom
  • REST APIs & GraphQL — JSON endpoints with FastCGI optimization
  • Single-page apps — static asset serving with 1-year cache
  • E-commerce & SaaS — production stack with pool tuning
  • WordPress & CMS — standard PHP applications