本文解决的报错 502 Bad Gateway / connect() failed (111: Connection refused) while connecting to upstream

Nginx 报 502 Bad Gateway 的四种原因和排查顺序

502 的意思不是「Nginx 坏了」,而是「Nginx 找不到后面那个应用」。搞清楚这一点,排查方向就只有一个。

先搞懂 502 是什么意思

访问网站看到 502,很多人第一反应是去重启 Nginx。方向错了。

看一眼架构就明白:

浏览器  →  Nginx (80端口)  →  你的 FastAPI 应用 (8000端口)
                 ↑                      ↑
             它是好的              问题在这里

Nginx 只是个「转发员」。它收到请求后去找 8000 端口上的应用,找不到,才回一个 502 告诉你「我后面那个人不见了」

所以 502 说明:Nginx 是活着的,挂掉的是你的应用。

看 Nginx 的错误日志能确认:

tail -30 /var/log/nginx/error.log

典型的一行:

connect() failed (111: Connection refused) while connecting to upstream,
upstream: "http://127.0.0.1:8000/"

Connection refused = 8000 端口根本没人接。

按这个顺序排查

第一步:应用还活着吗

systemctl status blog

Active: 那一行。是 failedinactive (dead) 就说明应用挂了,直接看日志:

journalctl -u blog -n 50 --no-pager

90% 的 502 到这一步就找到原因了。 常见的有:

  • Python 报错启动失败(依赖没装、代码有语法错)
  • 数据库连不上(密码错、MySQL 没启动)
  • .env 文件不存在或权限不对

第二步:端口对得上吗

应用显示是 running,但还是 502:

ss -tlnp | grep 8000

正常输出应该像这样:

LISTEN 0 2048 127.0.0.1:8000 0.0.0.0:* users:(("uvicorn",pid=1234,fd=8))

没有输出 = 应用虽然"活着"但没在监听这个端口。blog.service 里核对 --port 参数,和 Nginx 配置里的 proxy_pass 端口是否一致。

我踩过一次:service 里写的 8000,Nginx 里写的 8080。

第三步:绕过 Nginx 直接测应用

curl -i http://127.0.0.1:8000/healthz
  • 返回 {"status":"ok"} → 应用没问题,是 Nginx 配置的问题
  • 连不上 → 应用的问题,回第一步

这一步是关键的分界点,能把问题范围一刀切成两半。

第四步:Nginx 配置本身

nginx -t                    # 检查配置语法
systemctl reload nginx      # 语法没问题就重载

nginx -t 会明确指出哪个文件哪一行有问题。

改完配置一定要 reload

改了 .conf 文件但没 reload,Nginx 用的还是旧配置。 我在这上面浪费过 20 分钟,一直纳闷「明明改对了怎么还是 502」。

四种原因汇总

原因 怎么确认 怎么修
应用启动失败 journalctl -u blog -n 50 看报错,多半是依赖或数据库
端口不一致 ss -tlnp \| grep 8000 统一 service 和 Nginx 里的端口
Nginx 配置错 nginx -t 按提示改,然后 reload
应用被 OOM 杀了 dmesg \| grep -i "killed process" 加 swap 或减少 worker 数量

最后一个在 1G 内存的轻量服务器上很常见。内存不够时系统会直接杀掉最占内存的进程,日志里会有 Out of memory: Killed process

真正的教训

我在这个问题上卡了将近一小时,因为一上来就在改 Nginx 配置——而问题根本不在那儿。

后来总结出一条:排查网络问题永远从里往外

应用 → 端口 → 反向代理 → 防火墙 → 安全组 → DNS

先确认最里面那层是好的,再往外走一层。跳着查只会浪费时间。