跳到主要内容

Nginx 反向代理与流量治理

Nginx 常位于外部流量、应用服务与静态资源之间。运维目标不是只让配置加载成功,而是保证配置变更可验证、连接可追踪、超时边界明确,并且发生故障时能够快速限流、摘除后端或回滚。

1. 变更前检查与平滑加载​

所有变更先在目标节点校验语法和完整配置,再通过 reload 平滑加载。不要直接重启;重启会中断正在处理的连接。

# 检查主配置及全部 include 文件的语法;失败时不要继续加载。
sudo nginx -t

# 输出 Nginx 实际生效的完整配置,排查 include 顺序和重复 server 块。
sudo nginx -T | less

# 平滑加载新配置:旧 worker 继续处理已有连接,新 worker 接管新请求。
sudo systemctl reload nginx

# 查看服务状态和最近错误,确认新 worker 已正常拉起。
sudo systemctl status nginx --no-pager
sudo journalctl -u nginx -n 100 --no-pager

变更前应备份待修改文件、记录当前版本和回滚命令。需要回滚时恢复原文件后重新执行 nginx -t,再 reload;不要在语法校验失败时强制加载。

2. 反向代理与健康边界​

proxy_connect_timeout、proxy_read_timeout 和 proxy_send_timeout 分别约束连接后端、读取后端响应和向后端发送请求的时间。它们应小于上游应用的无效等待时间,并与负载均衡器、客户端超时协调。

# /etc/nginx/conf.d/api.example.internal.conf
upstream api_backend {
# least_conn 适合请求耗时存在明显差异的服务。
least_conn;
server 10.20.10.11:8080 max_fails=3 fail_timeout=10s;
server 10.20.10.12:8080 max_fails=3 fail_timeout=10s;
# 维护期间保留配置但不接收流量。
# server 10.20.10.13:8080 down;
keepalive 64;
}

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

location / {
proxy_pass http://api_backend;
# 透传原始 Host、客户端地址和协议,便于应用日志与跳转逻辑正确工作。
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_http_version 1.1;
proxy_set_header Connection "";
proxy_connect_timeout 3s;
proxy_read_timeout 30s;
proxy_send_timeout 30s;
}
}

开源版 Nginx 的 max_fails 属于被动健康检查,只在请求失败后才会暂时摘除后端。业务需要主动健康检查时,应由负载均衡器、服务网格或受支持的 Nginx 发行版提供;不能把 TCP 可连通误认为应用健康。

3. TLS 与安全响应头​

证书私钥权限必须仅限 Nginx 运行账号和受控管理员读取。证书替换后先 nginx -t,再 reload,并从外部验证证书链和 SNI。

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

# 使用受控证书和私钥;私钥文件不得提交到仓库或写入镜像。
ssl_certificate /etc/nginx/tls/api.example.internal.fullchain.pem;
ssl_certificate_key /etc/nginx/tls/api.example.internal.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;

# 仅当站点全量 HTTPS 且重定向策略验证完成后启用 HSTS。
add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
}
# 指定域名发起 TLS 握手,核对证书链、有效期和协商协议。
openssl s_client -connect api.example.internal:443 -servername api.example.internal </dev/null

# 从客户端侧查看响应头和状态码,确认 HTTPS 与代理链路均正确。
curl -fsSI https://api.example.internal/

4. 限流、连接限制与静态资源​

限流阈值必须基于正常峰值、突发流量和后端容量设定。先观察状态码和误伤比例,再逐步收紧;不要在事故中未经评估地把所有请求限成很小的值。

# 在 http 块定义:每个客户端 IP 平均每秒 20 个请求,使用受控共享内存记录状态。
limit_req_zone $binary_remote_addr zone=api_rate:10m rate=20r/s;
# 每个客户端 IP 最多 30 个并发连接,防止单一来源耗尽 worker 连接。
limit_conn_zone $binary_remote_addr zone=per_ip_conn:10m;

server {
listen 80;
server_name static.example.internal;

location /api/ {
# 允许短时突发 40 个请求;超过阈值返回 429,而不是压垮上游。
limit_req zone=api_rate burst=40 nodelay;
limit_req_status 429;
limit_conn per_ip_conn 30;
proxy_pass http://api_backend;
}

location /assets/ {
# 带版本号的静态资源可长期缓存;未版本化内容不应使用 immutable。
expires 30d;
add_header Cache-Control "public, immutable";
try_files $uri =404;
}
}

5. 日志、连接与故障排查​

访问日志用于定位请求量、延迟和状态码;错误日志用于定位上游连接失败、超时和配置问题。生产环境建议使用结构化日志并采集 $request_id,让网关、应用和链路追踪系统能够关联同一请求。

# 在 http 块定义 JSON 访问日志;日志采集器应处理字段转义和轮转。
log_format access_json escape=json '{'
'"time":"$time_iso8601",'
'"request_id":"$request_id",'
'"remote_addr":"$remote_addr",'
'"request":"$request",'
'"status":$status,'
'"request_time":$request_time,'
'"upstream_addr":"$upstream_addr",'
'"upstream_status":"$upstream_status",'
'"upstream_response_time":"$upstream_response_time"'
'}';

access_log /var/log/nginx/access.json access_json;
error_log /var/log/nginx/error.log warn;
# 持续查看上游失败、超时和连接错误;事故中先确认具体 upstream 与错误时间。
sudo tail -F /var/log/nginx/error.log

# 汇总访问日志状态码,快速发现 4xx/5xx 是否异常增长。
awk '{count[$9]++} END {for (code in count) print code, count[code]}' \
/var/log/nginx/access.log | sort -n

# 查看监听端口及活跃 TCP 连接,确认请求是否真正进入本机。
sudo ss -lntp | rg ':(80|443)'
sudo ss -tan '( sport = :80 or sport = :443 )' | awk 'NR>1 {count[$1]++} END {for (state in count) print state, count[state]}'

出现 502 时优先检查上游地址、进程监听、网络策略和错误日志;504 则重点检查后端耗时、超时配置与连接池耗尽。任何临时扩大超时或关闭限流的动作,都应设置复查时间并在恢复后回收。

6. 发布检查表​

  • 已在目标节点执行 nginx -t,并审阅 nginx -T 中最终生效的 server 与 upstream。
  • 已从入口侧验证关键路径的状态码、TLS 证书、跳转及真实客户端 IP。
  • 已确认后端实例、超时阈值、限流参数与业务容量匹配。
  • 已确认访问日志、错误日志和监控采集正常,且日志轮转不会中断写入。
  • 已准备可执行的配置回滚,并在加载后观察 4xx、5xx、延迟和上游错误率。