Nginx 反向代理生产配置:upstream 与缓存限流

Nginx 反向代理是生产环境最常见的流量入口:它把外部请求转发给后端应用服务器,再把响应回传给客户端。官方文档明确指出,代理经常被用来在多台服务器之间分发负载,或把请求交给非 HTTP 协议的应用服务器处理。相比Nginx 站点配置,反向代理更强调"转发"这一层,是流量治理的前置关口。

一、upstream:定义后端服务器组

upstream 定义一个后端服务器组,proxy_pass 指向该组时,Nginx 会按负载均衡算法把请求分发给组内服务器。

upstream backend_app {
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
    server 127.0.0.1:3003 weight=2;
}

server {
    listen 80;
    server_name api.example.com;

    location / {
        proxy_pass http://backend_app;
    }
}

默认算法是轮询(round-robin),可以通过 weight 调整权重——上面 3003weight=2 意味着它承接约两倍的请求。需要会话保持的应用可以用 ip_hash 让同一客户端始终落在同一后端;后端处理能力差异明显时,least_conn(最少连接)往往比轮询更合理。proxy_pass 后面的地址如果不带 URI,Nginx 会把完整的原始请求 URI 透传给后端——这是最常见的用法,务必不要随手加 /

二、透传请求头

默认情况下 Nginx 会把 Host 头改写为 $proxy_host,后端拿到的就不是真实域名了。要还原真实域名与客户端信息,需要显式设置:

location / {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://backend_app;
}

X-Forwarded-For 是日志审计与安全分析的基础:没有它,后端只能看到 Nginx 自身的 IP,无法区分真实访客,限流、封禁、归属分析全都无从谈起。注意 $proxy_add_x_forwarded_for 会在原有值后面追加本次连接地址,多级代理场景下每一层都应这样追加,才能保留完整链路。

三、proxy_cache:反向代理缓存

Nginx 可以在反向代理层做内容缓存,把热点响应留在内存与磁盘里,显著减轻后端压力。用 proxy_cache_path 定义缓存目录与参数,在 location 中启用:

proxy_cache_path /var/cache/nginx levels=1:2
                 keys_zone=mycache:10m max_size=1g
                 inactive=60m use_temp_path=off;

location / {
    proxy_cache mycache;
    proxy_cache_valid 200 302 10m;
    proxy_cache_valid 404 1m;
    add_header X-Cache-Status $upstream_cache_status;
    proxy_pass http://backend_app;
}

$upstream_cache_status 会返回 HIT/MISS/BYPASS/EXPIRED 等状态,配合 X-Cache-Status 响应头可以快速验证缓存是否生效、命中率是多少。开启缓存前要想清楚边界:只适合幂等的 GET 请求,涉及登录态、购物车、个性化内容的接口要显式 proxy_cache_bypass 或干脆不缓存。更细的缓存键设计可参考缓存键策略

四、limit_req:限流防刷

limit_req_zone 定义限流速率,limit_req 在 location 中应用。典型的防刷配置如下:

limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;

location /api/ {
    limit_req zone=api_limit burst=20 nodelay;
    proxy_pass http://backend_app;
}

rate=10r/s 表示平均每秒放行 10 个请求;burst=20 允许突发时多放行 20 个并排队处理,nodelay 则让这些突发请求立即放行但照常计数。两者组合,既不会误伤正常访问高峰,又能把脚本刷量挡在门外。若想让被限流的客户端得到标准化的响应,可以加一行 limit_req_status 429;

五、TLS 终结

反向代理层是终结 TLS 的理想位置。证书可由 Let's Encrypt + Certbot 自动签发与续期(或参考一键申请脚本):

server {
    listen 443 ssl http2;
    server_name api.example.com;

    ssl_certificate     /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;

    location / {
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://backend_app;
    }
}

server {
    listen 80;
    server_name api.example.com;
    return 301 https://$host$request_uri;
}

在 Nginx 层终结 TLS 后,内网后端可以用明文 HTTP 通信,证书只在一处集中管理,大大降低内网证书维护成本。X-Forwarded-Proto 对后端判断"是否 HTTPS"很关键,否则后端可能拼出错误的回调地址。完整 TLS 配置可参考CDN SSL/TLS 配置最佳实践;若已启用 HTTP/3,可进一步参考HTTP/3 加速指南

六、缓冲区与超时

生产环境通常需要调整代理缓冲,避免慢客户端拖累后端:

location / {
    proxy_buffering on;
    proxy_buffers 16 4k;
    proxy_buffer_size 8k;
    proxy_connect_timeout 5s;
    proxy_read_timeout 60s;
    proxy_send_timeout 60s;
    proxy_pass http://backend_app;
}

默认 Nginx 会缓冲后端响应,等整体接收后再发给客户端,这对慢速客户端是必要的优化;但对流式接口(如 SSE、实时推送),应关闭缓冲以保证首字节尽快到达。超时也要分层理解:proxy_connect_timeout 控制与后端建连的时间,proxy_read_timeout 控制两次读操作之间的间隔,并非整个请求的总时长。

七、结合容器部署

当后端跑在 Docker Compose 里时,Nginx 通常作为宿主机入口代理容器端口,可参考Docker Compose 生产部署。更底层的 Nginx 性能调优见Nginx 优化完全指南,LNMP 集成见LNMP 环境搭建

常见排查场景

生产中最常见的三类"转发异常",通常都能在 Nginx 层快速定位:

  1. 后端日志里客户端 IP 全是 127.0.0.1:几乎可以断定是没配 X-Forwarded-For,后端拿到的是代理地址。
  2. 缓存似乎没生效:用 curl -I 查看响应头里的 X-Cache-Status,若一直是 MISS,检查 proxy_cache_key 是否因为带了 $args 而每请求都不同。
  3. 504 Gateway Timeout:多为 proxy_read_timeout 过短,后端处理超过设定值就断连,调大超时或优化后端查询即可。

16IDC 观察

反向代理不是"转发一下"那么简单,它是流量治理的前置层:负载均衡让多实例分担压力,缓存让热点请求不打到后端,限流让异常流量被挡在门外,TLS 终结让证书管理集中化。把这四件事在 Nginx 层做好,后端应用就能专注业务逻辑,架构的健壮性会明显提升。

原文来源:https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/
参考:Nginx 官方内容缓存指南 https://docs.nginx.com/nginx/admin-guide/content-cache/content-caching/