
本文教你如何用 Nginx 在前置网关上完成反向代理与负载均衡,并给出可直接复用的 nginx.conf 模板。读完你会得到三件产出:覆盖 HTTP/HTTPS、WebSocket 与 gRPC 的 upstream 模板;针对慢请求、节点摘除、灰度的踩坑清单;验证配置的命令集合。
一、Nginx 反向代理的典型场景
为什么生产环境多在应用前再套一层 Nginx?三个原因:把 HTTPS、限流、静态资源缓存从业务进程剥离;用一份配置承接多个后端,避免业务进程暴露在公网;通过 upstream 分发到多台实例做水平扩容与故障转移。
场景判断:单台后端、QPS 长期低于 200 的小站,让应用直接监听公网即可;后端有重启、灰度需求或要把 PHP-FPM、Node.js、Go 挂到同一域名不同路径,就该上反向代理;后端实例超过 2 台并需要按权重或最小连接数分发时,同时需要 upstream 负载均衡。底层资源直接决定 Nginx 与后端实例的吞吐上限——这里说的带宽(Bandwidth,即网络出口的数据传输速率,单位 Mbps)与并发连接数(即同时维持的活跃 TCP 连接数)是两条最常见的上限线,往往在压测时第一次被暴露出来。云服务器(基于虚拟化的弹性计算资源)的机型选择可参考 云服务器选购指南 里的并发与带宽章节。
二、可复用的反向代理基础模板
下面这段配置覆盖了 80% 的生产场景:监听 443,HTTPS 证书由 Let’s Encrypt 签发,把 /api/ 路径转发给后端,其它路径回落到主应用。这份模板有意保持精简,每一行都对应一个生产场景里被反复证明的最佳实践,建议你拷贝过去之后逐行读一遍,再根据自己的业务接口数与并发模型做参数微调。
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/le/fullchain.pem;
ssl_certificate_key /etc/le/privkey.pem;
location /api/ {
proxy_pass http://be;
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_read_timeout 30s;
}
location / { proxy_pass http://be; }
}
关键参数说明:proxy_set_header 必须显式带上 X-Real-IP 与 X-Forwarded-For,否则后端拿到的全是 Nginx 自己的 IP,业务日志会退化成同一行;三个 timeout 默认值偏大,建议按接口实际响应时间收紧,连接超时 3 到 5 秒、读超时按 P99 响应时间的两倍。X-Forwarded-Proto 容易被忽略,但 Laravel、Django 依赖它判断 HTTPS,缺失会让生成的链接错回 http,触发混合内容问题。
把这套模板部署到 VPS(Virtual Private Server,虚拟专用服务器,基于虚拟化划分的独立实例)时,可参考 美国 VPS 部署教程 的防火墙与端口放行章节。配置落地后建议把整套 conf 纳入 Git,每次改动以 PR 形式审查,避免直接在生产机 vim 改完 reload。
三、upstream 负载均衡与策略选择
把单台后端换成 upstream 段后,Nginx 就具备了负载均衡能力。常见的策略有四种:默认 round-robin 按顺序轮询;weight 加权轮询适合后端配置不一致;least_conn 把请求分发给当前活跃连接数最少的节点,适合长连接服务;ip_hash 用客户端 IP 取模,适合需要会话粘性的场景。
upstream backend {
least_conn;
server 10.0.1.11:8080 weight=3 max_fails=2 fail_timeout=15s;
server 10.0.1.12:8080 weight=2 max_fails=2 fail_timeout=15s;
server 10.0.1.13:8080 backup;
keepalive 64;
}
backup 节点只在主节点全部宕机时参与分发,适合作预备机;max_fails 与 fail_timeout 控制被动健康检查,连续失败两次后摘除 15 秒;keepalive 让 Nginx 与后端复用 TCP 连接,能把短请求场景下的握手成本降低约 40%。注意 keepalive 必须配合 proxy_http_version 1.1; 与清空 Connection 头,否则 HTTP/1.0 默认每次都重建连接。生产建议把 keepalive 设为后端单实例预估连接数的两倍。
WordPress 多实例时,建议把 wp-admin 单独抽出来用 ip_hash 锁定到一台,避免登录会话因分发跳变失效;底层主机选型可参考 WordPress 香港主机选购指南 与 W3 Total Cache 调优实战。
四、健康检查与节点摘除
Nginx 开源版的健康检查是被动型:真实请求失败累计到阈值才会摘除节点,期间已有用户感知错误。要做到主动检查,需要在应用层暴露 /healthz,再用脚本或 Nginx Plus、tengine_upstream_check 模块定时探测。
折中做法是用 cron 调 curl 检查节点,发现异常后通过 nginx -s reload 把故障节点临时改成 down:
for ip in 10.0.1.11 10.0.1.12 10.0.1.13; do
c=$(curl -s -o /dev/null -w "%{http_code}" --max-time 3 http://${ip}:8080/healthz)
echo "${ip} ${c}"
done
把脚本接到企业微信、钉钉机器人做告警,比等用户反馈再排查省心得多。
五、WebSocket、gRPC 与超时配置
WebSocket 与 gRPC 是反向代理最容易踩坑的两类协议。WebSocket 需要 Upgrade 头透传:
location /ws/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
}
proxy_read_timeout 默认 60 秒会让长连接每分钟断一次,长聊天、推送业务建议拉到 1 小时。gRPC 需要 grpc_pass 替代 proxy_pass,listen 必须带 http2。
超时调优原则:upstream 内部超时要小于外部网关的客户端超时,否则会出现”幽灵连接”吃光 worker_connections 配额。worker_connections 默认 1024,公网入口建议拉到 65535 并相应调高 ulimit。
六、生产环境踩坑清单
本节给出一组生产中最常踩到的故障与处理方向:proxy_pass 末尾带不带斜杠决定 URI 是否被拼接覆盖,实际跨域问题里 90% 的 404 都是斜杠拼错导致;https 后端要用 proxy_ssl_server_name on 才能正确发送 SNI,否则 Cloudflare、CloudFront 会直接返回 526;后端读写慢导致 502 时,先看 error.log 有没有 upstream prematurely closed connection,再看进程是否被 OOM kill;灰度发布用 split_clients 按百分比分流比直接改 upstream 权重更安全。
改动 nginx.conf 后必须 nginx -t 验证语法,再 nginx -s reload 平滑重载。重载过程不会中断现有连接,但 worker 进程要等所有连接释放才退出,老连接耗尽前内存占用会暂时翻倍。更多 WordPress 多实例议题可继续阅读 WordPress 分类下的相关文章。
总结与建议
Nginx 的反向代理与负载均衡是”配一次受益很久”的能力:要点不在追求高级模块,而在于把 proxy_set_header、超时、keepalive、健康检查这几个基础项配置正确。建议你先按本文模板搭一套测试环境,用 ab 或 wrk 跑一轮压测再上生产;如果有多区域、跨机房需求,下一步可考虑把 Nginx 与 Consul、Etcd 这类服务发现组件结合,让 upstream 列表自动同步。最后把整套配置沉淀到 Git 仓库,团队任何人都能 10 分钟内复现。