本节摘要:反向代理指 Nginx 代表后端服务器接收客户端请求并转发响应。核心是 proxy_pass 及其配套的头部改写、超时与故障页面配置——代理的第一原则是"忠实转达",常见故障几乎都源于转达失真。
upstream app_backend { server 10.0.1.11:8080; } server { listen 80; server_name shop.example.com; location / { proxy_pass http://app_backend; } }
三行配置就能转发,但直接上线会立刻遇到两类问题:后端日志里客户端 IP 全是 Nginx 机器的 IP;后端应用收到的 Host 是 upstream 名字而不是域名。都是头部转达失真。
location / { proxy_pass http://app_backend; proxy_set_header Host $host; # 保留原始域名 proxy_set_header X-Real-IP $remote_addr; # 直连客户端 IP proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 链路追加 proxy_set_header X-Forwarded-Proto $scheme; # 原始协议 }
X-Forwarded-For 是追加语义:多层代理时每层把自己的下游 IP 加到末尾,后端取第一个才是真实客户端。应用侧(如 Spring 的 ForwardedHeaderFilter、Express 的 trust proxy)要显式开启信任,否则头部照样没人读。

⚠️ X-Forwarded-For 可被客户端伪造首段,风控取 IP 时应使用直连层写入的 X-Real-IP 或可信代理链推导。
proxy_connect_timeout 3s; proxy_send_timeout 10s; proxy_read_timeout 30s; # 等后端响应的最长时间 proxy_intercept_errors on; # 后端错误码由本机页面接管 error_page 502 503 504 /50x.html; location = /50x.html { root /data/www/error; internal; }
proxy_read_timeout 必须大于后端最慢接口的耗时,否则慢接口会被掐断成 504;反过来又不能无限放宽,否则后端假死时连接堆积。30s 是多数业务的安全线,特殊慢接口单独在 location 覆盖。
一是 proxy_pass 的转发目标带不带斜杠,决定 location 前缀是否从 URI 里剥掉:
location /api/ { proxy_pass http://app/; # /api/user → 后端收到 /user } location /api/ { proxy_pass http://app; # /api/user → 后端收到 /api/user }
二是 upstream 里写域名时,DNS 只在启动时解析一次,后端换 IP 不重启不生效;动态解析要用变量形式配合 resolver。
proxy_pass 默认每个请求向后端新建一条 TCP 连接,用完即关。高 QPS 下这表现为:后端机器上大量 TIME_WAIT 状态的连接、Nginx 出站端口被快速消耗、每请求多付一次建连往返。打开上游 keepalive 是代理上线的标准动作:
upstream app_backend { server 10.0.1.11:8080; keepalive 64; # 每 worker 的空闲连接池大小 keepalive_requests 1000; # 单连接复用上限 keepalive_timeout 60s; } server { location / { proxy_pass http://app_backend; proxy_http_version 1.1; # keepalive 必须 1.1 proxy_set_header Connection ""; # 清掉默认的 close 头 } }
三条缺一不可:不开 1.1、不清 Connection 头,连接池形同虚设。上线后验证同样简单,看后端机器的 TIME_WAIT 数量是否断崖式下降,Nginx 侧的出站端口消耗速率是否放缓。一次真实改造里,仅这一组配置让 P99 降了 15ms——省的全是建连往返。
代理上线初期最常见的报障是 504。排查按两步走。第一步看错误日志关键词区分两类:upstream timed out 是等响应超时,connect() failed 是连不上。第二步分别处理。前者的典型成因是 proxy_read_timeout 短于后端最慢接口;后者的成因多半是后端监听地址写了回环而 Nginx 从另一网卡访问,或防火墙没放行网段。验证连通性的最小命令:
# 在 Nginx 机器上直接探后端 curl -w "connect=%{time_connect} total=%{time_total}\n" http://10.0.1.11:8080/healthz # connect 值高 → 网络或防火墙问题;total 高 → 后端本身慢
这个 time_connect 与 time_total 的拆分,是判断 504 该修网络还是修超时参数的最快证据。
代理职责的边界同样要明确:Nginx 是转发者,不是业务的第二个实现。凡是开始在 Nginx 里写复杂业务逻辑(多层 if 判断用户身份、用 rewrite 模拟路由表)的团队,都在重演同一个错误——把应用层复杂度搬进配置层,失去类型检查、测试与日志。健康的分工是:Nginx 只做与业务无关的流量治理(转发、超时、限流、缓存),一切需要理解业务语义的决策留给应用。这条边界守住了,Nginx 的配置才能长期保持第二章追求的那种可读秩序。