
在 docker 环境中将 php 错误重定向到 stdout 时,错误消息会同时出现在 php-fpm 和 nginx 容器日志中,这是因 php-fpm 默认通过 stderr 向 fastcgi 传递错误所致;正确做法是将 `error_log` 指向 `/proc/self/fd/2`,确保日志仅输出一次且符合 12-factor 日志原则。
当你在 PHP-FPM 容器中设置 error_log = /dev/stdout 时,看似已将错误导向标准输出,但实际仍可能触发 PHP-FPM 的默认错误处理机制——它会主动将错误内容写入 stderr(即文件描述符 2),而该流会被 Nginx 的 FastCGI 模块捕获并封装为 [error] ... FastCGI sent in stderr: "PHP message: ..." 日志,导致同一错误在两个容器中重复出现。
根本原因在于:/dev/stdout 是一个符号链接(通常指向 /proc/self/fd/1),而 PHP-FPM 在内部错误处理路径中对 stderr(fd 2)有特殊逻辑。若未显式覆盖,部分错误(尤其是 error_log() 调用之外的警告、Notice 或配置级错误)仍会走 stderr 通路。
✅ 正确解决方案是将 error_log 显式设为 /proc/self/fd/2:
; php.ini 或 www.conf 中配置 error_log = /proc/self/fd/2
或在运行时通过 php-fpm.conf 或环境变量注入(推荐使用 Dockerfile 或 php-fpm.d/ 配置挂载):
立即学习“PHP免费学习笔记(深入)”;
# Dockerfile 示例(基于 php:8-fpm) COPY docker-php-error-log.ini /usr/local/etc/php/conf.d/docker-php-error-log.ini
docker-php-error-log.ini 内容如下:
; 将所有 PHP 错误强制输出到 stderr(即容器 stdout) error_log = /proc/self/fd/2 log_errors = On display_errors = Off
⚠️ 注意事项:
- 不要使用 error_log = /dev/stderr:在某些 Alpine 基础镜像中 /dev/stderr 可能不可靠或被重定向;
- /proc/self/fd/2 是 Linux 下最稳定的方式,它直接映射当前进程的 stderr 文件描述符,确保与容器日志系统完全对齐;
- 同时务必关闭 display_errors(如你已在 index.php 中所做),避免错误泄露到 HTTP 响应体;
- Nginx 侧无需修改配置——只要 PHP-FPM 不再向 stderr 发送冗余错误,Nginx 就不会记录 FastCGI sent in stderr 日志。
? 验证效果:
重启服务后执行请求,你将只在 PHP-FPM 容器日志中看到:
docker-compose-nginx-phpfpm-php-fpm-1 | NOTICE: PHP message: test
而 Nginx 容器日志中不再出现对应 FastCGI sent in stderr 行,实现干净、单源、可聚合的日志输出,真正践行 12-Factor Logs 原则。











