我一直都没有修复这个问题,导致nginx获取到的IP都是cdn边缘节点的IP,网上的处理教程都很简单,在nginx设置一下 real_ip_header X-Forwarded-For; 就可以解决了,但是这种方法对于多层链路无效的。
获取方法基本上都是如下,我之前写的文章。
对于多层链路,就无效了。我的网站链路是这样的。
用户 → CDN 边缘节点 → 云WAF → 源站
按照网上教程结果拿到的还是 CDN 边缘节点的 IP,而不是用户的真实 IP。
这是因为:
- X-Forwarded-For 是一个链式的 IP 列表,第一段才是用户真实 IP。
- CDN 会先写自己的 X-Forwarded-For,WAF 再转发时可能又覆盖或追加了一层。
- 你现在在源站
set_real_ip_from信任的是 WAF 的 IP,所以real_ip_header会把 WAF 发来的 X-Forwarded-For 的第一个 IP 当成真实 IP,而这个第一个 IP 就是 CDN 的边缘节点。
解决方法
你需要让源站信任 CDN 和 WAF 两层的 IP,然后递归解析 X-Forwarded-For 中最前面的那个 IP。
例如:假设
- CDN 节点 IP 段:
1.1.1.0/24 - WAF IP:
2.2.2.2
源站 Nginx 配置应为:
#信任 CDN 节点 IP 段
set_real_ip_from 1.1.1.0/24;set_real_ip_from 1.1.1.0/24;
# 信任 WAF 服务器 IP
set_real_ip_from 2.2.2.2;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
这样流程是:
- 源站看到 WAF 的 IP,因在
set_real_ip_from里,信任它提供的 X-Forwarded-For。 - Nginx 递归解析 X-Forwarded-For,发现里面还有 CDN IP,且 CDN IP 也在信任列表中,于是继续向前找。
- 最前面的就是用户真实 IP。
注意事项:
- CDN 的回源必须保留用户真实 IP(例如 Cloudflare、阿里云 CDN、腾讯云 CDN 都有保留或替换 X-Forwarded-For 的设置)。
- 你必须把 所有中间层的 IP 段都放到
set_real_ip_from,否则 Nginx 不会继续向前解析。 - 如果 CDN 使用的是
True-Client-IP或CF-Connecting-IP等自定义头,你可能需要改成:
real_ip_header CF-Connecting-IP;或者real_ip_header True-Client-IP;
我可以帮你把 CDN + WAF + 源站的 IP 递归解析配置 整理成一个完整示例,这样你直接套上就能获取到用户的真实 IP。
然后重启nginx,再访问,就可以获取用户的IP了。
