502 的全称是 Bad Gateway,翻译过来叫坏网关。这个翻译其实挺误导人的,因为它让人以为网关坏了。真实情况是:Nginx 好端端地在那儿,问题永远出在它背后的上游服务,绝大多数时候就是 PHP-FPM。搞清这一点,排查方向就不会跑偏。
第一段,确认 FPM 还活着。systemctl status php-fpm 一眼就能看出来,如果进程不在,先看它为什么起不来——刚改完配置就起不来,八成是配置文件写错了,php-fpm -t 会把出错的文件和行号直接报出来。这一步能解决掉相当比例的 502。
第二段,也是最常踩的坑:socket 路径对不上。Nginx 里的 fastcgi_pass 指向的 socket,必须和 FPM 池配置里的 listen 完全一致。升过 PHP 版本的人对此应该有印象——系统装的是 php8.3-fpm.sock,配置里还写着 php8.2-fpm.sock,路径对不上,每个请求都是 502。两边 grep 一下对照,十秒钟的事。
第三段,权限。socket 文件确实存在,Nginx 依然连不上,日志里会出现 Permission denied。这时候别急着 chmod 777,那只是掩盖问题,重启之后还会复现。正确做法是在池配置里指明 socket 的属主属组和权限,让它每次重启都生成正确的。
第四段,进程耗尽。这类 502 最阴险,因为它挑时间——凌晨两点一切正常,白天高峰期突然全站 502。特征是 FPM 日志里出现 server reached pm.max_children,意思是进程开到上限了,新请求排不上队。默认的 pm.max_children 通常只有 5,稍有流量就不够用。
#!/bin/bash
# 502 四段定位:存活 -> 路径 -> 权限 -> 进程数
LOG="/var/log/nginx/error.log"
echo "--- 1. FPM 是否存活 ---"
systemctl is-active php-fpm 2>/dev/null || systemctl is-active 'php*-fpm' 2>/dev/null
php-fpm -t 2>&1 | tail -n 3
echo "--- 2. 监听与转发是否一致 ---"
echo "[FPM listen]"; grep -R "^listen" /etc/php/*/fpm/pool.d/ 2>/dev/null
echo "[Nginx fastcgi_pass]"; grep -R "fastcgi_pass" /etc/nginx/ 2>/dev/null
echo "--- 3. socket 属主与权限 ---"
stat -c "%U:%G %a %n" /run/php/*.sock 2>/dev/null
echo "--- 4. error.log 关键字归类 ---"
grep -oE "Connection refused|No such file or directory|Permission denied|recv\(\) failed|too big header|max_children" \
"$LOG" | sort | uniq -c | sort -rn
日志里那几个关键字基本能对号入座:Connection refused 是上游根本没监听;No such file or directory 是 socket 路径写错了;Permission denied 是权限;recv() failed 多半是 PHP 进程中途被杀,常见于内存不足被 OOM 干掉;too big header 是响应头超了缓冲区;max_children 就是进程数打满。一个关键字对应一条明确的处置路径,不用猜。
改完务必走一遍 nginx -t 再 reload,别直接 restart。reload 是平滑重载,已有的连接不会断;restart 会把正在处理的请求一起掐掉,在生产环境上这是无谓的额外损失。
顺带说一句,如果你近期动过 PHP 版本或做过系统大版本升级,突然全站 502,别往复杂了想,先去对 socket 路径。十个里有七八个是这个原因,剩下的才是权限和进程数。
数据来源:Nginx ngx_http_fastcgi_module 官方文档
申请创业报道,分享创业好点子。点击此处,共同探讨创业新机遇!


