cdn加速后ip_hash失效因$remote_addr变为cdn节点ip,需通过real_ip模块识别可信cdn ip段、设置real_ip_header提取真实ip,并用$realip_remote_addr替代$remote_addr进行hash。

CDN 加速后,Nginx 的 ip_hash 指令默认基于 $remote_addr 计算哈希值,而该变量此时是 CDN 节点的出口 IP,不是用户真实 IP —— 导致同一用户在不同 CDN 节点间跳转时被分配到不同后端,破坏会话一致性。要让 ip_hash 精确作用于真实客户端 IP,必须先可靠提取并替换哈希依据。
确认 CDN 传递的真实 IP 头字段
不同 CDN 厂商使用不同请求头传递原始 IP,常见有:
• Cloudflare:用 X-Forwarded-For(最左 IP)或专用头 Cf-Connecting-IP
• 阿里云 CDN / 百度云加速:通常用 X-Forwarded-For
• 华为云 / 腾讯云:可能支持 X-Real-IP 或自定义头如 X-Originating-IP
务必查阅你所用 CDN 的文档,确认其实际写入的头部名称及格式(是否可信、是否可伪造、是否含多级代理)。
配置 real_ip 模块识别可信来源
仅靠读取 X-Forwarded-For 不安全 —— 该头可被客户端随意伪造。Nginx 必须结合 set_real_ip_from 明确指定哪些上游节点(即 CDN 节点 IP 段)是可信的,才允许从中解析真实 IP:
- 在
http块中添加 CDN 提供的可信 IP 段(例如 Cloudflare 公布的全部 IPv4/IPv6 地址段) - 设置
real_ip_header X-Forwarded-For(或对应 CDN 的真实头名) - 启用
real_ip_recursive on,确保从可信代理链中取最左未被污染的 IP
示例(以 Cloudflare 为例):
http {set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.22.200.0/22;
# ……(填入全部 CF 官方 IP 段)
real_ip_header Cf-Connecting-IP;
real_ip_recursive on;
}
改用 $realip_remote_addr 替代 $remote_addr 做 hash
启用 real_ip 模块后,Nginx 会将可信真实 IP 写入内置变量 $realip_remote_addr(注意不是 $remote_addr)。
在 upstream 块中,必须显式使用该变量作为 ip_hash 的输入源:
# 关键:使用真实 IP 变量,而非默认 remote_addr
ip_hash;
hash $realip_remote_addr consistent;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
⚠️ 注意:ip_hash 指令本身不支持变量,所以需搭配 hash 指令(需 nginx ≥ 1.7.2)并设为 consistent,才能真正基于 $realip_remote_addr 哈希;若坚持用原生 ip_hash,则必须确保 real_ip 生效后 $remote_addr 已被覆盖 —— 这仅在某些编译版本或特定条件下成立,不可靠。
验证与兜底处理
上线前务必验证:
• 用 curl 模拟 CDN 请求头(如 -H "Cf-Connecting-IP: 1.2.3.4"),检查 access_log 中 $realip_remote_addr 是否正确
• 查看 nginx -t 是否报 real_ip 配置语法错误
• 若 CDN 头缺失或不可信,$realip_remote_addr 会回退为 $remote_addr,此时 hash 仍基于 CDN 节点 IP —— 可通过日志标记区分:
log_format debug '$realip_remote_addr ($remote_addr) - $http_cf_connecting_ip';











