# auvem/php-fpm-wordpress — multi-version PHP-FPM + nginx Docker images This repository contains Dockerfiles and configuration for building PHP-FPM images optimized for WordPress and a companion nginx image. It aims to make adding and maintaining multiple PHP versions straightforward while keeping builds reproducible and small. ## Repository Layout - `php-fpm/` — top-level directory containing PHP version lanes - `7.4/` — PHP 7.4 FPM lane (multi-stage, Alpine-based) - `Dockerfile` — builds PHP + required extensions - `...` - `nginx/` — NGINX build configuration with batteries-included configuration file - `Dockerfile` — nginx:alpine-slim image that ships `nginx.conf` - `nginx.conf` — default server config that works with the php-fpm image - `shared/php-fpm/` — canonical shared files - `www.conf` — canonical php-fpm pool config - `entrypoint.sh` — optional guarded entrypoint to fix mount permissions at container start ### Note about shared files and builds The CI workflow is configured to build with the repository root as the Docker build context and to point Docker to lane Dockerfiles (for example, `file: docker/7.4/Dockerfile`). That means Dockerfiles can safely `COPY` shared files from `docker/php-fpm/` without requiring per-lane duplicates. This reduces maintenance overhead — keep the canonical copy in `docker/php-fpm/www.conf` and the CI will make it available to all lanes. ## Adding a new PHP version 1. Create `php-fpm//` (e.g. `php-fpm/8.1/`). 2. Copy `php-fpm/7.4/Dockerfile` (for example) into the new directory and update `ARG BASE_TAG` to the desired `php:-fpm-alpine` tag. 3. Adjust `docker-php-ext-install`/build deps if needed. 4. Update the `matrix.lane` list for the `build` job in `.github/workflows/php-fpm.yml`. 5. Push — CI will detect the new lane and build it. NOTE: CI will additionally rebuild all other images registered in `matrix.lane`, cost tradeoff of this overhead vs. the benefits of intermittent rebuilds with latest OS security patches built-in should be weighed. ## Bind mounts and permissions - Images use `/var/www/html` as the webroot. When you mount a host directory over that path the mount replaces the image contents, including ownership. - Recommended safe options: - Pre-chown host files to UID/GID 1000 before starting containers: ```bash sudo chown -R 1000:1000 ./wp_root ``` - Or enable the entrypoint-based fixup in php-fpm by setting `CHOWN_ON_START=1` for the `php-fpm` service (the entrypoint is guarded — it only runs when this env is explicitly enabled). ## Logging & debugging - PHP-FPM streams master/worker logs plus PHP fatals to stderr, so `docker compose logs php-fpm` (or your platform equivalent) will always contain the messages you need for incident response. - The auto-prepend bootstrap additionally installs shutdown/exception hooks that write uncaught throwables and fatal errors to stderr even if WordPress or a plugin tampers with `ini_set()`. - When you need full stack traces in the browser, set `FORCE_DEBUG_ERRORS=1` on the `php-fpm` service. The bootstrap enables verbose output and logs a single notice so you remember to remove it later. - Remove or unset `FORCE_DEBUG_ERRORS` after troubleshooting so production responses stay clean. ## Local Testing & Development Use the provided `docker-compose.yml` in the repo root for local development — it builds images from the repo (so shared files are available) and mounts `./wp_root` for site content. ## Production Example Below is an example `docker-compose.yml` for production deployments that pulls images from the package registry at gitea.auvem.com. Adjust image versions and secrets as appropriate. ```yaml services: mariadb: image: mariadb:latest restart: unless-stopped environment: MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: ${MYSQL_PASSWORD} MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} volumes: - ./db_data:/var/lib/mysql php-fpm: image: gitea.auvem.com/auvem/wordpress-docker/php-fpm:7.4-stable restart: unless-stopped depends_on: - mariadb volumes: - ./wp_root:/var/www/html:rw nginx: image: gitea.auvem.com/auvem/wordpress-docker/nginx:latest restart: unless-stopped ports: - "80:80" depends_on: - php-fpm volumes: - ./wp_root:/var/www/html:ro ``` ## CI / build notes ### Security & hardening - Multi-stage builds keep final images minimal and reduce attack surface. - PHP uses `php.ini-production` with opcache tuned. The php-fpm pool is configured to drop workers to `app` (UID 1000) while the master runs as `root` to avoid socket/permission surprises; workers remain unprivileged. - The nginx config contains conservative security headers and blocking of hidden files; review and extend headers (CSP, COEP, COOP) as needed per-site. ### Production deployment and archival - For archival (quiesce + tar), stop services and `tar` the `./wp_root` and any associated volumes (database dump + attachments). Ensure services are fully topped to avoid inconsistent state.