From 415cd4baf85e658526d89c096cd5f68d7c978d75 Mon Sep 17 00:00:00 2001 From: Elijah Duffy Date: Mon, 8 Dec 2025 02:25:54 -0800 Subject: [PATCH] php-fpm: improve dockerfile, switch to per-lane www.conf Shared www.conf isn't viable due to differing supported options between PHP-FPM versions. Additionally, the Dockerfile multi-stage build wasn't useful as it copied build artifacts. Switched to single-stage with build artifact pruning. --- php-fpm/7.4/Dockerfile | 83 +++++++++++++++++++++-------------------- php-fpm/7.4/www.conf | 54 +++++++++++++++++++++++++++ shared/php-fpm/www.conf | 31 --------------- 3 files changed, 96 insertions(+), 72 deletions(-) create mode 100644 php-fpm/7.4/www.conf delete mode 100644 shared/php-fpm/www.conf diff --git a/php-fpm/7.4/Dockerfile b/php-fpm/7.4/Dockerfile index 681341e..ec3fc7e 100644 --- a/php-fpm/7.4/Dockerfile +++ b/php-fpm/7.4/Dockerfile @@ -1,7 +1,9 @@ -# Multi-stage Alpine-based PHP 7.4 FPM image optimized for WordPress -ARG BASE_TAG=7.4-fpm-alpine3.16 -FROM php:${BASE_TAG} AS build +# Alpine-based PHP 7.4 FPM image optimized for WordPress +ARG BASE_VERSION=7.4 +ARG BASE_TAG=${BASE_VERSION}-fpm-alpine3.16 +FROM php:${BASE_TAG} +# Install build dependencies, PHP extensions, and runtime dependencies in a single layer RUN set -eux; \ apk add --no-cache --virtual .build-deps \ $PHPIZE_DEPS \ @@ -10,7 +12,6 @@ RUN set -eux; \ g++ \ make \ pkgconfig \ - bash \ freetype-dev \ libjpeg-turbo-dev \ libpng-dev \ @@ -21,6 +22,25 @@ RUN set -eux; \ oniguruma-dev \ mariadb-dev \ ; \ + \ + # Install runtime dependencies + apk add --no-cache \ + bash \ + freetype \ + libjpeg-turbo \ + libpng \ + libxml2 \ + zlib \ + icu-libs \ + libzip \ + mariadb-client \ + openssl \ + ca-certificates \ + tzdata \ + ; \ + update-ca-certificates; \ + \ + # Configure and install extensions docker-php-ext-configure gd --with-freetype --with-jpeg; \ docker-php-ext-install -j"$(nproc)" \ gd \ @@ -38,40 +58,24 @@ RUN set -eux; \ soap \ pcntl \ ; \ + \ + # Install PECL extensions pecl channel-update pecl.php.net; \ pecl install redis && docker-php-ext-enable redis; \ + \ + # Use production php.ini cp "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"; \ + \ + # Clean up build dependencies apk del .build-deps; \ rm -rf /var/cache/apk/* /tmp/* -FROM php:${BASE_TAG} AS runtime - -RUN set -eux; \ - apk add --no-cache \ - freetype \ - libjpeg-turbo \ - libpng \ - libxml2 \ - zlib \ - icu-libs \ - libzip \ - mariadb-client \ - openssl \ - ca-certificates \ - tzdata \ - ; \ - update-ca-certificates || true - -# Copy built PHP and extensions from the build stage -COPY --from=build /usr/local/lib/php /usr/local/lib/php -COPY --from=build /usr/local/etc/php /usr/local/etc/php - # Create a non-root application user and prepare webroot directory -RUN addgroup -g 1000 app || true; \ - adduser -D -u 1000 -G app app || true; \ - mkdir -p /var/www/html; \ - chown -R app:app /var/www/html; \ - mkdir -p /var/run/php /run/php /var/log/php; \ +RUN addgroup -g 1000 app && \ + adduser -D -u 1000 -G app app && \ + mkdir -p /var/www/html && \ + chown -R app:app /var/www/html && \ + mkdir -p /var/run/php /run/php /var/log/php && \ chown -R app:app /var/run/php /run/php /var/log/php # Minimal security / production tuning for opcache and PHP @@ -92,19 +96,16 @@ RUN set -eux; \ echo 'error_log = /proc/self/fd/2'; \ } > /usr/local/etc/php/conf.d/zz-hardening.ini -EXPOSE 9000 - -HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 CMD pgrep -f "php-fpm" || exit 1 - -WORKDIR /var/www/html - # Copy pool configuration and entrypoint from shared path in repo root -COPY --chown=root:root shared/php-fpm/www.conf /usr/local/etc/php-fpm.d/www.conf +COPY --chown=app:app php-fpm/${BASE_VERSION}/www.conf /usr/local/etc/php-fpm.d/www.conf COPY --chown=root:root shared/php-fpm/entrypoint.sh /usr/local/bin/entrypoint.sh RUN chmod 755 /usr/local/bin/entrypoint.sh +WORKDIR /var/www/html +USER app + ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] - -USER root - CMD ["php-fpm"] + +EXPOSE 9000 +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 CMD pgrep -f "php-fpm" > /dev/null || exit 1 diff --git a/php-fpm/7.4/www.conf b/php-fpm/7.4/www.conf new file mode 100644 index 0000000..9e79965 --- /dev/null +++ b/php-fpm/7.4/www.conf @@ -0,0 +1,54 @@ +; PHP-FPM pool configuration for PHP 7.4, optimized for WordPress in a container. + +[www] +; Listen on a TCP socket. This is standard for containerized setups +; where Nginx and PHP-FPM are in separate containers. +listen = 0.0.0.0:9000 + +; Run as the non-root 'app' user for security. +user = app +group = app + +; Use the 'dynamic' process manager to scale child processes based on demand. +; This is memory-efficient for sites with variable traffic. +pm = dynamic + +; The maximum number of child processes to be created. +; This is the most important setting. The value depends on available RAM. +; A typical WordPress process can use 30-60MB RAM. 10 children = ~300-600MB. +; Adjust this based on your container's memory limit. +pm.max_children = 10 + +; The number of child processes created on startup. +pm.start_servers = 2 + +; The minimum number of idle processes. If less than this, new ones will be created. +pm.min_spare_servers = 1 + +; The maximum number of idle processes. If more than this, some will be killed. +pm.max_spare_servers = 3 + +; The number of requests each child process should execute before respawning. +; This is a crucial feature to prevent memory leaks from third-party code or plugins. +pm.max_requests = 500 + +; The timeout for serving a single request after which the worker process will be killed. +; Helps prevent long-running scripts from tying up resources. +request_terminate_timeout = 300s + +; The timeout for serving a single request after which a PHP backtrace will be +; dumped to the slowlog. Useful for debugging performance issues. +request_slowlog_timeout = 5s +slowlog = /var/log/php/www-slow.log + +; Redirect worker stdout and stderr to the main error log. +; This ensures that any `echo` or `var_dump` calls from workers are captured in the container logs. +catch_workers_output = yes + +; We are logging errors to stderr in zz-hardening.ini, so we can disable the FPM access log +; to avoid redundant logging and improve performance. Nginx should handle access logging. +; access.log = /var/log/php/www-access.log + +; Ensure that PHP-FPM does not clear environment variables. +; This is important for passing variables from the container runtime (e.g., Docker Compose). +clear_env = no diff --git a/shared/php-fpm/www.conf b/shared/php-fpm/www.conf deleted file mode 100644 index aa79f57..0000000 --- a/shared/php-fpm/www.conf +++ /dev/null @@ -1,31 +0,0 @@ -; Shared php-fpm pool configuration for containers - -[www] -listen = 0.0.0.0:9000 - -user = app -group = app - -listen.owner = app -listen.group = app -listen.mode = 0660 - -pm = dynamic -pm.max_children = 10 -pm.start_servers = 2 -pm.min_spare_servers = 1 -pm.max_spare_servers = 3 -pm.max_requests = 500 - -request_terminate_timeout = 300s -request_slowlog_timeout = 5s -slowlog = /var/log/php/www-slow.log - -catch_workers_output = yes -access.log = /var/log/php/www-access.log - -clear_env = no - -emergency_restart_threshold = 10 -emergency_restart_interval = 1m -process_control_timeout = 10s