FORMA

常见故障排查思路

本文文件名为 seror.md(service error 缩写),对应本目录学习路径中「阶段 10:调优与安全」的故障排查部分;姊妹篇 se.md安全基础。核心概念见 Nginx 核心概念

故障排查的关键是快速定位,而非盲目重试。下面按最常见的五种现象归类,每一种都给出清晰的排查路径和解决思路。

一、502 Bad Gateway

现象
浏览器显示 502 Bad Gateway,错误日志常见记录:

text
upstream prematurely closed connection while reading response header from upstream

含义
Nginx 作为反向代理时,能连接上后端服务器,但后端没有返回有效的 HTTP 响应(比如进程崩溃、端口未监听、返回了无法解析的垃圾数据)。

排查步骤

  1. 后端服务是否存活?
    bash
    # 检查后端端口是否在监听
    netstat -tlnp | grep <后端端>
    # 直接 curl 后端地址,看是否返回正常
    curl -v http://127.0.0.1:8080/
    

    若直接访问后端就报错或连接拒绝,说明问题不在 Nginx,是应用服务挂了或未启动。
  2. 后端是否有语法错误或异常退出?
    查看后端日志(PHP-FPM、Gunicorn、Node.js 进程)。PHP-FPM 超时、内存溢出、脚本致命错误等都会导致 502。
  3. Nginx 与后端协议不匹配
    例如设置了 proxy_http_version 1.1 但后端不支持,或后端要求 HTTP/1.0。可尝试强制 HTTP/1.0。
  4. 后端响应头过大
    如果后端返回的响应头超过 proxy_buffer_size 的限制(默认 4k 或 8k),Nginx 会直接中断并返回 502。可增大:
    nginx
    proxy_buffer_size 16k;
    proxy_buffers 4 32k;
    
  5. PHP-FPM 进程数耗尽
    当所有子进程都在处理请求时,新请求会等待,如果配合了超时,可能直接 502。调整 pm.max_children 并观察 pm.status_path

快速验证
curl -v https://yourdomain 看响应信息,同时 tail -f /var/log/nginx/error.log,对照上游地址和状态。

二、504 Gateway Timeout

现象
浏览器显示 504 Gateway Time-out,错误日志类似:

text
upstream timed out (110: Connection timed out) while reading response header from upstream

含义
Nginx 在指定的时间内没有从后端收到完整的响应。根本原因是后端处理耗时 > Nginx 等待的超时时间

排查步骤

  1. 确认超时配置是否过短 查看当前 proxy_read_timeout(默认 60s):
    nginx
    location / {
        proxy_read_timeout 60s;
    }
    

    如果后端任务本身就需要长时间运行(例如报表导出、大数据查询),适当调大此值:
    nginx
    proxy_read_timeout 300s;
    

    同时可调整 proxy_connect_timeoutproxy_send_timeout
  2. 检查后端应用响应时间 在 Nginx 访问日志中启用 $upstream_response_time,观察哪类请求耗时高:
    nginx
    log_format timing '$remote_addr - $request_time '
                      'upstream=$upstream_response_time '
                      'status=$status';
    

    统计慢请求,针对性优化数据库查询、接口逻辑或第三方调用。
  3. 后端服务健康状态 即使连接建立,后端可能因高负载而无法在短时间内生成响应。查看应用服务器的 CPU/内存/线程。
  4. 网络延迟 如果后端部署在不同机房,检查网络 RTT,在超时设置中预留余量。

注意:不要盲目调高超时去掩盖应用性能问题,正确处理是:优化慢接口 + 适当超时 + 异步化长耗时任务

三、403 Forbidden

现象
页面返回 403 Forbidden,错误日志常见:

text
directory index of "/data/www/" is forbidden

text
open() "/data/www/index.html" failed (13: Permission denied)

原因归类与解决

  1. 目录缺少索引文件且 autoindex 未开启
    当请求的是目录(如 /),但该目录下没有 index 指令指定的文件(index.html, index.php 等),又禁用了目录列表,Nginx 默认返回 403。
    解决:添加索引文件或开启 autoindex on;(仅限非敏感目录)。
  2. 文件系统权限问题
    Nginx 的 worker 进程运行用户(如 www-data)无权读取请求的文件或目录。
    bash
    # 检查文件权限和属主
    ls -l /data/www/index.html
    

    确保对该用户有 读权限(目录需有执行权限 x,文件需有读权限 r)。修正:
    bash
    chown -R www-data:www-data /data/www
    chmod 755 /data/www
    

    同时检查父目录权限,整个路径都需要对 worker 用户至少可执行。
  3. deny 规则误伤
    前面配置的 allow/denydeny all 覆盖了正常 IP。
    curl -v 观察请求,并在日志中看来源 IP 是否正确(是否经过了代理导致 IP 变化)。
  4. 文件系统 ACL 或 SELinux
    在 CentOS/RHEL 上,SELinux 可能阻止访问非标准 Web 目录。可临时 setenforce 0 测试,若恢复正常则调整上下文 chcon -R -t httpd_sys_content_t /data/www 或直接使用标准目录。

四、404 与 location 匹配问题

现象
明明文件存在,但访问返回 404 Not Found。

根本原因
请求 URI 没有按预想被正确的 location 处理,最终用错了 rootalias 路径。

排查思路

  1. 验证 location 匹配是否正确 在错误日志启用 debug 级别(针对特定 IP),观察 location 匹配过程,或通过 add_header 回应测试:
    nginx
    location /app {
        add_header X-Location "app block";
    }
    

    然后用 curl -I http://domain/app/ 查看返回的头部,确认命中了哪个块。
  2. 区分 rootalias 误用
    • root /data/www; 加上请求 /images/1.jpg 查找的实际路径是 /data/www/images/1.jpg
    • alias /data/www; 加上请求 /images/1.jpg 查找的实际路径是 /data/www/1.jpg
      请严格按照前面核心模块章节的对比检查配置。注意 alias 末尾要带 /,如果 location 也带 /
  3. 正则优先级覆盖 如果定义了多个 location,写了正则,可能某个宽泛的正则先匹配而忽略了更准确的普通前缀。回顾 location 优先级= > ^~ > ~ 或 ~* > 前缀。若无意中定义了 ~ \.php$ 匹配,可能把图片请求都传给 PHP,导致 404。调整匹配顺序或使用 ^~ 阻止正则。
  4. try_files 路径错误 如果 try_files 写了 $uri /index.html,但 /index.html 的实际路径拼接后不存在,也会产生 404。检查 root 指令继承关系。

快速验证:在配置中临时开启 error_log /tmp/nginx-debug.log debug; 并触发请求,查看文件路径。

五、重定向循环

现象
浏览器报 “ERR_TOO_MANY_REDIRECTS”,地址栏不断在两个 URL 间跳转。

常见原因与解决

  1. HTTP 到 HTTPS 的死循环
    反向代理 Nginx 后面如果还有一个 Nginx 或 CDN 处理 HTTPS,前端 Nginx 发出 HTTP 请求,后端又跳转回 HTTPS,形成循环。
    检查proxy_set_header X-Forwarded-Proto $scheme; 是否被正确设置,并且后端应用信任该头。对于 WordPress 等,可能需要配置 $_SERVER['HTTPS'] = 'on' 基于该头。
  2. return 301 的递归
    nginx
    server {
        listen 80;
        server_name example.com;
        return 301 http://www.example.com$request_uri;
    }
    

    如果 www.example.com 又解析回当前 server,且本 server 又跳转,即出现循环。
    解决:确保跳转目标对应另一个 server 块,或者使用 if ($host !~ ^www\.) { ... } 有条件跳转。
  3. rewrite 规则未加 last 或产生二次匹配
    一个 rewrite 修改 URI 后,如果不加 last,可能后续的 rewrite 规则又将其改回来。检查所有 rewrite 规则,确保有一个终止条件。
  4. Cloudflare/CDN 的 SSL 配置不当
    如果源站设置了强制 HTTPS,但 CDN 用 HTTP 回源,源站返回 301 到 HTTPS,CDN 继续用 HTTP 请求…… 需要设置 CDN 的加密模式为 “Full” 或 “Full (strict)”。

排查命令

bash
curl -L -v http://example.com 2>&1 | grep -E "^(> GET |< HTTP|Location:)"

观察跳转链,找出哪一步产生了出乎意料的 301/302。

六、首选排查武器:nginx -t 与错误日志

无论遇到什么问题,养成两个第一时间动作:

  1. 配置测试 nginx -t
    每次修改配置后必须运行:
    bash
    nginx -t && nginx -s reload
    

    它会检测语法错误、上下文错误,并打印出错文件名和行号,避免因错误配置导致服务中断。
  2. 紧盯错误日志
    绝对多数问题都会在 error_log 留下痕迹。为方便排查,建议:
    bash
    tail -f /var/log/nginx/error.log
    

    一旦请求出现异常,立刻就能看到具体的 upstream 状态、权限拒绝、重定向过多等详细说明。临时将日志级别调至 warnerror 过滤噪音:
    nginx
    error_log /var/log/nginx/error.log error;
    

    如果本地环境,可针对特定 IP 开启 debug 日志深入。

排错心法:遇到问题 → 看错误日志 → 重现请求并观察 → 定位具体 location/upstream → 逐个假设验证。始终保留一份已知正常的可回滚配置,对故障零容忍。

七、排障常备命令速查

命令用途
nginx -t检查配置语法,改配置后的第一反应
nginx -s reload平滑重载配置,不中断现有连接
tail -f /var/log/nginx/error.log实时观察错误日志
curl -v -I <url>只看响应头,快速判断状态码与关键 Header
netstat -tlnp | grep <port>确认端口是否被正确监听
nginx -V查看编译参数,确认是否包含所需模块(如 --with-http_ssl_module

把这张表贴在常用终端旁边,遇到问题先按顺序过一遍,往往能在几分钟内定位到大方向。

延伸阅读

  • Nginx 核心概念:理解 Master-Worker、反向代理等原理,是看懂本文排错思路的前提。
  • 安全基础:限流、IP 控制等安全配置本身也可能是故障(如误杀正常流量)的来源,出现异常 403/503 时可对照排查。

参考文献

资料说明
nginx 文档官方
运维导读学习路径
nginx -V 参数说明编译参数

Series

nginx

7 / 7

安全基础