API 网关专栏 · 第 65 章

API 网关与 NGINX:分层、职责归属与迁移模式

2026年09月14日
API 网关与 NGINX:分层、职责归属与迁移模式

团队采用 API 网关后,NGINX 仍可能有价值,但不应成为一个无法解释的额外跳点。如果它继续负责已有的边缘 TLS、静态内容或分阶段迁移边界,就保留它;如果两层都在执行同样的路由、认证、重试和日志记录,就应替换或绕过其中一层。

关键问题不是 NGINX 属于“反向代理”、新产品属于“API 网关”。两者都能代理、终止 TLS、路由和执行策略。应先决定哪一层负责公开契约,再明确客户端身份、上游 TLS、超时、重试和回滚行为。

本文中的 NGINX 行为以 NGINX Open Source 1.30.5 为审查基准。使用这些示例前,应固定已部署的软件包或源码构建版本,并核对已启用模块;持续更新的文档页面不能替代版本契约。

核心要点

  • 有意识地选择三种模式之一:NGINX 位于网关之前、API 网关成为唯一边缘,或使用临时迁移链路。
  • 在信任直接对等端并按规则解析地址链之前,把转发头视为不可信输入。
  • NGINX real_ip_recursive 默认为 off;切换它会改变哪个地址成为 $remote_addr。
  • 使用 https:// 上游不代表会验证证书;proxy_ssl_verify 默认为 off。
  • 按方法、尝试次数、时间以及下游响应是否已经开始来限制重试。

判断两层是否值得付出成本

模式适用情况主要风险
NGINX → API 网关 → 服务NGINX 仍有独立的边缘、静态、TLS 或迁移职责重复策略、额外延迟和不一致的请求头信任
API 网关 → 服务网关可以完整负责公网边缘迁移时遗漏旧 NGINX 行为
NGINX → 新旧网关分流需要可快速回滚的受控分批迁移临时规则长期遗留或持续漂移

不要只评估请求延迟。第二层代理还会增加证书轮换、配置交付、日志关联、容量、补丁和事故职责。反过来,如果未盘点主机名规范化、重定向、请求体限制、缓冲和错误页就移除 NGINX,也会改变外部 API 契约。

模式 1:让 NGINX 保持精简的边缘职责

1flowchart LR
2    C[客户端] --> N[NGINX 边缘]
3    N -->|已验证的上游 TLS| G[API 网关]
4    G --> A[API 服务]

在该模式中,NGINX 负责公网套接字和一小组有意保留的边缘行为。API 网关负责消费者认证、路由策略、配额、转换和 API 可观测性,服务仍负责对象与工作流授权。

应限制 API 网关,使客户端不能绕过 NGINX 直接访问。可使用网络策略、防火墙规则、私有地址或已认证的源站连接。如果网关仍可从公网访问,攻击者就能绕过 NGINX 的限制和请求头规范化。

下面的 NGINX 摘录演示交接方式,但不是完整生产配置。证书路径、解析器行为、健康检查和准确网关主机名,都要按已安装 NGINX 版本调整并验证。

1upstream api_gateway {
2    server api-gateway.internal.example:9443;
3    keepalive 64;
4}
5
6server {
7    listen 443 ssl;
8    server_name api.example.com;
9
10    ssl_certificate     /etc/nginx/tls/public.crt;
11    ssl_certificate_key /etc/nginx/tls/public.key;
12
13    location / {
14        proxy_http_version 1.1;
15        proxy_set_header Connection "";
16        proxy_set_header Host $host;
17        proxy_set_header X-Forwarded-For $remote_addr;
18        proxy_set_header X-Forwarded-Proto https;
19
20        proxy_ssl_server_name on;
21        proxy_ssl_name api-gateway.internal.example;
22        proxy_ssl_verify on;
23        proxy_ssl_trusted_certificate /etc/nginx/tls/internal-ca.pem;
24
25        proxy_connect_timeout 2s;
26        proxy_read_timeout 30s;
27        proxy_next_upstream error timeout;
28        proxy_next_upstream_tries 2;
29
30        proxy_pass https://api_gateway;
31    }
32}

用解析后的 $remote_addr 替换 X-Forwarded-For,可以建立简单的单跳契约。如果 NGINX 自己位于另一个代理之后,应先配置并测试 Real IP 模块,否则 $remote_addr 表示的是直接相连的代理,而不是最终客户端。

建立客户端 IP 信任边界

官方 ngx_http_realip_module 参考把可信对等端与请求头中的地址分开处理。set_real_ip_from 列出有权提供替代地址的对等端,real_ip_header 则选择来源字段。从源码编译 NGINX 时,该模块默认不会构建,需通过 --with-http_realip_module 启用。发行版软件包可能不同,因此应使用 nginx -V 核对实际构建。以下行为也已对照 NGINX 1.30.5 Real IP 模块源码复核。

real_ip_recursive 是会改变行为的布尔参数,默认值为 off:

  • off(默认):当连接来自可信地址时,NGINX 使用所选请求头里的最后一个地址替换客户端地址。
  • on:NGINX 沿地址链查找,选择最后一个不受信任的地址。

两条路径都不能证明最终用户身份。结果是否可信,取决于可信对等端配置、它们重写请求头的方式和网络路径。应从可信与不可信连接发送伪造请求头进行测试,并在诊断日志中保留 $realip_remote_addr,让运维人员看到原始直连对等端。

不要把 $proxy_add_x_forwarded_for 当作安全控制。代理模块将其定义为传入的 X-Forwarded-For 加上 $remote_addr。如果原始请求头来自不可信调用方,直接转发完整地址链也会保留不可信数据。下文涉及的代理默认值与执行路径也已对照 NGINX 1.30.5 代理模块源码复核。

验证上游 TLS,而不只是加密

proxy_pass 中的 https:// 会加密连接,但文档中 proxy_ssl_verify 的默认值是 off:

  • off(默认):NGINX 不验证上游服务器证书。
  • on:NGINX 使用已配置的可信 CA 验证证书;上游需要时还要配置预期名称和 SNI。

上面的摘录设置了 proxy_ssl_verify on,提供信任包、启用 SNI,并固定预期网关名称。应测试过期证书、不可信签发方和名称不匹配。还要决定 NGINX 是否向网关出示客户端证书,以便网关认证边缘代理。只有加密、没有对等端验证,无法阻止错误端点冒充网关。

proxy_ssl_server_name 也是会改变行为的布尔参数,默认值为 off。设置为 off 时,NGINX 不会向被代理的 HTTPS 服务器发送 TLS SNI;设置为 on 时,会发送 proxy_ssl_name 选定的名称。启用 SNI 可以帮助使用虚拟主机的上游选择证书,但不会自动开启证书验证,因此仍需单独设置 proxy_ssl_verify on。

限制超时与重试

NGINX 文档将 proxy_next_upstream error timeout 定义为默认重试条件,同时指出一个重要交付边界:只有在尚未向客户端发送部分响应时,NGINX 才能切换上游。响应一旦开始交付,再换服务器也无法修复这次失败。

上述配置把尝试次数限制为两次,但方法是否安全是另一项决策。不要为了减少表面错误就开启非幂等操作重试。对于可重放写操作,应定义幂等键、服务端去重、总体截止时间,以及 NGINX、API 网关、服务网格和客户端共同遵守的最大尝试预算。

超时应形成逐层递减的预算。客户端截止时间要长于完整网关链路,每个内部超时又要为返回有效错误留出时间。proxy_read_timeout 是两次读取之间的空闲边界,并不天然等于请求总截止时间;流式路由需要单独设计。

模式 2:让 API 网关成为唯一边缘

当网关能够有意识地复现全部必要公网行为,而额外一层没有独立负责人时,就可以移除 NGINX。首先盘点:

  • DNS、证书、TLS 版本、密码套件和客户端证书行为;
  • 重定向、主机名规范化、路径重写和错误响应;
  • 请求头与请求体上限、缓冲、流式传输和 WebSocket 升级;
  • 客户端 IP 解析以及该值的所有消费者;
  • 上游池、主动或被动健康行为和连接复用;
  • 超时、重试、缓存、压缩和静态资源;
  • 访问日志、指标、关联字段和安全告警。

先把行为转成测试,再转换配置。语法相似的路由可能在 URI 规范化、请求头合并、正则语义或故障时机上表现不同。

模式 3:用 NGINX 作为迁移开关

NGINX 可以把小部分用户分流到新网关,同时让大多数流量继续走旧路径。优先使用稳定且不敏感的选择器,例如专用测试主机名,或从公网请求中删除后由运维控制的分组头。除非两个目的地共享兼容状态和幂等行为,否则不要对写操作做百分比分流。

回滚应是经过审查的配置变更,而不是紧急手工编辑。预先定义触发回滚的指标、连接排空时间、WebSocket 与流的处理方式,以及流量返回后如何协调配置状态。

避免重复策略

为每项策略写出一个权威负责人和必要的纵深防御例外:

策略推荐回答的归属问题
JWT 验证哪一层验证 issuer、audience、签名和时间声明?
限流哪个身份和共享计数器定义配额?
重试哪一层知道方法安全性和剩余截止时间?
WAF 或 Schema 检查检查了哪个表示形式和多大请求体?
重定向或重写哪一层负责外部 URI 契约?
访问日志哪个事件是接受、拒绝和上游交付的权威记录?

重复的防御性验证可以有合理理由,但密钥、故障行为和遥测必须一致。任何一层拒绝请求时,都应提供便于运维归因的原因,同时不向客户端暴露敏感策略细节。

验证与切流清单

  • 不可信网络无法直接访问网关与源站。
  • 可信与不可信转发头测试会得到预期 $remote_addr。
  • 使用 mTLS 时,网关会拒绝无效的 NGINX 客户端身份。
  • 设置 proxy_ssl_verify on 后,NGINX 会拒绝无效上游证书。
  • 除非存在已记录转换,否则 Host、scheme、path、query 和 body 保持不变。
  • 缺失、无效和有效凭据在预期层失败或通过。
  • 重试次数、上游尝试与总截止时间符合路由契约。
  • 大请求、流式、gRPC 和 WebSocket 路由遵循已测试的缓冲与超时路径。
  • 日志可以关联同一请求,但不会把调用方提供的 ID 当作可信身份。
  • 回滚会恢复流量与配置,而不只是 DNS。

总结

当每层都有独立且可测试的职责时,NGINX 与 API 网关可以共存。确保公网入口唯一,从可信对等端重建客户端身份,开启上游证书验证,并限制全链路重试。如果迁移后 NGINX 不再提供独立价值,移除重复跳点通常比维护两个部分重叠的网关更简单。

常见问题

NGINX 本身是 API 网关吗?

NGINX 提供大量网关基础能力。它是否满足团队的 API 管理要求,取决于准确版本、模块、配置工作流、策略生命周期和运维模型。

NGINX 应追加还是替换 X-Forwarded-For?

在信任边界,应先依据有文档的可信代理链确定客户端地址,再转发规范化的值或明确约定的地址链;不要默认保留调用方提交的值。

proxy_pass https://... 会验证上游证书吗?

不会自动验证。NGINX 文档中 proxy_ssl_verify 默认为 off。应启用验证,并配置可信 CA 与名称/SNI 行为。

后续步骤

继续比较 NGINX 与 Envoy 等网关运行时基础,设计安全的网关超时与重试,并定义可信客户端 IP 策略。

获取方案