ip_hash失效的根本原因是$remote_addr被多级代理覆盖为内网ip(如10.10.2.5),而非真实客户端ip;需在http块顶部配置set_real_ip_from、real_ip_header和real_ip_recursive还原真实ip,并全链路透传x-forwarded-for,后端读x-real-ip,必要时改用cookie或consistent_hash等更鲁棒策略。

内网多级代理下 ip_hash 失效,根本不是 Nginx 配置写错了,而是它压根没拿到真实客户端 IP——所有请求的 $remote_addr 都是上一跳代理的内网地址(比如 10.10.2.5),哈希结果自然全挤在一台后端上。
第一步:确认并修复入口 Nginx 的真实 IP 还原
这是前提,其他都白搭。必须让 $remote_addr 变成用户真实 IP(哪怕只是内网地址)。
- 在
http块顶部(不能放在server或location内)添加可信代理段:set_real_ip_from 10.0.0.0/8;<br>set_real_ip_from 172.16.0.0/12;<br>set_real_ip_from 192.168.0.0/16;
- 指定从哪个 HTTP 头取原始 IP:
real_ip_header X-Forwarded-For;(若用 Cloudflare 改为CF-Connecting-IP) - 开启递归解析,自动跳过不可信中间跳:
real_ip_recursive on; - 加一条日志格式验证是否生效:
log_format debug '$remote_addr — $realip_remote_addr — $upstream_addr';
看$realip_remote_addr是否已变成你期望的终端 IP(如172.16.5.123)
第二步:确保 X-Forwarded-For 全链路透传不中断
任何一级代理清空、覆盖或错误拼接 X-Forwarded-For,都会让还原失败。
Linux 性能分析与调优专家,覆盖 CPU、内存、磁盘 I/O、网络、内核参数、编译优化、容器/K8s。适用场景:系统卡顿/高负载、内存不足/OOM/Swap 高、CPU 异常/iowait 高。
- 首层代理(直连客户端)必须用
$remote_addr初始化:proxy_set_header X-Forwarded-For $remote_addr; - 后续每一层(如 WAF → 内网 SLB → Nginx LB)必须用:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
(这个变量会自动追加当前$remote_addr到已有值末尾) - 严禁在任意中间层写死:
proxy_set_header X-Forwarded-For $remote_addr;
——这会抹掉前面所有 IP,只剩最后一跳
第三步:检查后端是否真正依赖 IP 粘性
就算 IP 还原成功,如果后端本身不共享状态,ip_hash 也解决不了数据不一致。
- 确认后端共用同一套外部状态源:Redis 实例地址、JWT 密钥、DB 连接串等必须完全一致
- 禁用本地内存缓存(如 Caffeine、Guava Cache),除非做了跨节点同步
- 后端代码应读
X-Real-IP(由 realip_module 注入,可信),而非直接解析X-Forwarded-For(易伪造) - Spring Boot 中启用
RemoteIpValve并配置trusted-proxies匹配你的 Nginx 可信网段
第四步:考虑是否真该用 ip_hash
局域网多用户共出口是常态,ip_hash 在这种场景下天然失效。与其硬调,不如换更鲁棒的方案。
- 改用
hash $cookie_session_id;:只要 cookie 有效,粘性稳定,不受 NAT 影响 - 用
hash $arg_token;或hash $http_authorization;:对接口级鉴权系统更友好 - 升级 Nginx 后使用
consistent_hash $binary_remote_addr;:增减后端时仅影响少量连接 - 如果后端已用 Redis 存 session,直接关掉 ip_hash,改用
least_conn或轮询,更健壮










