排查ip_hash哈希偏移的核心是确认$remote_addr是否为用户真实IP;若被多层代理覆盖为内网地址(如10.10.1.1),则哈希必然失真,需通过set_real_ip_from、real_ip_header和real_ip_recursive精准还原,并验证日志中$remote_addr与$http_x_forwarded_for是否匹配。

排查 Nginx 中因多级代理导致 ip_hash 绑定真实 IP 偏移,核心是确认 Nginx 实际用于哈希计算的客户端 IP 是否被上游代理覆盖或伪造,而非原始用户真实 IP。
确认 Nginx 接收到的真实远端地址
Nginx 的 ip_hash 默认使用 $remote_addr 变量做哈希——它只取直接 TCP 连接的对端 IP(即最后一跳代理的 IP),不是用户真实 IP。如果前面有 CDN、LB 或反向代理(如 HAProxy、另一层 Nginx),$remote_addr 就是那台代理的内网 IP,所有用户都映射到同一组代理 IP 上,导致 ip_hash 严重倾斜甚至全部打到同一台后端。
- 在 server 或 location 块中临时加日志:
log_format debug_log '$remote_addr - $http_x_forwarded_for - $http_x_real_ip';
access_log /var/log/nginx/debug.log debug_log; - 触发请求后检查日志:若
$remote_addr是内网地址(如 10.x、172.16–31.x、192.168.x),而$http_x_forwarded_for或$http_x_real_ip才含公网 IP,说明真实 IP 被藏在请求头里。
正确提取并信任真实客户端 IP
不能直接用 $http_x_forwarded_for,它可能被客户端伪造;必须结合 set_real_ip_from 和 real_ip_header 让 Nginx 主动解析可信代理链。
- 在 http 或 server 块中声明可信代理段:
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.0.0/16; - 指定从哪个 header 提取真实 IP:
real_ip_header X-Forwarded-For;
real_ip_recursive on;(启用递归解析,取最左非可信 IP) - 验证生效:此时
$remote_addr会自动变为解析后的用户真实 IP,ip_hash即基于此计算。
验证 ip_hash 是否真正按真实 IP 分散
仅看日志还不够,要验证哈希行为本身是否符合预期。
- 用不同真实 IP(如手机热点、朋友网络)反复请求,观察 upstream 日志中
$upstream_addr是否稳定落在同一台后端(同一 IP+端口); - 在 upstream 块中开启
ip_hash同时添加hash $remote_addr consistent;对比测试(注意二者互斥,需注释掉一个); - 用
curl -H "X-Forwarded-For: 1.2.3.4" http://your-domain/模拟不同 IP,配合 access_log 看$remote_addr是否变化,并检查后端分发是否随之变化。
替代方案:用真实 IP 做自定义 hash(更可控)
如果代理层级复杂、header 不统一,或需要兼容 IPv6/私有 IP 隔离,可绕过 ip_hash,改用 hash 指令 + 可信变量:
- 定义可信 IP 变量:
map $remote_addr $client_real_ip {
default $remote_addr;
}
(配合 set_real_ip_from 后,$remote_addr 已是真实 IP) - 在 upstream 中使用:
upstream backend {
hash $client_real_ip consistent;
server 192.168.1.10:80;
server 192.168.1.11:80;
} - 优势:支持
consistent(一致性哈希),增减节点影响更小;不依赖模块限制,逻辑更透明。


















