Nginx 反向代理配置与 502 排查实战
一、最小可用的反向代理配置
下面是一段能直接上线的反向代理配置,挂在 conf.d/app.conf 里:
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 5s;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
}
}几个点必须说清楚:proxy_pass 结尾带不带 / 语义不同。写成 http://127.0.0.1:8080/ 会把 location 匹配到的前缀替换掉,写成 http://127.0.0.1:8080 则原样透传 URI。配置改完用 nginx -t 校验,再用 nginx -s reload 生效,不要用 restart,会断连接。
二、502 的三类根因
Nginx 返回 502 的含义只有一句:上游返回了无效响应,或连接根本没建起来。按发生位置分三类。
- 连不上上游:端口没监听、进程挂了、防火墙拦截。用
ss -lntp | grep 8080确认监听,用curl -v http://127.0.0.1:8080/health绕开 Nginx 直连验证。 - 连上了但超时:上游处理超过
proxy_read_timeout。默认 60 秒,导出大文件或跑长 SQL 时很容易触发。 - 上游主动断开:应用崩溃、被 OOM Killer 杀掉,或 PHP-FPM 进程池打满。
第一步永远是看日志:
tail -n 100 /var/log/nginx/error.log grep -c ' 502 ' /var/log/nginx/access.log
error.log 里的 connect() failed (111: Connection refused) 是端口没人听;upstream timed out 是超时;recv() failed (104: Connection reset by peer) 是上游崩了。这三种指向完全不同的排查方向。
三、坑一:Host 头丢失导致上游 502
某次把应用从 IP 访问改成域名访问后,Nginx 全量 502,直连后端却正常。原因是没有配 proxy_set_header Host $host,Nginx 默认把 Host 设成 proxy_pass 里的地址,即 127.0.0.1:8080。后端的 Spring Boot 开了虚拟主机校验,认不出这个 Host 就直接 reset 连接。
验证方式是在后端抓包看请求头:
tcpdump -i lo -A -s 0 'tcp port 8080' | grep -i host
补上 proxy_set_header Host $host; 后恢复。如果后端还依赖真实 IP 做限流,X-Real-IP 和 X-Forwarded-For 也要一起加,否则日志里全是 127.0.0.1。
四、坑二:keepalive 没配,端口被 TIME_WAIT 占满
QPS 到 2000 左右时开始零星 502,error.log 报 Cannot assign requested address。这是 Nginx 到上游每次请求都新建 TCP 连接,短连接大量堆积在 TIME_WAIT,本地临时端口耗尽。
解决分两步。上游块里声明 keepalive:
upstream backend {
server 127.0.0.1:8080;
keepalive 64;
}
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}注意 proxy_http_version 1.1 和清空 Connection 缺一不可,缺了 keepalive 不生效。另外把 net.ipv4.tcp_tw_reuse 设为 1。改完后 ss -s 观察,timewait 数量应从数万降到几百。
五、快速定位的检查顺序
nginx -t确认配置语法,排除 reload 失败导致的旧配置继续服务。curl -v http://127.0.0.1:8080/直连上游,确认应用本身是否健康。tail -f /var/log/nginx/error.log看具体错误串,按三类根因对号入座。ss -lntp和ps aux | grep 应用名确认进程与端口。dmesg -T | grep -i oom检查是否被系统杀掉。
小结
502 不是 Nginx 自己的错误,它只是转述上游的问题。配置层面把 Host、X-Forwarded-*、keepalive 三项固定下来,能消掉大部分线上 502。排查时先用 error.log 的错误串判断是连接失败、超时还是连接被重置,再决定去查端口、查超时参数还是查应用进程,不要一上来就调 proxy_read_timeout。
- 点赞
- 收藏
- 关注作者
评论(0)