一、问题现象
- 核心配置
nginx
后端节点集群配置
upstream backend_servers {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
server {
listen 80;
server_name 192.168.1.30;
client_max_body_size 50M;
location / {
root /usr/share/nginx/html/admin;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
# 异常的接口转发配置
location /admin-api/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://backend_servers;
}
}
- 问题表现
访问 http://192.168.1.30/admin-api/server/ 前缀的接口,持续返回 404;
若将 proxy_pass http://backend_servers; 替换为单节点 proxy_pass http://192.168.1.12:8080;,接口可正常访问;
单独测试集群内每台后端节点(192.168.1.10/11/12:8080)的 admin-api/server/ 接口,均返回正常,无 404 问题。
二、排查过程
- 初步排除常见问题
排除后端节点故障:所有节点单独访问接口正常,无服务未启动 / 接口缺失问题;
排除路径拼接问题:单节点转发未加尾斜杠仍正常,说明后端支持 /admin-api/server/ 完整路径;
排除网络连通性:Nginx 服务器可正常 telnet 所有后端节点的 8080 端口,无防火墙拦截。 - 关键验证:模拟 upstream 转发请求
通过 curl 模拟 Nginx upstream 的转发行为,发现核心差异:
bash
运行
模拟upstream转发(带Host: backend_servers),返回404
curl -v -H "Host: backend_servers" http://192.168.1.12:8080/admin-api/server/
模拟单节点转发(带Host: 192.168.1.12:8080),返回正常
curl -v -H "Host: 192.168.1.12:8080" http://192.168.1.12:8080/admin-api/server/
结论:upstream 模式下 Nginx 默认传递的 Host 头异常,导致后端服务识别失败。
三、根因分析
Nginx upstream 转发时,若未显式配置proxy_set_header Host,会默认将Host头设置为 upstream 集群名称(如backend_servers),而非客户端请求的 Host 或后端节点的 IP: 端口。
后端服务通常依赖Host头做路由匹配、域名鉴权或反向代理识别,当收到Host: backend_servers这种非预期值时,会判定为非法请求,返回 404;而单节点转发时,Nginx 隐式传递Host: 后端IP:端口,后端能正常识别,因此请求成功。
四、解决方案
-
核心修复:显式配置 Host 头
在接口转发的 location 块中添加proxy_set_header Host host;,强制传递客户端请求的 Host 头(或后端识别的固定 Host): nginx location /admin-api/ { proxy_set_header X-Real-IP remote_addr;
proxy_set_header X-Forwarded-For proxy_add_x_forwarded_for; proxy_set_header Host host; # 关键:传递客户端请求的Host(如192.168.1.30)若后端需固定Host,可替换为:proxy_set_header Host "192.168.1.12:8080";
proxy_pass http://backend_servers;
} -
配置生效
bash
运行
检查配置语法
nginx -t
平滑重启Nginx
nginx -s reload
- 生产环境优化(可选)
为避免后续节点故障 / 异常导致 404,补充 upstream 健康检查和连接优化:
nginx
upstream backend_servers {
server 192.168.1.10:8080 max_fails=3 fail_timeout=10s;
server 192.168.1.11:8080 max_fails=3 fail_timeout=10s;
server 192.168.1.12:8080 max_fails=3 fail_timeout=10s;
keepalive 32; # 长连接优化
}
location /admin-api/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_http_version 1.1; # 强制HTTP/1.1,避免连接兼容问题
proxy_pass http://backend_servers;
}
五、总结
Nginx upstream 负载均衡与单节点转发的核心差异之一是Host头的默认传递规则,当出现「单节点正常、集群 404」且后端节点无故障时,优先排查:
是否缺失Host头配置;
是否有其他关键请求头(如 X-Forwarded-Host)未传递;
upstream 集群名称是否被后端服务拦截。
显式配置proxy_set_header Host $host;是解决此类问题的关键,也是 Nginx 反向代理的最佳实践(避免依赖默认行为)。