Nginx 反向代理和负载均衡
约 1021 字大约 3 分钟
2025-11-01
使用与后端协议兼容的 pass 指令
原理与注意事项
Nginx 提供多种 *_pass 指令,每种指令都针对特定的后端协议:
HTTP 后端:使用 proxy_pass,通过普通 HTTP 与后端服务器通信。
非 HTTP 后端:
uwsgi_pass→ 使用 uWSGI 协议fastcgi_pass→ 使用 FastCGI 协议(如 PHP-FPM)scgi_pass→ 使用 SCGI 协议
正确使用协议能够确保性能和功能的充分发挥。例如,使用 uwsgi_pass 可以充分利用 uWSGI 的插件和特性,而使用 proxy_pass 仅能通过 HTTP 与 uWSGI 通信,无法利用 uWSGI 特有功能。
示例
错误配置
server {
location /app/ {
proxy_pass 192.168.154.102:4000; # 实际是 uWSGI 应用,不应使用 proxy_pass
}
}正确配置
server {
location /app/ {
proxy_pass http://192.168.154.102:80; # HTTP 前端代理
}
location /app/v3 {
uwsgi_pass 192.168.154.102:8080; # uWSGI 后端
}
location /app/v4 {
fastcgi_pass 192.168.154.102:8081; # PHP-FPM 后端
}
}小心 proxy_pass 指令中的斜杠
原理
proxy_pass 的 URI 部分会影响最终请求的 URL 生成方式:
- 不带 URI:Nginx 保留原始请求 URI(包括所有
/../等),直接转发给后端。 - 带 URI:Nginx 会替换匹配的 location 前缀部分,类似
alias指令的行为。
示例
location = /a {
proxy_pass http://127.0.0.1:8080/a;
}
location ^~ /a/ {
proxy_pass http://127.0.0.1:8080/a/;
}总结: 尾随斜杠要慎用,否则可能导致请求路径错位,尤其在动态路由或 API 接口时。
正确使用 $host 设置 Host 头
原理
$host 是推荐的 Host 变量,因为它总是有意义:
$host→ 请求行中的主机名,或者 Host 头,或者匹配的 server_name$http_host→ 请求头中原始 Host 值$server_name→ Nginx 配置的 server_name
推荐:
proxy_set_header Host $host;总结:使用 $host 能保证 Host 头正确传递给后端,避免应用获取到错误的主机信息。
正确设置 X-Forwarded-For 头
原理
X-Forwarded-For 用于传递客户端真实 IP:
- 通过多个代理时,会形成逗号分隔的 IP 列表
- 第一个 IP 是最原始的客户端 IP
- 后端必须正确解析该列表,并结合信任链来确定真实 IP
示例
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 等价写法
proxy_set_header X-Forwarded-For $http_x_forwarded_for,$remote_addr;
# 或使用 realip 模块
proxy_set_header X-Forwarded-For "$http_x_forwarded_for, $realip_remote_addr";安全性注意
- 不信任外部客户端随意设置的 X-Forwarded-For
- 信任链应从负载均衡器开始
- 后端应用需解析正确顺序,避免 IP 欺骗
正确设置 X-Forwarded-Proto 头
原理
标识客户端协议(HTTP 或 HTTPS):
$scheme→ 当前请求协议- 多级代理时,直接使用
$scheme可能会产生偏差 - 可使用
$proxy_x_forwarded_proto解决多级代理问题
示例
# 单级代理
proxy_set_header X-Forwarded-Proto $scheme;
# 多级代理
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;总结:确保后端知道客户端使用的协议,便于生成正确 URL 或安全策略判断。
传递必要的 Host 与 X-Forwarded 头
建议头列表
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-Host $host:$server_port;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Proto $scheme;说明:这些头能让后端准确获取客户端信息,实现访问控制、日志记录、统计分析等功能。
自定义头命名规范
原理
- 遵循 RFC-6648,弃用
X-前缀 - 可继续使用
X-前缀,但不推荐 - 新的自定义头使用无前缀且有意义的名称
示例
# 不推荐
add_header X-Backend-Server $hostname;
# 推荐
add_header Backend-Server $hostname;负载均衡与健康检查
配置示例
upstream backend {
server bk01_node:80 max_fails=3 fail_timeout=5s;
server bk02_node:80 max_fails=3 fail_timeout=5s down; # 标记下线
}总结
max_fails与fail_timeout控制被动健康检查down可永久下线或维护中服务器- 支持备份服务器,主服务器不可用时自动切换
- IP 哈希时
down可避免客户端哈希失效
安全与防盗链
示例
location ~* \.(gif|jpg|png)$ {
valid_referers none blocked 192.168.0.1;
if ($invalid_referer) {
rewrite ^/ http://$host/logo.png;
}
}说明
- 限制访问资源来源,防止盗链
- 可结合 CDN、缓存进一步提升安全性和性能