导读:本期聚焦于小伙伴创作的《如何解决 Docker 中 Nginx 无法正确代理 PHP-FPM 的问题》,敬请观看详情。把 Nginx 和 PHP-FPM 分容器部署后,页面频繁出现 502 错误或者浏览器直接下载 php 文件,多半是 FastCGI 通信配置有误。两个服务若不在同一网络,Nginx 用 localhost 根本访问不到 FPM 容器。正确的做法是在 docker-compose 中建专用 bridge 网络,Nginx 的 fastcgi_pass 应写容器名加 9000 端口。另外,FPM 的 listen 必须设为 0.0.0.0:9000 而非 unix socket,否则跨容器无法连通。脚本路径也要保持一致,避免 primary script 找不到。理清这些点,代理故障就能快速排除。

在 Docker 环境里将 Nginx 与 PHP-FPM 拆分为独立容器是最常见的 PHP 部署形态,但许多人在配置后发现 Nginx 返回 502 Bad Gateway,或者浏览器把 index.php 当成文件下载。这类问题通常不是程序代码错误,而是容器间通信与 FastCGI 参数没有对齐所致。下面从网络、配置、路径三个层面说明如何排查与修复。

如何解决 Docker 中 Nginx 无法正确代理 PHP-FPM 的问题

一、容器网络与 fastcgi_pass 地址

最典型的故障是 Nginx 配置里写了 fastcgi_pass 127.0.0.1:9000;。在容器化环境中,Nginx 容器有自己的回环地址,PHP-FPM 运行在另一个容器,因此 127.0.0.1 指向的是 Nginx 自己,自然连不上 FPM,于是报 502。必须让两个容器处于同一个自定义 bridge 网络,并使用容器名(或服务名)作为主机名访问。

使用 docker-compose 时,声明一个网络并将服务都加入其中。Nginx 的 fastcgi_pass 应写成 php-fpm:9000,这里的 php-fpm 是 compose 服务名,Docker 内置 DNS 会将其解析为对应容器 IP。若手动跑 docker run,则需加 --network mynet 并确保 FPM 容器同名或可通过别名访问。

version: '3'
services:
  nginx:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
      - ./code:/var/www/html
    networks:
      - appnet
  php-fpm:
    image: php:fpm-alpine
    volumes:
      - ./code:/var/www/html
    networks:
      - appnet
networks:
  appnet:
    driver: bridge

二、PHP-FPM 监听地址配置

官方 php:fpm 镜像默认监听 9000 端口,且绑定到 0.0.0.0,这适合跨容器访问。但如果你挂载了自定义 www.conf,里面可能出现 listen = /run/php/php-fpm.sock。Unix socket 只能本机进程间通信,跨容器绝对连不上,Nginx 会报连接拒绝。

解决方法是将 FPM 的 listen 改为 0.0.0.0:9000,并确认 listen.allowed_clients 未限制来源(或设为任意)。改完重启 FPM 容器,用 docker exec 进 nginx 容器执行 nc -zv php-fpm 9000 验证端口通断,通了才算网络层就绪。

; 在 php-fpm 的 pool 配置中
[www]
listen = 0.0.0.0:9000
listen.allowed_clients = any
user = www-data
group = www-data

三、Nginx FastCGI 脚本路径映射

即使网络通了,仍可能遇到 "Primary script unknown" 错误。这是因为 Nginx 收到的请求交给 FPM 时,FPM 要在自己容器内的文件系统里找脚本。两个容器挂载了相同的代码目录(如 /var/www/html),但 Nginx 配置里的 rootfastcgi_param SCRIPT_FILENAME 若不一致,就会找不到文件。

正确写法是 Nginx 的 root 设为 /var/www/html,并在 location ~ .php$ 块中使用 fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name; 或直接用 $document_root$fastcgi_script_name。注意 FPM 容器也必须把代码挂到同样的绝对路径,否则路径对不上。

server {
    listen 80;
    root /var/www/html;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ .php$ {
        fastcgi_pass php-fpm:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

四、权限与日志排查

若上述都正确但依旧异常,需看日志。Nginx 侧查 /var/log/nginx/error.log,FPM 侧查 /usr/local/var/log/php-fpm.log 或标准输出。常见还有权限问题:FPM 进程用户(如 www-data)对挂载的代码目录无读权限,导致脚本无法打开。可在宿主机把目录权限设为 755,文件 644,或在 compose 中加 user: "1000:1000" 匹配宿主机用户。

另外,SELinux 开启的系统上,挂载目录可能被阻止访问,可临时设 setenforce 0 验证。确认是 SELinux 原因后,用 chcon 修改上下文而非直接关闭安全模块。经过网络、监听、路径、权限四步核对,Docker 中 Nginx 代理 PHP-FPM 的问题基本都能解决。

# 查看 nginx 容器日志
docker logs nginx_container_name

# 进入 fpm 容器看进程与监听
docker exec -it php-fpm_container_name sh
netstat -tlnp | grep 9000

DockerNginxPHP-FPM修改时间:2026-08-10 04:51:12

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。