ip_hash启用需严格遵循三铁律:必须顶格置于upstream首行、至少两台后端且server仅写ip:port、禁用weight等参数;须配合set_real_ip_from和real_ip_header还原真实ip,否则nat或代理下会话必然漂移。

直接在 upstream 块第一行写 ip_hash; 就能启用客户端 IP 绑定,但仅靠这一行远远不够——真实环境里,IP 失真、NAT 干扰、后端变动都会让会话“看似生效实则漂移”。关键不在加不加,而在加得对不对、配得全不全。
基础配置必须守死三条铁律
ip_hash 不是开关式指令,它有严格的语法和结构约束:
- 必须放在 upstream 块首行,顶格书写,不能缩进,不能换行,不能加注释
- upstream 内至少要定义两台后端 server(不能只写 localhost 或单节点)
- server 行只允许写
IP:PORT格式,禁用http://、路径、weight、backup、down等参数;加了会导致 Nginx 启动失败
正确示例:
upstream backend {
ip_hash;
server 10.0.1.10:8080;
server 10.0.1.11:8080;
}
真实 IP 是 ip_hash 生效的前提
如果请求经过 CDN、WAF、前置代理或公司 NAT 出口,$remote_addr 默认是上一跳地址,所有用户会被哈希成同一个值,全部打到同一台后端——这根本不是会话保持,而是会话集中。
必须在 http 块中配置可信代理段与头字段还原逻辑:
- 用
set_real_ip_from明确声明可信代理网段(如192.168.0.0/16、10.0.0.0/8) - 用
real_ip_header X-Forwarded-For指定取真实 IP 的 HTTP 头 - 在
location中透传头信息:proxy_set_header X-Real-IP $remote_addr;和proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
绕不开的硬限制与典型失效场景
ip_hash 表面简单,实则处处是坑。以下问题一旦触发,会话就不可靠:
- IPv4 只取前三段哈希:192.168.1.100 和 192.168.1.254 被视为同一 IP,在企业内网或家庭宽带 NAT 下,整栋楼用户都压向一台后端
- 后端列表变更即全局漂移:新增、下线、重排 server 顺序,所有 IP 的哈希映射整体偏移,大量用户会话丢失并重定向
-
单点故障无兜底:某台 server 标记为
down,Nginx 会剔除它,但原有 IP 仍绑定剩余节点——若该节点后续也宕机,会话彻底中断,且无法自动回退
什么情况下该考虑替代方案
当业务出现以下信号,说明 ip_hash 已到能力边界,应主动升级:
- 用户大量通过统一出口访问(如学校、政企、运营商 NAT)
- 后端频繁扩缩容或滚动发布
- 需要支持权重分配(如新老版本灰度)
- 四层 TCP/UDP 转发(如数据库代理),ip_hash 完全不生效
推荐路径:
- Web 层改用
hash $cookie_jsessionid consistent;,抗代理、NAT 更强 - Session 统一存 Redis,解耦路由与状态,Spring Boot 可配
spring.session.store-type=redis - TCP/UDP 场景改用
stream模块 +hash $remote_addr consistent;











