读完这篇,你不仅能搭一个能用的反向代理,还能看懂生产环境上千行的 nginx 配置为什么那样写。
一、开篇:反向代理到底解决了什么问题
你大概率遇到过这些场景:
- 后端服务只监听
127.0.0.1:8080,外网用户怎么访问? - 一台机器扛不住了,加了两台,前端路由怎么分?
- 前端调后端跨域被浏览器拦住,怎么优雅解决?
- WebSocket / SSE 长连接频繁断,Nginx 上该配什么?
- 某个接口被脚本疯狂刷,怎么在 Nginx 层拦住?
反向代理 就是这些问题的标准答案。它站在客户端和后端服务器之间,代替后端接收请求再转发,同时顺手把负载均衡、SSL 终结、缓存、限流、日志统一做了。
本文从最基础的 proxy_pass 讲起,一路深入到生产环境跑了三年的真实配置------里面会有你见过的和没见过的写法,每一段都有解释。
二、核心概念:一个请求的完整旅程
用户浏览器
│
▼
┌─────────────┐
│ Nginx │ ← 反向代理(对用户来说是服务器)
│ 18081端口 │
└──────┬──────┘
│ proxy_pass
▼
┌─────────────────────────────┐
│ upstream 后端集群 │
│ 172.16.130.43:8090 (wg) │
│ 172.16.130.44:8090 (wg) │
│ 172.16.130.48:8090 (警察) │
│ ... │
└─────────────────────────────┘
Nginx 在这中间做了什么?
- 接收请求 --- 监听端口,解析 HTTP 协议
- 路由决策 --- 根据
location匹配规则,决定把请求发给哪个upstream - 请求改写 --- 修改 URI(rewrite)、添加/修改请求头(proxy_set_header)
- 负载均衡 --- 从 upstream 中选一台健康的机器
- 转发 & 等待 --- 建立连接、发送请求、等待响应
- 响应返回 --- 拿到后端响应,按需修改响应头,返回给客户端
以上六步,每一步在生产环境都有坑。我们一步步看。
三、基础配置:从 proxy_pass 开始
1. 最简反向代理
nginx
server {
listen 18081;
server_name _;
location /api {
proxy_pass http://172.16.130.43:8090;
}
}
请求 http://nginx:18081/api/ykz/login → 转发到 http://172.16.130.43:8090/api/ykz/login
但这还不够------后端服务看到的来源 IP 永远是 Nginx 的 IP。需要 IP 透传。
2. IP 透传三件套
nginx
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
| 头 | 作用 | 不配的后果 |
|---|---|---|
X-Real-IP |
真实客户端 IP | 后端日志全是 Nginx IP |
X-Forwarded-For |
代理链完整 IP | 多层代理时丢失来源 |
Host |
原始请求域名 | 后端做域名路由时失效 |
nginx.conf 里 log_format 通常第一个字段就是 $http_x_real_ip,说明日志体系强依赖这个头。丢了它,全链路追踪就断了。
3. location 匹配优先级
Nginx 的 location 匹配是有严格顺序的,不是你写哪行就先用哪行:
| 优先级 | 语法 | 含义 | 生产示例 |
|---|---|---|---|
| 最高 | = /path |
精确匹配 | location = /nginx_status |
| 高 | ^~ /prefix |
前缀匹配(优先) | location ^~ /api/bigScreen/queryBuildingLocation |
| 中 | ~ 正则 |
大小写敏感正则 | `location ~ ^/(app |
| 低 | ~* 正则 |
大小写不敏感正则 | `location ~* .(?:htm |
| 最低 | /prefix |
普通前缀匹配 | location /api |
生产案例解读:
nginx
# 高优先级前缀匹配:精确拦截特定接口做限流
location ^~ /api/bigScreen/queryBuildingLocation {
limit_req zone=allips6 burst=120 nodelay;
proxy_pass http://houseFormPolice;
}
# 正则匹配:处理多路径前缀(app/ 和 bigscreen/ 都要剥离后转发)
location ~ ^/(app/|bigscreen/)?event/insert1 {
proxy_pass http://172.16.130.56:8090;
rewrite "^/(app/|bigscreen/)?(.*)$" /$2 break;
}
核心原则 :能用 ^~ 就不要用 ~。正则每次请求都要编译执行,^~ 是纯字符串前缀匹配,性能好得多。
4. 请求头那些事
nginx
# 允许带下划线的自定义头(如 my_api_key)
underscores_in_headers on;
# 隐藏 Nginx 版本号(安全基线)
server_tokens off;
# 自定义请求头覆盖
proxy_set_header X-Forwarded-For ""; # 清空上游传过来的伪造头
proxy_set_header Host "23.210.227.114"; # 强制指定 Host(绕过 WAF 拦截)
生产案例 :配置里 underscores_in_headers on 配合 map $http_x_real_ip------真实来源 IP 通过下划线头 X-Real-IP 传递,不开这个选项的话这个头会被 Nginx 直接丢弃。
四、负载均衡实战
1. 四种分配策略
nginx
upstream wg {
# 策略1:加权轮询(默认,也是最常用的)------5台机器均匀分担
server 172.16.130.43:8090 weight=5 max_fails=5 fail_timeout=30s;
server 172.16.130.44:8090 weight=5 max_fails=5 fail_timeout=30s;
server 172.16.130.45:8090 weight=5 max_fails=5 fail_timeout=30s;
server 172.16.130.46:8090 weight=5 max_fails=5 fail_timeout=30s;
server 172.16.130.47:8090 weight=5 max_fails=5 fail_timeout=30s;
}
upstream userlogin {
# 策略2:同样加权轮询,但只有2台------登录接口需要会话保持的话要考虑 ip_hash
server 172.16.130.30:8090 weight=5 max_fails=3 fail_timeout=5s;
server 172.16.130.31:8090 weight=5 max_fails=3 fail_timeout=5s;
}
| 策略 | 指令 | 适用场景 |
|---|---|---|
| 加权轮询(默认) | weight=N |
后端性能不均,通用场景 |
| IP Hash | ip_hash; |
需要会话保持(如登录态) |
| 最少连接 | least_conn; |
长连接服务(WebSocket/SSE) |
| 随机 | random; |
大规模集群,避免热点 |
2. 健康检查------生产级别的分敏感度策略
生产配置里有一个非常值得学习的模式:不同 upstream 用不同的 fail_timeout。
nginx
# 核心业务(wg):5次失败才摘除,摘除 30 秒------容错性高
upstream wg {
server 172.16.130.43:8090 max_fails=5 fail_timeout=30s;
}
# 非核心但需要快速响应的(bigscreen):3次失败即摘除,只摘 5 秒
upstream bigscreen {
server 172.16.130.8:8090 max_fails=3 fail_timeout=5s;
}
设计思路:
- 核心业务
fail_timeout=30s:给故障恢复留足时间,避免频繁摘除/恢复引起的抖动 - 大屏接口
fail_timeout=5s:大屏是实时展示,点状的短暂故障可以容忍,5秒后立刻重试即可
建议 :给 userlogin 这样的登录 upstream 加上 ip_hash,避免用户登录后请求落到不同机器导致 session 丢失:
nginx
upstream userlogin {
ip_hash;
server 172.16.130.30:8090 max_fails=3 fail_timeout=5s;
server 172.16.130.31:8090 max_fails=3 fail_timeout=5s;
}
3. rewrite 前缀剥离:break vs last
配置里大量使用 rewrite 做路径前缀剥离,这是 Nginx 反向代理最常见的模式之一:
nginx
# 模式:URL 前缀剥离
# 请求 /bigscreen/api/ykz → 转发到 bigscreen upstream 的 /api/ykz
location /bigscreen/api {
proxy_pass http://bigscreen;
rewrite "^/bigscreen/(.*)$" /$1 break;
}
| Flag | 行为 | 什么时候用 |
|---|---|---|
break |
停止当前 location 的后续 rewrite,继续处理 | 剥离前缀后必须用 break |
last |
停止当前 location,用新 URI 重新走一轮 location 匹配 | 需要换一个 location 处理时 |
redirect |
返回 302 重定向给客户端 | 需要客户端重新发请求时 |
常见坑 :break 和 last 搞反了------用 last 做前缀剥离,结果新 URI 匹配到了别的 location,请求被发到了错误的 upstream。
一个需要 last 的生产案例:
nginx
# 定义 map 匹配来自23.210.255.100得接口
map $http_x_real_ip $yitu_proxy {
default "";
"23.210.255.100" "172.16.130.73:18082";
}
server {
# 翼图 IP 过来的请求,先改写 URI 然后换到 internal location 处理
if ($yitu_proxy != "") {
rewrite ^/(.*)$ /__yitu_proxy__/$1 last;
}
# internal location:外部无法直接访问,只有 rewrite 进来的才会走到这里
location /__yitu_proxy__/ {
internal;
proxy_pass http://$yitu_proxy;
rewrite "^/__yitu_proxy__/(.*)$" /$1 break;
}
}
这里用 last 是因为改写了 URI 后需要换一个 location 处理;内部 location 里的 break 则是正常的剥离前缀。
4. 接口限流:保护后端的最后一道防线
生产配置里已经有一套成熟的限流体系:
nginx
# 定义限流规则
limit_req_zone $binary_remote_addr zone=allips:10m rate=50r/m;
location ^~ /api/bigScreen/queryBuildingLocation {
limit_req zone=allips burst=120 nodelay;
proxy_pass http://houseFormPolice;
}
三个参数的含义:
| 参数 | 含义 | 建议 |
|---|---|---|
rate=50r/m |
每分钟最多50 个请求(约 0.13 req/s) | 根据业务需求 |
burst=120 |
允许瞬时突发 120 个请求排队 | 根据业务峰值设,大屏接口设高 |
nodelay |
排队中的请求立即处理(不延迟) | 用户体验好,但瞬时压力大 |
目的:防止突发流量或异常请求瞬间耗尽服务器资源,导致服务宕机。限流相当于给系统装上"安全阀",确保在高压下系统仍然能正常运行,而不是彻底崩溃。
提示 :
$binary_remote_addr比$remote_addr省内存(4字节 vs 7-15字节),大规模限流场景必用。
五、生产最佳实践
1. 全局性能优化
nginx.conf 里有几行容易被忽略但极其重要:
nginx
worker_processes auto; # 自动匹配 CPU 核心数
worker_cpu_affinity auto; # 每个 worker 绑定一个 CPU 核心
worker_connections 8192; # 每个 worker 最大连接数
events {
use epoll; # Linux 下最高效的事件模型
multi_accept on; # 一次接受所有新连接(而不是一个一个来)
}
http {
sendfile on; # 零拷贝发送静态文件
tcp_nopush on; # 配合 sendfile,攒够一个包再发
tcp_nodelay on; # 对 keepalive 连接,有数据立即发(降低延迟)
}
这三兄弟 sendfile + tcp_nopush + tcp_nodelay 的组合很多人配错:
tcp_nopush on只在sendfile on时生效------它会等数据包填满再发,减少网络包数量tcp_nodelay on跟它不矛盾------只对 keepalive 连接生效,让小块数据立即发送
2. 日志即监控
生产 log_format 是含金量极高的一行:
nginx
log_format main '$http_x_real_ip | $remote_addr | $remote_user | [$time_iso8601] '
'| "$request" | $status | $body_bytes_sent | $request_time '
'| $upstream_addr | $upstream_status | $upstream_response_time '
'| "$http_referer" | "$http_user_agent" | "$http_x_forwarded_for"';
每个字段都是排坑利器:
| 字段 | 排坑场景 |
|---|---|
$request_time |
客户端感知的响应时间(含网络) |
$upstream_response_time |
后端真实处理时间------排坑核心指标 |
$upstream_addr |
请求落到了哪台机器------定位单机故障 |
$upstream_status |
后端返回的状态码------502/504 一眼看到 |
$http_x_real_ip |
真实客户端 IP(经过多层代理透传) |
经验 :如果 $request_time 很大但 $upstream_response_time 很小,问题在网络层(比如跨机房);如果两者都大,问题在后端。
3. 超时控制------按业务设,不要一刀切
nginx
# 全局默认(http 块)
proxy_connect_timeout 30; # 连接后端超时 30s
proxy_read_timeout 200; # 等待后端响应超时 200s
proxy_send_timeout 200; # 发送请求给后端超时 200s
# 特定接口覆盖(server/location 块)
location /chat/ {
proxy_read_timeout 86400s; # AI 对话:等 24 小时(SSE 长连接)
}
location /event/getEventByList {
proxy_read_timeout 60s; # 普通查询:60s 足够
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
}
经验教训 :不要全局设一个很大的 proxy_read_timeout。正常的 API 调 200s 已经是"后端可能挂了"的信号。只有 SSE / WebSocket / AI 推理这种场景才需要 86400s(24小时)。
4. Buffer 调优------两套策略
生产配置恰好展示了两种典型场景的 Buffer 设置:
策略 A:大 Buffer(常规 API / 大响应体)
nginx
proxy_buffer_size 1024k; # 响应头缓冲区
proxy_buffers 16 1024k; # 16个响应体缓冲区,每个 1MB
proxy_busy_buffers_size 2048k; # 忙碌时能发送的最大缓冲区
proxy_temp_file_write_size 2048k; # 写入临时文件的最大块大小
适用场景:后端返回较大 JSON、Excel 导出、图片/文件。允许 Nginx 缓存整个响应后再发给客户端,减少后端连接占用时间。
策略 B:关闭 Buffer(SSE / AI 流式 / MCP 长连接)
nginx
location /tuowei/ai-event-api/analysis/chat {
proxy_buffering off; # 核心:禁用缓冲,边收边发
proxy_cache off; # 关闭缓存
proxy_http_version 1.1; # HTTP/1.1 才支持分块传输
proxy_set_header Connection ''; # 维持长连接,不清空 Connection 头
chunked_transfer_encoding on; # 分块传输编码
proxy_request_buffering off; # 关闭请求缓冲
gzip off; # 不要压缩流式内容
# 禁用客户端/中间代理缓冲
add_header Cache-Control "no-cache, no-transform" always;
add_header X-Accel-Buffering "no" always;
# 超长超时(AI 推理可能很久)
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
适用场景:ChatGPT 式流式输出、SSE 推送、MCP 协议长连接。核心就是 proxy_buffering off------它让 Nginx 不缓存后端响应,收到一个 chunk 就立刻发给客户端。
生产案例: MCP 配置也是这样:
nginx
location ^~ /jczz_mcp {
proxy_pass http://172.16.130.152:8000;
proxy_buffering off;
proxy_cache off;
proxy_http_version 1.1;
chunked_transfer_encoding on;
proxy_set_header Connection '';
proxy_read_timeout 86400s;
}
5. WebSocket / SSE 代理
nginx
location /api {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_pass http://wg;
}
三行关键配置:
proxy_http_version 1.1--- HTTP/1.1 才支持协议升级Upgrade $http_upgrade--- 透传客户端的协议升级请求Connection "Upgrade"--- 告诉后端:这个连接要升级
这也是配置里 /api、/bigscreen/api 都在用的模式------因为后端可能同时处理 HTTP API 和 WebSocket,不主动升级就只当 HTTP 走。
6. Gzip 压缩------省带宽的正确姿势
nginx
gzip on;
gzip_comp_level 5; # 压缩级别 5(性价比最佳,不要设 9)
gzip_min_length 1024; # 小于 1KB 不压缩(越压越大)
gzip_proxied any; # 对所有代理请求生效(包括后端返回的)
gzip_vary on; # 告诉缓存服务器"我可能不压缩,别把压缩版发给不支持的用户"
gzip_types text/plain text/css application/javascript application/json
application/xml image/svg+xml application/octet-stream;
注意 gzip_types 里不要加图片和视频------它们本身就是压缩格式,Gzip 只会让它们更大。
7. 接口下线的正确姿势
配置里有从"正常代理 → 下线 → 拒绝访问"的完整生命周期:
nginx
# 阶段1:正常代理
location ^~ /dubbo/api/ {
proxy_pass http://23.211.10.6:32080;
}
# 阶段2:下线但仍可被调试
# location ^~ /dubbo/api/ {
# proxy_pass http://23.211.10.6:32080;
# }
# 阶段3:返回 404(彻底下线)
location ^~ /dubbo/api/ {
return 404;
}
# 阶段4:返回 401(需要鉴权才能访问)
location ^~ /contradiction/insertConfig {
return 401;
}
经验 :不要直接删 location。先注释掉 proxy_pass 换成 return 404,观察几天日志有没有人还在调,确认无影响后再删除配置。
8. stub_status 监控
nginx
location /nginx_status {
stub_status on;
access_log off;
allow 172.16.130.2; # 仅允许内网监控机器访问
deny all;
}
访问后返回:
Active connections: 291
server accepts handled requests
16630948 16630948 31070465
Reading: 6 Writing: 179 Waiting: 106
| 字段 | 含义 |
|---|---|
Active connections |
当前活跃连接数 |
accepts |
历史总连接数 |
handled |
成功处理的连接数(accepts - handled = 连接被拒绝数) |
requests |
总请求数 |
Reading / Writing / Waiting |
正在读请求头 / 正在写响应 / 空闲 keepalive |
9. 生产级完整配置模板
整合以上所有实践,一个可直接放到 conf.d/ 下用的模板:
nginx
# ============================================
# 全局设置(放在 nginx.conf 的 http 块)
# ============================================
worker_processes auto;
worker_cpu_affinity auto;
worker_connections 8192;
events {
use epoll;
multi_accept on;
}
http {
server_tokens off;
underscores_in_headers on;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# 全局超时
proxy_connect_timeout 30;
proxy_read_timeout 200;
proxy_send_timeout 200;
# 全局日志格式
log_format main '$http_x_real_ip | $remote_addr | [$time_iso8601] '
'| "$request" | $status | $request_time '
'| $upstream_addr | $upstream_response_time';
# 全局 Buffer(大响应体)
proxy_buffer_size 1024k;
proxy_buffers 16 1024k;
proxy_busy_buffers_size 2048k;
# Gzip
gzip on;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_proxied any;
gzip_vary on;
gzip_types text/plain text/css application/javascript application/json;
# ========================================
# upstream 定义(按业务分池)
# ========================================
upstream wg {
server 172.16.130.43:8090 weight=5 max_fails=5 fail_timeout=30s;
server 172.16.130.44:8090 weight=5 max_fails=5 fail_timeout=30s;
server 172.16.130.45:8090 weight=5 max_fails=5 fail_timeout=30s;
}
upstream userlogin {
ip_hash; # 登录接口必须会话保持
server 172.16.130.30:8090 weight=5 max_fails=3 fail_timeout=5s;
server 172.16.130.31:8090 weight=5 max_fails=3 fail_timeout=5s;
}
# ========================================
# 限流规则
# ========================================
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=120r/m;
limit_req_zone $binary_remote_addr zone=token_limit:10m rate=8r/m;
# ========================================
# server 块
# ========================================
include conf.d/*.conf;
}
nginx
# conf.d/app.conf ------ 你的实际业务配置
server {
listen 18081;
# IP 透传
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
# CORS(按需)
add_header Access-Control-Allow-Origin 'https://your-frontend.com';
# 静态文件
location / {
root /data/web/dist;
if ($request_filename ~* .*\.(?:htm|html)$) {
add_header Cache-Control no-store;
}
}
# 常规 API → 负载均衡
location /api {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_pass http://wg;
}
# 大屏 API(路径前缀剥离)
location /bigscreen/api {
proxy_pass http://bigscreen;
rewrite "^/bigscreen/(.*)$" /$1 break;
}
# 登录接口
location ^~ /api/ykz {
proxy_pass http://userlogin;
}
# AI 流式接口(关闭 Buffer)
location /chat/ {
proxy_pass http://ai-backend:7889;
proxy_buffering off;
proxy_cache off;
proxy_http_version 1.1;
proxy_set_header Connection '';
chunked_transfer_encoding on;
gzip off;
proxy_read_timeout 86400s;
add_header X-Accel-Buffering "no" always;
}
# 监控(仅内网)
location /nginx_status {
stub_status on;
access_log off;
allow 172.16.130.0/24;
deny all;
}
}
六、常见排坑指南
1. proxy_pass 末尾斜杠的坑
nginx
# 请求 /api/user/login
location /api/ {
proxy_pass http://backend/; # → http://backend/user/login (√ 期望行为)
#proxy_pass http://backend; # → http://backend/api/user/login (× 带了前缀)
#proxy_pass http://backend/v2/; # → http://backend/v2/user/login (√ 换前缀)
}
记住 :proxy_pass 末尾有 / → 剥离 location 前缀;没有 / → 保留完整 URI。
2. 502 Bad Gateway 排查三板斧
bash
# 1. 检查后端是否存活
curl -v http://172.16.130.43:8090/api/health
# 2. 检查 Nginx 错误日志
tail -f /data/logs/error.log | grep "upstream"
# 3. 看日志里的 upstream_addr 和 upstream_status
# 如果 upstream_addr 不对,说明 location 匹配到了错误的 upstream
tail -100 /data/logs/access.log | awk '{print $NF}'
日志里 $upstream_addr 和 $upstream_status 就是这个用途------502 时直接 grep 日志,一秒定位是哪个后端挂了。
3. WebSocket 连接秒断
症状:WebSocket 连接建立后立即断开,客户端报 1006。
根因:漏配了这三行:
nginx
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
配置里的 /api、/bigscreen/api、/app/api 都配了这三行------说明有 WebSocket 场景,是吃过这个坑的。
4. SSE 流式输出阻塞
症状:AI 对话等了很久才一次性吐出所有文字。
根因:没关 Buffer。Nginx 默认会缓存后端响应,等全部收完再发给客户端。
解法:按 5章第4 节的策略 B 来------proxy_buffering off 是核心,但必须配合 proxy_cache off、gzip off、chunked_transfer_encoding on。
5. 上游 keepalive 连接池耗尽
nginx
upstream wg {
server 172.16.130.43:8090;
keepalive 32; # 保持 32 个到每个后端的空闲连接
}
location /api {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://wg;
}
如果不配 keepalive,Nginx 每次请求都要建新的 TCP 连接------高并发下就是大量的 TIME_WAIT。
6. rewrite 的 if 地狱
配置里有一个反例值得警惕:
nginx
if ($yitu_proxy != "") {
rewrite ^/(.*)$ /__yitu_proxy__/$1 last;
}
if 在 location 外使用是 当前配置唯一合法的场景 (基于 $变量 判断)。但如果写成这样就是坑:
nginx
# 不推荐:if 嵌套 location
location / {
if ($args ~ "debug=1") {
proxy_pass http://debug-backend; # 可能会被忽略
}
proxy_pass http://normal-backend;
}
在 location 内用 if 做 proxy_pass 分支是 Nginx 头号坑,行为不可预测。正确做法是用 map:
nginx
# 定义 map 匹配来自23.210.255.100得接口
map $http_x_real_ip $yitu_proxy {
default "";
"23.210.255.100" "172.16.130.73:18082";
}
server {
# 翼图 IP 过来的请求,先改写 URI 然后换到 internal location 处理
if ($yitu_proxy != "") {
rewrite ^/(.*)$ /__yitu_proxy__/$1 last;
}
# internal location:外部无法直接访问,只有 rewrite 进来的才会走到这里
location /__yitu_proxy__/ {
internal;
proxy_pass http://$yitu_proxy;
rewrite "^/__yitu_proxy__/(.*)$" /$1 break;
}
}
这恰好是配置里 map $http_x_real_ip $yitu_proxy 的用法------根据请求头来源 IP 动态选择后端,优雅且可靠。
七、总结 + 落地清单
反向代理从"能跑"到"生产可用",中间差的不只是一个 proxy_pass:
| 层次 | 要做什么 | 你配置里的解法 |
|---|---|---|
| 基础 | proxy_pass + IP 透传 | X-Real-IP + X-Forwarded-For |
| 路由 | location 匹配 + rewrite 剥离 | ^~ 优先 + break 剥离前缀 |
| 高可用 | 负载均衡 + 健康检查 | max_fails + fail_timeout 分敏感度 |
| 保护 | 限流 + 超时 | limit_req_zone 多梯级 + 按接口设超时 |
| 性能 | Buffer 调优 + Gzip + keepalive | 大 Buffer / 零 Buffer 两套策略 |
| 流式 | SSE / WebSocket 代理 | proxy_buffering off + HTTP/1.1 |
| 监控 | 日志 + stub_status | $upstream_response_time + $upstream_addr |
| 安全 | server_tokens off + 接口下线 | return 404 / return 401 标记废弃 |
| 技巧 | map 动态路由 + internal location | 条件代理隔离不同来源 |
落地清单(逐条对照已有配置):
worker_cpu_affinity auto--- CPU 亲和性use epoll+multi_accept on--- 事件模型优化sendfile + tcp_nopush + tcp_nodelay--- 网络优化三件套log_format含$upstream_response_time--- 后端耗时监控max_fails分梯度 --- 健康检查分敏感度proxy_buffering off用于 AI/SSE --- 流式场景正确配置limit_req_zone多梯级 --- 接口限流分级return 404标记废弃接口 --- 接口生命周期管理stub_status内网监控 --- 运行状态可视化keepalive连接池 --- 建议在wgupstream 里加上userlogin加ip_hash--- 防止登录态漂移
本文所有生产案例均来自真实运行的 Nginx 配置(18081 端口,日均千万级请求)。配置会过时,思路不会。