HTTP 502 错误会让服务瞬间受阻。用户看到的是一个含糊的失败页面,而你的监控系统则会立刻亮起告警。残酷的现实是:Nginx 只是传话的人,真正的问题出在你的反向代理之后。

本指南提供一套逐步排查的方法,帮助你找出 Nginx 中 502 Bad Gateway 错误的根本原因。你将了解“我该如何一步步找到根本原因?”这个问题的答案:从代理错误日志开始,然后逐层检查上游服务、网络规则、Nginx 配置以及系统安全层。每一层都会进一步缩小排查范围。

只要按照这个顺序执行,你就能停止盲目猜测,真正修复每一次 502 背后的实际问题。

从代理错误日志入手诊断 502 Bad Gateway

当你遇到 HTTP 502 错误时,第一步永远应该是查看代理错误日志。这些日志会准确告诉你,为什么反向代理返回了 502。先不要急着查看应用程序,也不要立刻调整超时设置。先看代理错误日志。Nginx 在其中写下的消息,往往会直接指出根本原因。这样做可以为你节省数小时的盲目排查时间。每一次 Nginx 中的 bad gateway 错误,都会从这些日志里留下线索。你不需要猜测错误是怎么产生的,日志会立刻给出答案。

定位 Nginx 错误日志

你首先需要检查 Nginx 错误日志。默认路径通常是 /var/log/nginx/error.log。许多发行版还会为单独的 server block 使用 /var/log/nginx/your-site-error.log。要确认准确路径,请检查你的 Nginx 配置文件,查找 error_log 指令,路径就紧跟在该指令之后。

找到文件后,请实时查看日志。可以使用命令 tail -f /var/log/nginx/error.log。在命令运行时重现 502 Bad Gateway 错误。错误发生时,新的日志行会立即出现。你就能看到 Nginx 返回该错误的准确时间点。

你还可以使用 grep 过滤特定消息。运行 tail -f /var/log/nginx/error.log | grep upstream。这会只显示包含 upstream 的日志行。过滤后更容易聚焦与代理相关的错误。忽略与静态文件有关的无关条目,只关注包含 upstream 或 connect 的消息。

识别常见日志消息

打开错误日志,重点观察四种常见模式。每一种模式都对应着不同的上游问题。下面这张表列出了最常见的消息、它们通常意味着什么,以及你的下一步操作:

日志消息可能原因下一步操作
connect() failed (111: Connection refused)应用已停止,或 proxy_pass 使用了错误端口检查服务监听状态和当前生效配置
upstream timed out应用过慢、数据库过慢,或工作线程池耗尽在提高超时值之前,先追踪延迟与资源压力
upstream prematurely closed connection应用崩溃、连接被重置,或响应过程失败对照应用日志与进程重启时间进行关联排查
no live upstreams上游池中的所有后端都不可用检查健康检查、部署状态和上游地址

最常见的错误消息是 connect() failed (111: Connection refused)。这表示上游服务器已宕机。应用进程可能已经崩溃,或者根本没有启动,也可能是代理指向了错误的端口。代理收到的是“连接被拒绝”,说明在该地址上没有应用正在监听。

第二种最常见的模式是 upstream prematurely closed connection。代理把请求发送给上游后,上游开始处理,但在完整响应返回之前就断开了连接。这通常说明以下两种情况之一:

  • 上游服务器可能因为超时设置过短而主动断开连接。这样代理会在请求完成前收到 FIN 或 RST 数据包。
  • 上游应用可能在处理过程中崩溃。端口上不再有进程监听,此时操作系统内核会向代理发送一个 RST 数据包。
  • 无论哪种情况,代理都会把这种过早关闭视为发给 Nginx 的无效响应,最终结果就是 502 Bad Gateway。

因此,当你看到这条消息时,应立即检查上游应用日志。查看是否存在崩溃堆栈,或是否有超时限制。应用本身会告诉你它为什么断开连接。

确认上游服务器正在运行

后端崩溃或根本未启动,是 502 Bad Gateway 最常见的原因。在查看完代理错误日志后,下一步合乎逻辑的操作,就是确认上游应用是否真的在监听请求。错误日志已经告诉你是哪个上游地址连接失败,现在你需要确认该地址背后的进程是否存活。仅这一步,就能解决大多数触发该错误的 Nginx 事故。不要跳过。你的目标是在检查其他层之前,先确保上游服务器处于运行状态。当 Nginx 从上游服务器收到无效响应时,就会返回你看到的错误码。来自上游的无效响应或无响应,都会导致同样的结果。理解这些日志消息,能帮助你把错误日志和实际问题对应起来。

检查服务状态

大多数 Linux 发行版都使用 systemd 管理应用服务。你可以用一条命令检查 PHP-FPM 或 Gunicorn 这类上游服务是否处于活动状态。在上游主机上打开终端,运行以下通用状态检查命令:

systemctl status <service-name> —— 这是一个通用命令,可用于检查任何由 systemd 管理的服务状态,包括 Node.js、PHP-FPM 或 Gunicorn。

将 <service-name> 替换为你的实际服务名。对于 PHP 应用,具体命令通常会包含版本号:

sudo systemctl status php8.1-fpm —— 用于检查 PHP-FPM 服务状态。

输出通常会显示三种状态之一:active、inactive 或 failed。如果你看到 active 且带有 running 标记,说明服务还活着。如果看到 inactive 或 failed,就用 sudo systemctl start <service-name> 启动服务。然后再次测试 502 是否消失。如果服务是 active,但错误仍然存在,就继续看下一小节。错误日志中也可能出现 upstream server is unavailable 之类的消息,这通常发生在服务无法启动时。

如果你使用 Node.js,可通过 ps aux | grep node 确认进程是否还在。同时也要检查应用日志。Node.js 应用常常会静默崩溃,而不会通知进程管理器。一个已停止的 Node 进程,未必会在系统日志中留下明显错误。你必须查看它自己的日志文件,才能知道退出原因。像 PM2 这样的工具可以自动重启进程,但根本原因仍然需要通过日志来调查。

测试端口与连通性

服务正在运行,并不代表它一定监听在你预期的端口上。应用可能启动在了另一个接口或另一个端口,而不是你在 Nginx 中配置的那个。这种不匹配会导致 upstream server is unavailable 的情况。Nginx 尝试连接,却发现目标地址上没有服务,于是将状态记为 upstream server down,错误日志也会记录这一失败。

可以在 Nginx 主机上使用 curl -v http://localhost:PORT 测试直连。将 PORT 替换为上游端口。若响应成功,说明应用确实有输出;若出现 Connection refused,则可确认端口不匹配。此时应检查应用实际绑定的端口,然后把 proxy_pass 指令改成正确值。你也可以使用 telnet 作为替代测试。运行 telnet <upstream-ip> <port>。连接成功时,通常会出现一个空白屏幕并闪烁光标;如果失败,则会显示 Connection refused。

对于 Nginx Proxy Manager 用户,即使在管理界面中看到的协议和端口似乎都正确,502 仍然可能出现。此时应直接验证上游容器或服务,例如在 Nginx 容器内部,或在运行 Nginx Proxy Manager 的主机上执行 curl。因为 Web 界面显示的内容,并不总能反映运行时的真实状态。

如果 curl 成功,但 Nginx 仍然返回 502 Bad Gateway,那么问题可能出在超时、缓冲区或其他层面。但如果 curl 失败,你就已经确认上游服务器不可达。先修复应用监听问题,再继续下一步。

排除防火墙和网络拦截

防火墙规则或云安全组可能会在 Nginx 与上游服务器之间悄悄拦截流量。应用本身运行正常,端口监听也没问题,但 Nginx 仍会返回 502,因为某个包过滤器丢弃了连接请求。这一层位于两个都“看似健康”的服务之间,因此很容易被忽视。

检查防火墙规则

先从列出 Nginx 主机上的活动规则开始。命令 iptables -L -n -v 会显示所有链(包括 INPUT、OUTPUT 和 FORWARD)的规则及其匹配流量。你可以借此验证,发往特定上游端口的流量是否被允许。更简洁的视图是 iptables -L,它会列出默认表中的当前活动规则,让你快速了解整个防火墙配置。

另外两条命令也有助于你审查规则集:

  • sudo iptables -S —— 以可保存、可复用的格式显示当前规则集。示例输出通常会列出 INPUT、FORWARD 和 OUTPUT 链的默认策略(例如都为 ACCEPT),以及是否存在额外规则。
  • sudo iptables -L —— 以更易读的表格形式显示规则。示例输出会展示 INPUT、FORWARD 和 OUTPUT 链的默认策略,以及当前活动规则(例如允许 RELATED,ESTABLISHED 连接的 ACCEPT 规则)。

如果你的 Nginx 运行在云环境中,还要检查该实例对应的安全组或网络 ACL。这些控制位于主机之外,可能在 iptables 看到流量之前就已经把连接拦截了。

使用 curl 和 telnet 测试

查看规则告诉你“理论上应该怎样”,而测试才能说明“实际上发生了什么”。在 Nginx 主机上运行 curl -v http://<upstream-ip>:<port>。如果能成功响应,说明网络路径是通的;如果一直挂起或被拒绝,则说明要么有拦截,要么监听端已经失效。

你还可以使用 telnet <upstream-ip> <port> 做第二次验证。若出现空白屏幕并伴随闪烁光标,说明连接已打开;若被拒绝或超时,则表明存在拦截。如果这两项测试都失败,但服务在本机上运行正常,那么防火墙规则或安全组就是根本原因。修复规则后重新测试。一旦 Nginx 能重新连通上游,502 通常就会消失。

调整超时与缓冲区大小

一个响应缓慢的上游,也可能触发被 Nginx 记录为 502 的超时错误。代理已经在等待响应,但后端耗时太久,Nginx 最终放弃并返回错误。你看到的是网关失败,真正的问题却是延迟。这种情况通常发生在上游服务器最终是能完成响应的,只是没有在配置的时间窗口内完成。

调整 proxy_read_timeout 和 proxy_connect_timeout

有两个指令控制 Nginx 等待的时长。proxy_connect_timeout 指令设置与上游建立连接的时间上限;proxy_read_timeout 指令定义 Nginx 在两次读取上游数据之间允许等待的最长时间。只要任一限制到期,Nginx 就会关闭连接并返回 502。

这些值应根据应用的正常响应时间来设置。数据库负载较重的页面,可能需要更长的读取超时;而简单的 API 接口,可能所需时间更短。每次修改后都应重新测试。需要注意的是,如果上游本身确实过慢,单纯提高超时只是掩盖症状,因此应先调查应用性能。

为大响应头增大 proxy_buffer_size

过大的响应头同样可能引发 502。Nginx 会为上游响应头分配缓冲区,默认大小通常为 4k 或 8k。当响应头超过这个限制时,Nginx 就无法正确处理该响应,并返回错误。

根据原始说明,像 Laravel 这类会产生较长会话 Cookie 的应用、某些单点登录实现,以及返回大量 Set-Cookie 头的系统,常常会超过默认的 4k 或 8k proxy_buffer_size,从而导致 502 错误。在这些情况下,需要将 proxy_buffer_size 调大,才能避免该错误。

当你识别出这种模式后,应把 proxy_buffer_size 调整为更大的值。同时,也可以一并考虑 proxy_buffers 和 proxy_busy_buffers_size 这两个相关参数。修改之后继续观察错误日志。一旦缓冲区足以容纳完整响应头,这类与头部相关的 502 通常就会消失。

确认 Nginx 配置中的上游地址

上游名称或端口中的一个拼写错误,都是非常常见的根本原因。你可能把 Nginx 指向了错误的地址。结果就是:即使应用本身运行良好,502 仍然持续存在。因此,在排查其他层之前,你必须仔细检查 Nginx 配置。

检查 proxy_pass 和 upstream 块

proxy_pass 指令告诉作为反向代理的 Nginx,应该把请求转发到哪里。如果你把它设置为一个不存在的主机名,或一个没有服务监听的端口,那么问题就出在 Nginx 配置本身。打开你的 Nginx 配置文件,找到相关 location 块中的 proxy_pass 行,然后将其与上游应用的实际地址逐一比对。最常见的错误之一,就是端口或 socket 路径写错。比如你的应用实际监听 8080,但你却写成了 8081,这种不匹配就会导致 502。若你使用了 upstream 块,也要一并检查。upstream 块定义的是一个服务器组,随后 proxy_pass 会引用这个组名。如果被引用的名称拼写错误,结果也一样会导致 502。务必确认你使用的是正确的上游服务器和端口。你还可以在主机上直接用 curl 测试,确认该地址确实可用。这个步骤能节省大量时间,避免不必要的排查。

确认 location 块顺序

Nginx 会按照特定顺序处理 location 块。它先匹配前缀 location,然后再按照书写顺序匹配正则 location。第一个匹配到的 location 块会处理请求。如果你配置了多个都可能匹配同一 URI 的 location 块,那么请求有可能被错误的块接管,并被转发到错误的上游服务器。举例来说,你可能有一个用于 /api 的 location 块,代理到后端 A;还有一个用于 / 的 location 块,代理到后端 B。如果 /api 的匹配规则设置不当,那么访问 /api/login 时,就有可能先命中 /,导致请求被转给无法处理它的后端 B,最终出现 502。避免这种问题的方法之一,就是检查 Nginx 配置中 location 块的顺序。应把更具体的块放在兜底块之前,必要时使用 = 修饰符进行精确匹配。你还可以用 curl 测试看看到底是哪个 location 块在处理请求。理解 location 匹配优先级,能帮助你更快修复这类路由错误。一旦顺序确认正确,502 往往也会随之消失。

修复 PHP-FPM 与 Socket 权限问题

PHP-FPM 是 Nginx 常见的上游之一。若进程池停止运行,或 listen 指令配置错误,就会触发 502 错误。你必须验证进程池状态以及 socket 权限。这两项检查可以解决大多数与 PHP-FPM 有关的 502 问题。

确认 PHP-FPM 进程池状态

使用 sudo systemctl status php8.1-fpm 检查 PHP-FPM 进程池状态。请根据你的实际安装版本调整版本号。输出会显示该进程池是否处于 active 且 running 状态。如果是 inactive 或 failed,就运行 sudo systemctl start php8.1-fpm 启动它。很多情况下,这一步就能立刻解决 502。

接下来,验证 PHP-FPM 进程池配置中的 listen 指令。这个文件位于 /etc/php-fpm.d/www.conf。listen 指令定义了监听地址或 socket 路径。如果它与 Nginx 配置中的 fastcgi_pass 指令不一致,就会导致 502。运行 grep '^listen =' /etc/php-fpm.d/www.conf 查看当前设置,再与 Nginx 配置进行比对。二者必须完全一致。如果使用的是 Unix socket,那么路径必须一字不差;如果使用的是 TCP 地址,那么端口必须相同。

修正 Unix Socket 的所有权

当 listen 指令使用 Unix socket 时,文件权限就变得非常关键。Nginx 必须对该 socket 文件拥有读写权限。错误的所有权会阻止连接。下表展示了常见的权限设置。

设置项默认值 / 示例值用途
listen.ownernobody(默认注释值)Unix socket 的所有者
listen.groupnobody(默认注释值)Unix socket 的所属组
listen.mode0666(默认注释值)权限设置;需要具备读写权限
userapachePHP-FPM 进程用户
groupapachePHP-FPM 进程组

socket 所在目录同样需要具备正确的所有权和权限。下面这条命令展示了一个合适的配置方式。

解决 TLS 握手失败

如果上游使用 HTTPS,就又多了一个可能出错的环节。Nginx 连接后端,开始进行 TLS 握手,而协商失败。代理因此无法收到有效响应,于是返回 502。证书问题和协议不匹配都会导致这种结果,而且它们通常不会在访问日志中留下明显线索。

验证上游证书

证书过期、自签名证书,或者证书所签发的主机名与实际主机名不匹配,都会导致握手失败。Nginx 会拒绝上游身份并关闭连接。在更改任何配置之前,应先从 Nginx 主机直接测试上游。openssl s client 工具会显示完整的证书链以及验证结果。

只有当输出中出现诸如 Verify return code: 0 (ok) 或 Verification: OK 之类的信息时,证书检查才算通过。任何其他返回码都可能直接指向根本原因。请将其中的主机名和端口替换为你自己的上游值。如果你依赖私有 CA,也要确认 CA 文件与 Nginx 配置中引用的文件一致。

匹配协议与密码套件

协议版本或密码套件不匹配,也会导致握手失败。上游可能只接受 TLS 1.2,而 Nginx 提供的是其他版本;或者双方根本没有共同支持的密码套件。连接尝试因此失败,代理便向客户端报告 502。

检查两端的协议与密码设置。将 Nginx 配置中的 ssl_protocols 和 ssl_ciphers 指令,与上游服务器接受的参数进行比对。通过启用双方都支持的协议版本或密码套件,来扩大兼容范围。每次修改后,都应重新加载 Nginx,并再次使用 openssl s client 测试上游。只要握手成功,就说明修复已经生效。

现在,你已经有了一条可重复使用的排查路径:先看代理错误日志,再检查上游服务、网络规则、Nginx 配置和安全层。按照这个顺序,就能在不靠猜测的前提下,回答“我该如何一步步找到根本原因?”这个问题。

建议你把下面这份清单保存下来,以备下一次事故使用:

  • 首先阅读 Nginx 错误日志。
  • 确认上游进程正在运行且正在监听。
  • 使用 curl 或 telnet 测试可达性。
  • 验证 proxy_pass、超时和缓冲区设置。
  • 检查 SELinux、AppArmor 和 TLS 设置。

同一个 502 Bad Gateway 错误,很少会连续两次由同一个原因引发。持续监控上游健康状态,经常检查日志,并遵循 Nginx 代理最佳实践,能够预防大多数 502 事件。

常见问题

大多数 502 Bad Gateway 错误是由什么引起的?

最常见的原因是上游服务器已停止运行或无法访问。后端进程可能已经崩溃、停止,或者根本没有启动。应先检查代理错误日志,其中的消息通常会直接指向上游问题。

我怎么判断问题出在 Nginx 还是后端?

Nginx 错误日志会告诉你答案。出现 connection refused 消息,说明后端已停止;出现 timeout 消息,说明后端响应过慢。Nginx 只是报告故障,真正的问题仍然在后端。

即使应用运行正常,防火墙也会导致 502 吗?

会。防火墙规则或云安全组可能会在 Nginx 与上游之间丢弃数据包。服务在自己的主机上看起来一切正常,但从 Nginx 主机使用 curl 或 telnet 测试时,就能确认是否存在拦截。

为什么 502 只会在高流量时出现?

这通常意味着资源耗尽。上游工作线程池被占满,或者数据库开始变慢。Nginx 持续等待,最终超时。与其先提高超时值,不如先查看上游性能指标。

我该如何一步步找到根本原因?

从代理错误日志开始。然后确认上游进程正在运行并处于监听状态。接着测试网络可达性。之后再检查配置、超时和安全策略。每一层都会进一步缩小范围,直到你定位真正的故障点。