根本原因是Nginx未配置set_real_ip_from信任CDN回源IP段,导致不解析X-Forwarded-For头,$remote_addr仍为CDN节点IP;必须显式声明可信IP段、设置real_ip_header和real_ip_recursive on,并确保fastcgi_param REMOTE_ADDR $remote_addr透传生效。

宝塔面板开启 CDN 后拿不到真实 IP,根本不是 PHP 或日志没写对,而是 Nginx 根本没把 X-Forwarded-For 当真——它默认只认直接 TCP 连接的 $remote_addr,而这个值在 CDN 回源时就是 CDN 节点 IP。必须用 set_real_ip_from 显式告诉 Nginx:“这些 IP 段来的流量,头里带的 X-Forwarded-For 是可信的”,否则所有后续逻辑(限流、封禁、日志、地理定位)全会错。
确认 CDN 是否真的透传了 X-Forwarded-For 头
很多问题卡在这一步就停了:你以为 CDN 配好了,其实它压根没发这个头。
- 在网站根目录加个临时调试页
debug-ip.php,内容为:<?php var_dump($_SERVER['HTTP_X_FORWARDED_FOR'] ?? 'MISSING'); var_dump($_SERVER['HTTP_X_REAL_IP'] ?? 'MISSING'); var_dump($_SERVER['REMOTE_ADDR']); ?>
- 访问该页面,看输出:
- 如果
HTTP_X_FORWARDED_FOR是空或MISSING,说明 CDN 侧未开启“传递客户端真实 IP”——腾讯云叫「IP 回传」,阿里云在「域名管理 → 回源 IP 段」页面下方有开关,Cloudflare 要在「Rules → HTTP Request Headers」里启用「True Client IP」 - 如果
HTTP_X_FORWARDED_FOR有值但REMOTE_ADDR还是 CDN 内网段(如100.100.x.x),说明 Nginx 没配置信任段,还没走到解析那步
- 如果
在宝塔站点配置中添加 real_ip 相关指令
宝塔不提供图形化入口,必须手动改站点配置文件。这三行缺一不可,且顺序不能乱,必须放在 server { 块最顶部(location / { 之前):
-
set_real_ip_from必须填你所用 CDN 官方公布的**回源 IP 段**,不能写0.0.0.0/0(极不安全):- Cloudflare:必须用 IPv4 + IPv6 全列表(官网实时更新,别抄旧博客的
173.245.48.0/20) - 阿里云 CDN:控制台「域名管理 → 回源 IP 段」,每季度可能更新
- 腾讯云 CDN:「访问控制 → 回源设置 → IP 回传白名单」,要逐行填全
- Cloudflare:必须用 IPv4 + IPv6 全列表(官网实时更新,别抄旧博客的
-
real_ip_header X-Forwarded-For指定从哪个头取 IP,CDN 不统一,有些用X-Real-IP,那就得改成对应值 -
real_ip_recursive on是关键:当头里是X-Forwarded-For: 1.1.1.1, 2.2.2.2, 3.3.3.3(多层代理),它会从右往左跳过所有匹配set_real_ip_from的 IP,取第一个不匹配的——这才是用户真实 IP;关掉它等于直接信最左边,极易被伪造
验证 PHP 和日志是否真正拿到真实 IP
改完 Nginx 配置只是第一步。$remote_addr 变了,不代表 PHP 和日志就自动同步。
- 检查站点配置里是否存在
fastcgi_param REMOTE_ADDR $remote_addr;—— 宝塔默认有,但如果套过自定义模板或手动删过,可能已丢失;写成$http_x_forwarded_for是错的,会出问题 - 日志格式要显式包含
$http_x_forwarded_for才能看到原始头,但真正用于业务逻辑的是$remote_addr,所以日志建议这样定义:log_format cdn '$http_x_forwarded_for - $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';
然后在站点配置里写access_log /www/wwwlogs/xxx.log cdn; - 再次运行
debug-ip.php,正确输出应是:string(13) "203.0.113.45"(真实公网 IP)+string(25) "203.0.113.45, 198.51.100.1"(逗号分隔链路)+string(13) "203.0.113.45"(REMOTE_ADDR已更新)
最容易被忽略的是:CDN 回源 IP 段必须定期核对,尤其 Cloudflare 和阿里云每季度都可能调整;还有 real_ip_recursive on 这个开关,不写或写错位置,整个 real_ip 机制就形同虚设。


















