ip_hash基于$remote_addr计算,需先用set_real_ip_from和real_ip_header将cdn后的真实用户ip覆盖$remote_addr,再在upstream中配置ip_hash,使其自动作用于真实ip;real_ip配置必须置于http或server块,不可仅限location。

nginx 的 ip_hash 本身只作用于客户端直连 IP(即 `$remote_addr`),而经过 CDN 后,真实用户 IP 通常藏在请求头如 X-Forwarded-For 或 X-Real-IP 中。直接在 upstream 块里用 ip_hash 无法感知 CDN 后的真实用户 IP —— 它仍按 CDN 节点的出口 IP 做哈希,导致同一用户被分散到不同后端。
要让 ip_hash “看到”真实用户 IP,核心是:先用 set_real_ip_from + real_ip_header 把 $remote_addr 替换为真实 IP,再让 ip_hash 基于此计算。但注意:ip_hash 不支持变量,只认 $remote_addr(且不可改写为其他变量)。所以关键在于:让 nginx 在建立连接阶段就完成真实 IP 的识别和覆盖。
前提:正确配置 real_ip 模块识别 CDN 真实 IP
确保 nginx 编译时启用了 --with-http_realip_module(主流发行版默认包含)。然后在 http 或 server 块中配置:
-
set_real_ip_from指定可信 CDN 节点 IP 段(如 Cloudflare、阿里云全站加速、腾讯云 CDN 的官方 IP 列表) -
real_ip_header设置来源头字段(CDN 通常用X-Forwarded-For或X-Real-IP;推荐优先用X-Real-IP,更简洁可靠) -
real_ip_recursive on(可选,用于多层代理时递归取最后一个非信任 IP)
示例(以 Cloudflare 为例):
set_real_ip_from 173.245.48.0/20; set_real_ip_from 103.21.244.0/22; # ... 其他 Cloudflare IP 段(务必填全) real_ip_header X-Real-IP; # real_ip_header X-Forwarded-For; # 若 CDN 只传 XFF,且你确认格式规范(首 IP 即用户),也可用 real_ip_recursive on;
ip_hash 必须放在 upstream 块中,且依赖 real_ip 处理后的 $remote_addr
ip_hash 指令只能出现在 upstream 块内,它自动使用当前连接的 $remote_addr —— 这个值已在 real_ip 阶段被替换为真实用户 IP。因此只要 real_ip 配置生效,ip_hash 就天然基于真实 IP 工作。
⚠️ 注意:real_ip 配置必须位于 http 或 server 块(影响所有 location),不能只写在某个 location 里;否则 upstream 无法感知。
示例 upstream:
upstream backend {
ip_hash; # 此处无需指定变量,它自动用处理后的 $remote_addr
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
验证是否生效:检查日志与行为
添加日志格式,同时输出原始 $remote_addr 和真实 IP(如 $http_x_real_ip),对比确认:
log_format realip '$remote_addr - $http_x_real_ip - $http_x_forwarded_for - $request'; access_log /var/log/nginx/access.log realip;
访问时观察日志:
– 若 $remote_addr 显示为 CDN IP,说明 real_ip 未生效;
– 若 $remote_addr 已变为用户真实 IP,且 $http_x_real_ip 一致,则 ip_hash 已基于真实 IP 计算。
进一步验证:用同一真实 IP(如手机开飞行模式再连 WiFi)反复刷新,观察 upstream 分发是否始终命中同一台后端服务器。
常见陷阱与绕过方案
如果 CDN 不支持透传 X-Real-IP(只传 X-Forwarded-For 且格式混乱),或你无法控制 CDN 头,real_ip 可能失效。此时可考虑:
- 改用
hash $http_x_forwarded_for consistent;(需 nginx ≥ 1.7.2),但需确保 XFF 不被伪造(配合 CDN 白名单 +set_real_ip_from限定可信源) - 由 CDN 在请求头注入带签名的用户标识(如
X-CDN-UID),再用hash $http_x_cdn_uid;实现稳定路由 - 放弃 IP 级会话保持,改用 cookie hash(
ip_hash不适用,需hash $cookie_session_id;)或后端统一 Session 存储











