How to Configure PHP-FPM Logging to stdout/stderr in Docker Containers


1 views

When containerizing PHP-FPM applications, one common pain point is handling logs in a Docker-native way. While writing logs to files inside the container works, it violates the 12-factor app principle of treating logs as event streams.

The symlink approach that works for Nginx doesn't reliably work for PHP-FPM due to how the service handles file descriptors. Here's why the common solution fails:

# This often doesn't work as expected
RUN ln -sf /dev/stdout /var/log/fpm-access.log
RUN ln -sf /dev/stderr /var/log/fpm-php.www.log

Solution 1: Direct stdout/stderr Configuration

The most reliable method is modifying the PHP-FPM pool configuration:

# /etc/php5/fpm/pool.d/www.conf
[www]
; Replace existing log configuration with:
access.log = /proc/self/fd/2
catch_workers_output = yes
php_admin_value[error_log] = /proc/self/fd/2
php_admin_flag[log_errors] = on

Solution 2: Using Docker Logging Drivers

For advanced use cases, configure Docker's logging driver to capture the file logs:

# docker-compose.yml example
services:
  php-fpm:
    image: your-php-fpm-image
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

If logs still don't appear in docker logs, check:

  • Filesystem permissions on /proc/self/fd/
  • PHP-FPM worker process ownership
  • Docker container user namespace configuration

Here's a complete Dockerfile implementation:

FROM php:8.2-fpm

RUN apt-get update && apt-get install -y \
    && docker-php-ext-install pdo_mysql

# Configure PHP-FPM logging
RUN echo "access.log = /proc/self/fd/2" >> /usr/local/etc/php-fpm.d/docker.conf \
    && echo "catch_workers_output = yes" >> /usr/local/etc/php-fpm.d/docker.conf \
    && echo "php_admin_value[error_log] = /proc/self/fd/2" >> /usr/local/etc/php-fpm.d/docker.conf \
    && echo "php_admin_flag[log_errors] = on" >> /usr/local/etc/php-fpm.d/docker.conf

# Ensure proper permissions
RUN chmod -R 777 /proc/self/fd/

For centralized logging systems:

[www]
access.log = syslog
slowlog = syslog
php_admin_value[error_log] = syslog

When running PHP-FPM in Docker containers, many developers face difficulties getting logs to appear in docker logs output. The standard approach of writing logs to files in /var/log works, but breaks Docker's logging best practices.

The traditional PHP-FPM configuration writes logs to physical files:

access.log = /var/log/fpm-access.log
php_admin_value[error_log] = /var/log/fpm-php.www.log

While this works for accessing logs via shell, it prevents Docker from automatically collecting and forwarding these logs.

Here's the proper way to configure PHP-FPM for Docker logging:

# In your Dockerfile
RUN sed -i '/^;catch_workers_output/ccatch_workers_output = yes' /etc/php5/fpm/pool.d/www.conf && \
    sed -i '/^;access.log/caccess.log = /proc/self/fd/2' /etc/php5/fpm/pool.d/www.conf && \
    sed -i '/^;php_admin_value[error_log]/cphp_admin_value[error_log] = /proc/self/fd/2' /etc/php5/fpm/pool.d/www.conf

1. Use /proc/self/fd/2 (stderr) instead of /dev/stderr for better compatibility
2. Ensure catch_workers_output is set to yes
3. For separate access and error logs:

access.log = /proc/self/fd/1
php_admin_value[error_log] = /proc/self/fd/2

Here's a full working example:

FROM php:5-fpm

# Configure PHP-FPM logging
RUN echo "catch_workers_output = yes" >> /usr/local/etc/php-fpm.d/www.conf && \
    echo "access.log = /proc/self/fd/2" >> /usr/local/etc/php-fpm.d/www.conf && \
    echo "php_admin_value[error_log] = /proc/self/fd/2" >> /usr/local/etc/php-fpm.d/www.conf && \
    echo "php_admin_flag[log_errors] = on" >> /usr/local/etc/php-fpm.d/www.conf

# Additional PHP configuration
RUN echo "display_errors = stderr" >> /usr/local/etc/php/php.ini

EXPOSE 9000
CMD ["php-fpm"]

If logs still don't appear in docker logs:

  • Verify the PHP-FPM worker processes have permission to write to stdout/stderr
  • Check if any other configuration is overriding your settings
  • Test with a minimal configuration to isolate the issue

For PHP versions before 5.3, you might need to use symbolic links:

RUN mkfifo /var/log/fpm-access.log && \
    mkfifo /var/log/fpm-php.www.log && \
    chown www-data:www-data /var/log/fpm-*.log && \
    (tail -f /var/log/fpm-access.log >> /proc/self/fd/1 &) && \
    (tail -f /var/log/fpm-php.www.log >> /proc/self/fd/2 &)