Nginx 502 与 504 排查手册:先分清是"连不上"还是"等太久"
502 和 504 看着都是网关错误,但成因完全相反:一个是上游根本没连上,一个是连上了但超时。搞混方向会让排查绕大圈。
#先建立正确的判断顺序
很多人在遇到 502 时第一反应是重启服务,这没错,但跳过了定位环节,下次还会犯。
正确的第一步是看错误日志里 Nginx 给出的原因:
tail -n 50 /www/wwwlogs/example.com.error.log
关键就两种:
| 日志关键字 | 含义 | 排查方向 |
|---|---|---|
connect() failed (111: Connection refused) |
上游端口没人监听 | 进程挂了 / 端口错了 |
upstream timed out (110: Connection timed out) |
连上了但响应太慢 | 业务卡住 / 超时设置太短 |
502 对应前者,504 对应后者。 这个区分能省掉一半的排查时间。
#情况一:502 —— 上游连不上
按这个顺序排查,每一步都能排除一类原因:
# 1. 进程活着吗
pm2 list
# 2. 端口在监听吗(这是最关键的一步)
ss -ltn | grep 3000
# 3. 从本机能不能打通
curl -I http://127.0.0.1:3000
# 4. 看应用自己的报错
pm2 logs nebula-blog --lines 50
如果第 2 步端口不存在,问题 100% 在应用侧,和 Nginx 无关。常见原因:
- 应用启动就崩了:多半是环境变量缺失或依赖没装全
- 监听地址写成了 0.0.0.0 以外的具体外网 IP:容器或某些环境下拿不到这个地址,导致绑定失败
- 端口被别的进程占了:
ss -ltnp | grep 3000能看到占用者
如果第 2 步端口在,但 curl 不通,检查 Nginx 配置里的 proxy_pass 地址是不是写错了端口。
一个容易被忽略的点:SELinux 开启时会拦截 Nginx 向本机端口的转发。用
getenforce确认,如果是Enforcing,需要setsebool -P httpd_can_network_connect 1。
#情况二:504 —— 等太久了
504 说明连接建立了,但上游在规定时间内没返回。Nginx 默认的 proxy_read_timeout 是 60 秒。
先判断是"偶发慢"还是"稳定慢":
- 偶发:多半是某个接口在做重活(大批量导入、外部 API 调用)。解决办法是把这类请求异步化,而不是单纯调大超时。
- 稳定慢:说明存在性能瓶颈,调超时只是掩盖问题。
如果确认是合理的长任务,再针对性放宽:
location /api/export {
proxy_pass http://127.0.0.1:3000;
proxy_read_timeout 300s; # 读取超时
proxy_send_timeout 300s; # 发送超时
proxy_connect_timeout 15s; # 连接超时,这个不要放大
}
注意 proxy_connect_timeout 不要跟着放大。 它的意义是"连不上就快速失败",调大只会让故障暴露得更晚。
#情况三:看起来是 502,其实是别的
有两种"假 502"值得单独提:
1. 响应头过大导致 502
上游返回的 Header 超过 Nginx 缓冲区大小时,Nginx 会报 upstream sent too big header。典型场景是应用写了很多 Cookie。
proxy_buffer_size 16k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
2. 请求体过大返回 413
上传大文件时报的不是 502 而是 413,需要在 Nginx 和 Node 两侧同时放开:
client_max_body_size 120m;
app.use(express.json({ limit: '2mb' }));
// multer 的文件大小限制
multer({ limits: { fileSize: 100 * 1024 * 1024 } });
两侧限制必须一致或 Nginx 更宽,否则会出现"小文件能传、大文件报 502"这种诡异现象。
#一个通用的排查脚本
#!/usr/bin/env bash
# 用法:bash nginx-diag.sh example.com 3000
DOMAIN=${1:?域名}
PORT=${2:?端口}
echo "=== 1. Nginx 配置语法 ==="
nginx -t
echo "=== 2. 上游进程 ==="
pm2 list 2>/dev/null | head -10
echo "=== 3. 端口监听 ==="
ss -ltn | grep ":$PORT" || echo "!! 端口 $PORT 没有监听"
echo "=== 4. 本机直连 ==="
curl -s -o /dev/null -w "HTTP %{http_code} / 耗时 %{time_total}s\n" --max-time 10 "http://127.0.0.1:$PORT/healthz"
echo "=== 5. 最近错误日志 ==="
tail -n 20 "/www/wwwlogs/$DOMAIN.error.log" 2>/dev/null
echo "=== 6. SELinux ==="
getenforce 2>/dev/null || echo "未启用"
#相关资源
以下资料可直接下载:
服务器只读巡检脚本
一条命令采集系统、CPU、内存、磁盘、Docker、端口与防火墙信息,不修改任何系统状态,适合部署前体检。
#小结
| 现象 | 本质 | 第一件事 |
|---|---|---|
| 502 | 连不上上游 | ss -ltn 确认端口 |
| 504 | 上游响应超时 | 看业务日志找慢点 |
502 + too big header |
响应头超缓冲区 | 调 proxy_buffer_size |
| 413 | 请求体超限 | 同时改 Nginx 与应用限制 |
排查的本质是先把范围缩小到"应用侧"还是"网关侧",再往下钻。跳过这一步,就只能在黑暗中试错。
附件下载 共 1 个文件,点击直接下载
Nginx 反向代理站点配置模板
含 HTTPS 跳转、证书自动续期目录放行、WebSocket 升级、静态资源缓存与安全响应头的完整配置模板,改两个变量即可用。