Nginx 与网关排障

SKILL运维和基础设施
运维和基础设施 未标注权限 许可证不明确
安装这个技能

排查 nginx(及 OpenResty/Tengine 一类同源网关)在真实部署里的经典故障:502 上游没接住、504 到底是谁的超时、499 客户端先走、413 与大文件上传、SSE/流式响应被缓冲、upstream keepalive 没生效、尾斜杠与 proxy_pass 路径重写导致的 301/404、sub_filter 静默失效、反代到 HTTPS 上游时的证书与 SNI。每个模式给出判据、根因、最小修改和验证命令,并覆盖日志字段与定位阶梯。

一句话选型结论

按资料字段整理

Nginx 与网关排障是运维和基础设施类的 Agent Skill,安装方式未标注,权限级别未标注,许可证不明确,有可直接复制的安装命令。技能本质是给模型读的说明书,效果取决于模型与客户端;装完先用一个小任务验证,再放进正式流程。

分类运维和基础设施 安装方式未标注 权限级别未标注权限 许可证许可证不明确
累计安装 未标注 本周 未标注
GitHub 星标 未标注 仓库 未标注
下载量 未标注 技能市场下载数
权限级别 未标注权限 安装前请确认风险范围
许可证 许可证不明确 未说明

安装

未标注
在支持 Skills 的客户端里执行,装完问一句「你有哪些技能」验证
skillhub install user_617dd917/nginx-gateway-troubleshoot-moran
  1. 1
    确认客户端支持

    确认你的客户端支持 Skills(Claude、Codex、Cursor 等),并升级到较新的版本。

  2. 2
    拿到技能文件

    执行上面的命令安装;也可以把仓库里的 SKILL.md 手动放进客户端的 skills 目录。

  3. 3
    刷新技能列表

    重新打开客户端,或刷新技能列表,让新放进来的技能被加载。

  4. 4
    验证是否生效

    问一句「你有哪些技能」,确认列表里出现它,再拿一个小任务试跑。

技能档案

运维和基础设施
字段来自技能仓库与公开索引,中文说明由本站标注
作者 / 维护方user_617dd917仓库 未标注 · 版本 未标注
宿主客户端未标注技能可被这些客户端加载
安装方式未标注安装包 community
权限级别未标注权限安装前请确认风险范围
许可证未说明许可证不明确,商用前请自行确认条款
仓库可用性available技能仓库当前是否可访问
最近核验2026-11-06上游最后核验时间 · 数据更新 2026-11-06
正文体量18.6 KBSKILL.md 原文大小,越大说明说明书写得越细

典型使用场景

3 类
按分类整理的常见用法,具体以 SKILL.md 为准
查服务与日志

按现象定位服务状态与日志线索。

写部署与巡检脚本

把重复的部署、巡检写成脚本。

故障排查

按步骤排查网络、依赖与配置。

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 有可直接复制的安装命令,不用自己翻文档找入口。

先想清楚的地方

  • 没有标注权限级别,实际能做什么要装好后确认。
  • 许可证不明确,商用或二次分发前先到仓库确认条款。
  • 没有做站内核验,内容以作者仓库为准。
  • 技能只是说明书,实际效果取决于模型与客户端,装完先用小任务试一遍。

更适合

  • 需要在运维和基础设施场景里给模型补一套做法的人。
  • 愿意先读一遍 SKILL.md、确认它会让模型做什么的人。

不太适合

  • 对许可证要求很严、必须明确可商用的人。
  • 只想装完就自动变强、不打算看说明书的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
技能权限级别安装方式累计安装宿主客户端安装命令
Nginx 与网关排障当前 未标注权限 未标注 未标注 未标注 有
Azure 部署 调用外部服务 GitHub 仓库 664.2 万 Codex、Claude、Cursor 有
Azure diagnostics 问题管理 调用外部服务 GitHub 仓库 657.6 万 Codex、Claude、Cursor 有
Azure aigateway 部署 调用外部服务 GitHub 仓库 655.3 万 Codex、Claude、Cursor 有
Azure AI 搜索 调用外部服务 GitHub 仓库 651.4 万 Codex、Claude、Cursor 有
Azure Cloud migrate 部署 调用外部服务 GitHub 仓库 650.7 万 Codex、Claude、Cursor 有

SKILL.md 全文

18.6 KB
模型实际读到的说明书原文,来自技能仓库

Nginx 与网关排障 — 502/504/499/413、流式与重写

nginx 站在客户端与应用之间,它报的错很少是它自己的错:502 是上游没接住,504 是某个超时到点了,499 是客户端先走了。把责任判给谁,决定了你下一步该查哪一层。

本手册按症状 → 判据 → 根因 → 最小修改 → 验证组织,覆盖九类高频故障。全部结论都以「先看日志字段、再改配置」为前提。

目录

  • 何时使用
  • 参数与占位符
  • 现场采集脚本
  • 症状索引
  • 心智模型:三层超时与两条链路
  • 模式 1 — 502:上游没接住
  • 模式 2 — 504:到底是谁的超时
  • 模式 3 — 499:客户端先走了
  • 模式 4 — 413 与大文件上传
  • 模式 5 — SSE/流式被缓冲
  • 模式 6 — upstream keepalive 没生效
  • 模式 7 — 尾斜杠与路径重写
  • 延伸阅读(日志字段 / sub_filter / SNI)
  • 错误处理约定
  • 失败模式与恢复
  • 完整走查(端到端样例)
  • 不适用场景
  • 反模式与常见问题

何时使用

自动触发:用户描述与下表场景相关时直接启用,不需要点名本技能。

用户会这么说 实际场景
「nginx 一直 502,后端明明活着」 上游连接层失败(模式 1)
「偶尔 504,后端说没超时」 超时归属判断(模式 2)
「日志里一堆 499,用户说没响应」 客户端/LB 先断开(模式 3)
「传大文件 413,改配置没用」 请求体大小与缓冲(模式 4)
「SSE 一次性到达 / 流式卡住」 缓冲与超时(模式 5)
「改了 upstream keepalive 没提速」 keepalive 配置不完整(模式 6)
「访问 /api 被 301 到怪地址」「路径丢了前缀」 proxy_pass 路径语义(模式 7)
「sub_filter 以前好使,现在不替换了」 上游改版或 gzip(模式 8)
「反代到 HTTPS 上游报证书错」 SNI 与校验(模式 9)

手动调用:对话里说「用 Nginx 与网关排障处理」,或直接用 @ 引用本技能(平台的完整 slug 可能带作者后缀,不必写全名)。

不适合:应用自身的异常(把 500 甩给网关)、Ingress 控制器(ingress-nginx 有额外注解语义)、CDN/WAF 侧规则,见文末。

参数与占位符

动手前先替换下表占位符;未替换就跑等于用错环境。

占位符 含义 从哪里取
<host> server_name nginx -T | grep -n server_name
<upstream> 上游组名 nginx -T | grep -n 'upstream '
<port> 监听或上游端口 nginx -T | grep -n listen

现场采集脚本

python scripts/nginx_triage.py --json 一条命令采完版本、nginx -T 生效配置、监听端口、error.log 的 upstream/超时行、access log 状态码分布与上游证书到期时间;proxy_pass / upstream 里的 IPv6 地址([::1]:8080)能正确解析,不给 --upstream-host 时自动从配置的 https/443 上游挑证书检查目标;输出 findings(证据 + 最小动作)与 raw(原文)。--self-test 不碰系统,用内置样本验证判据。

findings 的 code 对应本节
E-ENV-01 模式 1(502:connect() failed / prematurely closed)
E-ENV-03 模式 2、3(504 upstream timed out、499 占比)
E-ENV-04 模式 4(413 client intended to send too large body)
E-ENV-06 模式 9(上游证书 30 天内到期,见 references/subfilter-and-tls.md)

症状索引

症状 先看 关键判据
502 Bad Gateway 模式 1 $upstream_status 为空 = 没连上;有值 = 上游回了非预期响应
504 Gateway Time-out 模式 2 $upstream_response_time 是否 ≈ 某个 timeout
499 模式 3 只有 nginx 有 499;$request_time ≈ 客户端放弃时刻
413 Request Entity Too Large 模式 4 报错来自 nginx 还是上游
流式/SSE 变成一次性 模式 5 响应头是否带 X-Accel-Buffering: no、proxy_buffering 是否 off
上游连接数暴涨、TIME_WAIT 多 模式 6 upstream 块是否配了 keepalive 且请求头 Connection 被清空
301/302 到错误主机或端口 模式 7 proxy_pass 带不带 URI、server_name_in_redirect
页面元素不替换 模式 8 上游是否 gzip、sub_filter_types、pattern 是否过期
证书不匹配 / SNI 报错 模式 9 proxy_ssl_server_name、proxy_ssl_name

心智模型:三层超时与两条链路

三层超时(从外到内,任何一层先到点,用户看到的就是那一层的错):

  1. 客户端 / 负载均衡 / CDN 的超时 → 表现为 499(客户端断开)或 LB 自己的 5xx
  2. nginx 的 proxy_connect_timeout / proxy_send_timeout / proxy_read_timeout → 表现为 504
  3. 上游应用自己的超时 → 通常表现为上游返回 504/500,$upstream_status 有值

判据一句话:看 $upstream_status 和 $upstream_response_time。为空且时间接近 connect_timeout,是连不上;有值且时间接近 read_timeout,是上游太慢;两者都正常但请求仍失败,往更外层找。

两条链路:

  • 连接链路:client → nginx → upstream。每一跳都有建立、传输、关闭三种状态,502 多发生在建立或关闭阶段。
  • 缓冲链路:client_body_buffer_size(请求体)与 proxy_buffering(响应体)。缓冲区一介入,流式语义就变了,大小与超时也随之中断。

模式 1 — 502:上游没接住

判据:error.log 里出现以下之一:

connect() failed (111: Connection refused) while connecting to upstream
upstream prematurely closed connection while reading response header
no live upstreams while connecting to upstream

根因分类:

日志特征 根因 修法
Connection refused 上游没监听该地址/端口,或只监听 127.0.0.1 而 nginx 走的是容器网络 核对 proxy_pass 地址族;容器内用服务名或 host-gateway
prematurely closed 上游进程崩溃、或读请求时被重启 查上游日志与重启记录(RestartCount/systemctl status)
no live upstreams 健康检查把全部节点摘了 看 max_fails/fail_timeout,确认健康检查判据是否过严
响应头格式非法 上游返回了非 HTTP 内容(如纯文本错误) 直连上游复现,确认它真的在说 HTTP

最小修改:先别改 nginx。用 curl 直连上游地址验证连通性;不通就是上游或网络的问题。

验证:

curl -sv http://<upstream>:<port>/health -o /dev/null
# 期望:Connected to ... / HTTP/1.1 200

模式 2 — 504:到底是谁的超时

判据:$upstream_response_time 接近某个配置值。

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

三个超时各自的语义:

指令 默认 管什么 典型误配
proxy_connect_timeout 60s(默认值以 nginx -T 与所装版本文档为准) 与上游建立连接 内网通常可降到 5s,快速失败
proxy_send_timeout 60s 向上游写请求(两次写之间) 大请求体时被误判
proxy_read_timeout 60s(同上,以 nginx -T 为准) 等上游响应(两次读之间) LLM/报表类接口必须调大

注意:proxy_read_timeout 是两次读之间的间隔,不是总时长。长任务只要持续有字节回来就不会超时;而"憋很久再一次性返回"的接口必然触发。

最小修改:只对需要的 location 调大 proxy_read_timeout,别全局改。

location /api/long-task/ {
    proxy_read_timeout 300s;
    proxy_send_timeout 300s;
    proxy_pass http://app;
}

验证:构造一个稳定的慢响应(例如上游 sleep 90 再返回),确认 90s 内不再 504,且 $upstream_response_time 记录到 90 左右。

模式 3 — 499:客户端先走了

判据:$status=499、$request_time 明显小于上游耗时、$upstream_status 常为空。

根因:客户端(或它前面的 LB/CDN)在 nginx 还没拿到响应时就断了。常见三种:

  1. 前端 fetch 设了更短的超时(如 10s),比 nginx 的 60s 先到
  2. 负载均衡空闲超时小于 nginx 的处理时间
  3. 浏览器标签被关/页面跳转

修法:把最外层的超时对齐——建议 客户端超时 > LB 空闲超时 > nginx proxy_read_timeout > 上游超时。但这是顺序要求,不是固定倍数:长任务/流式场景应按该接口的实际耗时设置,而不是机械地逐层放大。任何一层反了,都会出现"用户看到失败、服务端日志却显示成功或 499"。

验证:在客户端侧记录请求耗时与取消原因;同时看 nginx 的 $request_time 是否与客户端放弃时刻吻合。

模式 4 — 413 与大文件上传

判据:报错来自 nginx(响应体是 nginx 的 HTML),而不是上游。

根因:client_max_body_size(默认 1m)。另外两个容易被忽略的点:

  • 前端框架/网关可能也有上限(如 Spring 的 max-request-size),只改 nginx 不够
  • 开了 proxy_request_buffering on(默认)时,nginx 会先把整个请求体落盘再转发;大文件会放大磁盘占用与延迟

修法:

location /upload/ {
    client_max_body_size 200m;
    proxy_request_buffering off;     # 流式转发,nginx 不再整包落盘
    proxy_pass http://app;
}

关于 Expect: 100-continue:很多客户端在上传超过某个阈值时会先发这个头,等 100 Continue 再传。是否出现、阈值多少取决于客户端与实现,不要写死数字——用 curl -v 观察实际请求头,再决定要不要 proxy_http_version 1.1 与相关超时配套。

验证:

curl -v -F file=@big.bin http://<host>/upload/ -o /dev/null
# 期望:HTTP/1.1 200 或 201;不再是 413

模式 5 — SSE/流式被缓冲

判据:Chrome DevTools 里响应是一次性到达;curl -N 直连上游是流式的,经 nginx 变成批量。

根因:

  1. proxy_buffering on(默认)→ nginx 攒够缓冲区才下发
  2. gzip on 对 text/event-stream 也会缓冲
  3. 上游发的 X-Accel-Buffering 被忽略,或上游根本没发
  4. proxy_read_timeout 太短,长连接被掐断

最小修改:

location /events/ {
    proxy_buffering off;
    proxy_cache off;
    gzip off;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_read_timeout 3600s;
    proxy_pass http://app;
}

上游侧最佳实践是同时发响应头 X-Accel-Buffering: no——这样即使 nginx 配置被回滚,流式也不至于坏。

验证:

curl -N http://<host>/events/ -H 'Accept: text/event-stream'
# 期望:事件逐条出现(每行之间有明显间隔),而不是最后一次性刷出

模式 6 — upstream keepalive 没生效

判据:ss -tan state time-wait | wc -l 很高;上游看到的连接数远大于并发请求数。

根因:keepalive 只写一半。完整三件套缺一不可:

upstream app {
    server 10.0.0.11:8080;
    keepalive 32;                 # 1) 连接池大小
}

location / {
    proxy_http_version 1.1;       # 2) 必须 1.1
    proxy_set_header Connection "";  # 3) 清空(默认会发 close)
    proxy_pass http://app;
}

少第 2 条或第 3 条,连接仍会每次新建——配置看起来"加了 keepalive",实际没生效。

验证:上游的 netstat/连接数在请求结束后不再持续增长;或在上游打印连接对象 ID,观察复用。

模式 7 — 尾斜杠与路径重写

判据:访问 /api/users 被 301 到 /api/users/;或路径前缀在转发后丢失/重复。

根因:proxy_pass 的 URI 语义。

写法 行为
proxy_pass http://app;(无 URI) 原样透传完整路径
proxy_pass http://app/;(有 /) 替换掉 location 匹配部分
proxy_pass http://app/v1/; 用 /v1/ 替换匹配部分

连带项:重定向时 nginx 默认用 server_name 与监听端口生成 Location,反代场景常需要:

absolute_redirect off;      # 发相对 Location
server_name_in_redirect off;
port_in_redirect off;

验证:curl -sv http://<host>/api/users 看 Location 是否是期望的相对路径或正确主机。

延伸阅读

  • references/log-fields-and-commands.md · references/subfilter-and-tls.md
  • references/error-handling.md · references/faq-antipatterns.md

错误处理约定

本技能把出错分成四类(输入错误 / 环境错误 / 证据不足 / 结论冲突),处置与重试策略不同,不要混着来;四类判据表与统一输出格式见 references/error-handling.md 第一、二节。

本技能常见错误码:

代码 现象 处置
E-ENV-01 改完配置 502 变多 回滚到上一版配置,nginx -s reload
E-ENV-02 reload 后旧进程不退 等连接自然结束或优雅升级(-s quit 后再起)
E-ENV-03 504 调大超时仍复现 对齐外层 LB/CDN 超时
E-ENV-04 413 改完仍失败 同步调上游的请求体限制
E-ENV-05 流式偶发中断 调大该 location 的读超时
E-ENV-06 上游证书 30 天内到期或已过期 换证书后 nginx -t && nginx -s reload;自签上游先在 proxy_ssl_trusted_certificate 里导入 CA

输入校验清单、重试与退出语义见 references/error-handling.md。

失败模式与恢复

失败现象 常见原因 检查方法 恢复动作 可否重试
改完配置 502 变多 include 顺序或 upstream 名不匹配 nginx -T 看最终生效块 回滚到上一版配置,nginx -s reload 可
reload 后旧进程不退 长连接未结束 pgrep -c nginx 看 worker 数 等连接自然结束或优雅升级(-s quit 后再起) 可
504 调大超时仍复现 调的是错 location / 被更外层超时截断 看 $upstream_response_time 是否真的到点了 对齐外层 LB/CDN 超时 可
413 改完仍失败 上游框架也有上限 直连上游上传复测 同步调上游的请求体限制 可
流式偶发中断 proxy_read_timeout 小于事件间隔 看中断时刻与配置值 调大该 location 的读超时 可
上游证书校验失败 自签或 SNI 未发 openssl s_client 复测 导入 CA 或显式配置 proxy_ssl_* 不可重试(需改配置)

失败时优先回滚到 nginx -t 通过的上一个版本:网关配置是全站共享的,宁可回退也不要在线上试错。

完整走查(端到端样例)

场景:用户反馈"上传 60MB 视频总是失败,其它页面正常"。

输入:

curl -sv -F file=@demo-60mb.mp4 https://app.example.com/upload/ -o /dev/null
tail -n 50 /var/log/nginx/error.log

中间输出(示例):

> POST /upload/ HTTP/1.1
< HTTP/1.1 413 Request Entity Too Large
< Server: nginx/1.24.0
< Content-Type: text/html
2026-10-31 10:12:03 [error] 412#412: *991 client intended to send too large body: 62914560 bytes,
  client: 10.2.0.5, server: app.example.com, request: "POST /upload/ HTTP/1.1"

定位与修复:413 由 nginx 自己返回(响应头是 Server: nginx),且错误日志明确写了 client intended to send too large body → 是 client_max_body_size(默认 1m)拦的,不是应用层。改该 location:

location /upload/ {
    client_max_body_size 200m;
    proxy_request_buffering off;
    proxy_read_timeout 300s;
    proxy_pass http://app;
}

修复后复测:

nginx -t && nginx -s reload
curl -sv -F file=@demo-60mb.mp4 https://app.example.com/upload/ -o /dev/null
# < HTTP/1.1 201 Created

同时确认应用侧也接受了(上游日志出现对应文件记录),避免"nginx 放行、应用拒绝"的假成功。

结论:这轮走查验证了判据的先后顺序——先看是谁返回的 413(响应头 + error.log 归属),再决定改 nginx 还是改上游;proxy_request_buffering off 与超时是配套项,不是可选项。

不适用场景

  • 纯应用层异常:应用返回 500 并带堆栈,nginx 只忠实转发——按应用日志排查。
  • Kubernetes Ingress:ingress-nginx 的注解(如 nginx.ingress.kubernetes.io/proxy-body-size)与原生指令语义不同,且受控制器版本影响。
  • CDN/WAF 侧:回源超时、请求体上限、拦截规则在 CDN 上另有一套,先确认响应头是谁加的(Server、Via、X-Cache)。
  • HTTP/3 与 QUIC 特有行为:需要单独的协议层排查。

反模式与常见问题

反模式与高频问答见 references/faq-antipatterns.md。结论先给:这些做法都会让问题更难排查,改法在对应小节。

常见问题

5 问
答案由本站依据条目字段整理
Nginx 与网关排障怎么安装?

在支持 Skills 的客户端里执行:skillhub install user_617dd917/nginx-gateway-troubleshoot-moran。安装方式为未标注。装完刷新技能列表或重开客户端。

Nginx 与网关排障支持哪些客户端?

资料没有标注宿主客户端,但只要客户端支持 Skills(Claude、Codex、Cursor 等),一般都能加载。

Nginx 与网关排障权限高吗,安全吗?

权限级别为未标注权限。安装前先看它会读取或写入哪些内容。

Nginx 与网关排障收费吗?

本站不代收费用,也没有标注具体价格。是否收费取决于技能本身和所用的模型或客户端,正式使用前按作者说明确认。

Nginx 与网关排障用什么许可证?

许可证标注为 未说明(许可证不明确)。商用或二次分发前请到仓库确认条款原文。

热门专题

按场景挑技能
全部专题 →

技能内容以作者仓库为准;分类、权限级别与许可证状态的中文说明为中文整理,最近核验 2026-11-06。