发布时间:2026-09-19 05:00 更新时间:2026-09-19 05:00 阅读量:0
把域名解析切到 Cloudflare 之后,很多人会先遇到一个说不清的现象:网站能正常打开,但 Nginx 访问日志里出现的一整列 IP 都是 Cloudflare 的节点地址,宝塔面板的访客统计、自己写的限流规则、WordPress 的评论 IP 也全都跟着变了。更麻烦的是,一旦想封某个刷接口的 IP,封的其实是 Cloudflare 节点,可能把正常访客一起挡在门外。
问题的根源不在 Cloudflare,而在于回源请求多了一层代理:访客先连到 Cloudflare 边缘节点,节点再以自己身份向你的源站发起连接,源站 TCP 层看到的自然就是节点 IP。真实访客地址被放进了 HTTP 头里,需要源站主动去读。下面把这件事拆成几块讲清楚。
Cloudflare 回源时会带上若干和客户端地址相关的请求头,最常被混淆的是这两个:CF-Connecting-IP 记录的是 Cloudflare 认定的访客真实 IP,只有一个值,比较干净;X-Forwarded-For 是一个可能很长的链,每经过一层代理就会追加一个地址,格式类似「访客IP, 中间代理IP, ...」,越靠左越接近访客,但整条链是可以被客户端伪造的。
如果源站直接暴露在公网、任何人都能拿一个假 X-Forwarded-For 来访问,只按这个头取 IP 就等于把判断权交给了访客。所以正确的做法是:只在确认请求确实来自 Cloudflare 节点的前提下,才信任它带来的地址信息,并且优先使用 CF-Connecting-IP。这也是 Nginx real_ip 模块里那个「可信来源」参数存在的意义。
Nginx 的 ngx_http_realip_module 能把指定头里的地址还原成 remote_addr,之后日志变量 $remote_addr、限流模块、访问控制都会用还原后的值。多数发行版自带该模块,可以用 nginx -V 2>&1 | grep realip 确认,如果没有就需要重新编译,具体以官方文档和实际环境为准。
配置的核心是三步:声明从哪个头取值、声明信任哪些来源、让日志输出真实地址。下面是一段可直接放进 http 块或对应 server 块的示例,IP 段请以 Cloudflare 官方当前公布的列表为准,不要长期硬编码一份旧名单。
# 声明从 CF-Connecting-IP 读取真实访客地址
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 104.16.0.0/13;
其余 Cloudflare 网段按官方文档补全
real_ip_header CF-Connecting-IP;
real_ip_recursive on;
访问日志里 %remote_addr 已是真实访客 IP
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_cf_connecting_ip"';
access_log /www/wwwlogs/example.com.log main;几个容易踩的点:set_real_ip_from 写的是直接连到你的那一跳的地址,也就是 Cloudflare 节点段,不是访客段;real_ip_header 用 CF-Connecting-IP 比用 X-Forwarded-For 更省心,不用担心链里塞了伪造值;real_ip_recursive on 表示在可信来源列表里从右往左剥,直到遇到第一个不可信地址,配合 X-Forwarded-For 使用时更有意义,用单一值的 CF-Connecting-IP 时影响不大。改完先 nginx -t 检查语法,再平滑重载:
nginx -t && nginx -s reload
tail -f /www/wwwlogs/example.com.log如果用了宝塔面板,日志路径通常在 /www/wwwlogs/ 下,配置文件在站点目录的 nginx 配置里,面板生成的日志格式可能不含自定义变量,需要按面板提供的「配置文件」入口调整,改前先备份。另外,若你的源站还套了另一层 CDN 或负载均衡,可信来源要按实际链路逐层添加,别把公网 0.0.0.0/0 写进去,那等于谁都能伪造。
real_ip 配好之后,$remote_addr 会变成真实访客地址,但依赖它的组件不一定自动跟上,需要逐个确认。
限流方面,Nginx 的 limit_req、limit_conn 默认按 $binary_remote_addr 计算,这个变量同样会被 real_ip 模块改写,所以正常情况下无需额外处理。但如果你的限流是在应用层做的(比如 PHP 里读 $_SERVER['REMOTE_ADDR']),那它读到的是 FastCGI 传过来的值,要确认 Nginx 传的是还原后的地址。宝塔环境下可以在站点配置里加一行 fastcgi_param REMOTE_ADDR $remote_addr; 来明确指定,具体写法以实际配置文件结构为准。
日志方面,除了确认 $remote_addr 正确,建议把 $http_cf_connecting_ip 也打进日志,方便日后对照排查。做访问统计的 goaccess、awk 脚本一般直接分析日志文本,日志格式改了要同步调整解析参数,否则会认不出字段。
验证真实 IP 是否生效,有个简单办法:从自己电脑访问站点,然后用 grep 在日志里找自己的公网出口 IP,如果能看到,说明链路已经通了;如果看到的还是 Cloudflare 段,就回头检查 set_real_ip_from 是否漏了当前节点所在网段,或者配置是否加在了正确的层级上。也可以用 curl 带一个测试头直接请求源站来做对照,但注意别把源站真实 IP 暴露出去,源站最好只用防火墙放行 Cloudflare 网段访问。
最后提醒一句:Cloudflare 的节点网段会调整,建议定期对照官方发布的 IP 列表更新 set_real_ip_from,或者用脚本自动拉取生成配置文件,避免哪天节点换了段、日志里又开始出现陌生地址。真实 IP 拿对了,后面的封禁、限流、统计才不会误伤,这一步值得一次做扎实。
| 📑 | 📅 |
|---|---|
| Nginx日志按天切割实操:logrotate配置与不生效排查 | 2026-09-19 |
| 宝塔面板网站目录权限怎么给:www用户与755/644取舍 | 2026-09-19 |
| Nginx上传目录禁止执行PHP:location匹配与fastcgi拦截写法 | 2026-09-18 |
| 宝塔面板数据库连不上排查:socket与3306端口、bind-address区别 | 2026-09-18 |
| 301跳转链太长拖慢首屏:curl与浏览器面板揪出重定向链 | 2026-09-18 |
| WordPress改域名后打不开:siteurl与home改错的救援步骤 | 2026-09-19 |
| 宝塔面板SSL证书部署后HTTP/2没生效:协议开启、ALPN检查与Nginx版本差异 | 2026-09-19 |
| WordPress邮件发不出去:wp_mail走SMTP还是sendmail与SPF/DKIM检查 | 2026-09-20 |
| 宝塔面板FTP连不上:Pure-FTPd被动端口与权限排查 | 2026-09-20 |
| robots.txt写错导致整站被屏蔽:误写排查与sitemap配合 | 2026-09-20 |