排查 nginx 反向代理 502/504 错误
· 阅读需 4 分钟
把这个博客部署起来之后,访问偶发 502、504。前端就一个静态站点,后端就一个 nginx 容器,链路很简单,但越是简单的链路,问题越容易被忽略。记一下这次排查的过程。
环境
- 浏览器 →
192.168.1.3上的 nginx-ui(反代,终止 TLS) - nginx-ui →
192.168.1.5:8080上的容器(nginx 托管静态文件)
偶发,不是必现,大概十次里一两次。
现象
- 大部分请求正常 200。
- 偶发 502 Bad Gateway,或 504 Gateway Timeout。
- 刷新一下往往就好了。
排查思路
502/504 的本质是「反代拿不到上游的有效响应」。要么上游没响应(504 超时),要么上游拒绝了连接 / 连接被重置(502)。所以排查分两条线:
- 上游本身是不是活的——容器 nginx 在不在、监听对不对。
- 反代到上游的网络通不通——连接能不能建立、建立后能不能在超时内完成。
第一步:确认上游存活
# 容器状态
docker ps | grep www-anderslane
# 容器内 nginx 监听
docker exec www-anderslane wget -qO- http://localhost:80/ | head -5
# 从反代机直接打上游
curl -v -H 'Host: www.anderslane.cn' http://192.168.1.5:8080/
结果:容器在,监听正常,从反代机 curl 上游也 200。说明上游是活的,问题出在「偶发」上。
第二步:看反代错误日志
# nginx-ui 容器的错误日志
docker logs <nginx-ui-container> 2>&1 | grep -E 'upstream|502|504'
抓到关键几行:
upstream timed out (110: Connection timed out) while reading response header from upstream
upstream prematurely closed connection while reading response header from upstream
两类错误:
Connection timed out:TCP 连上了,但上游迟迟不回响应头 → 504。upstream prematurely closed connection:连接建立后被上游主动关了 → 502。
第三步:上游资源排查
容器是静态文件服务,怎么会超时?看容器资源:
docker stats --no-stream www-anderslane
发现偶发时段 CPU 飙到接近 100%,内存也接近上限(docker-compose.yml 里限了 256m)。再看进程:
docker exec www-anderslane ps aux
nginx worker 之外,多了一堆 wget --spider 进程——那是 healthcheck。
根因
docker-compose.yml 的健康检查:
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:80/"]
interval: 30s
timeout: 5s
retries: 3
wget --spider 在 alpine 上实际会发起请求并解析响应,30s 一次本不算频繁。但 mem_limit: 256m 偏紧,nginx 在高并发或被健康检查挤占时,worker 偶发 OOM 被杀、连接被重置 → 反代侧表现就是 502/504。
两条因素叠加:
- 内存上限太紧,峰值时 worker 被杀。
- 健康检查和正常请求抢资源,放大了峰值。
处理
- 放宽内存上限到 512m,给 nginx worker 留余量。
- 健康检查换成更轻的探测,直接打一个静态小文件,少解析。
- 反代侧
proxy_read_timeout设 30s(本来就是),proxy_connect_timeout设 5s 快速失败。 - 给静态资源开
expires长缓存,减少回源压力。
改完观察两天,502/504 消失。
复盘
几条经验:
- 偶发 502/504 先看上游资源,别一上来就调反代超时。超时只是症状,根因往往是上游扛不住。
- 容器资源限制要留余量,256m 对 alpine + nginx 平时够用,但峰值(OOM 边缘)会偶发杀进程,很难复现。
- 健康检查本身也是负载,在资源紧张的容器里别用重检查。
- 日志是最快的线索:
upstream timed outvsprematurely closed区分了超时和重置,直接指向不同方向。
排查这类问题的顺序我习惯是:上游存活 → 上游资源 → 网络/超时 → 反代配置。前两步排掉,剩下的基本就是配置调优了。