前言
当你的网站使用 Cloudflare CDN 时,Apache 日志中记录的 IP 地址会变成 Cloudflare 代理节点的 IP,而不是访客的真实 IP。这会导致:
- 网站统计(如 Google Analytics)失去精确度
- 无法根据 IP 进行地域分析
- 防火墙/WAF 规则无法准确拦截
- 日志审计追踪困难
Cloudflare 早已弃用 mod_cloudflare 模块,官方推荐使用 Apache 内置的 mod_remoteip 来解决这个问题。
本文基于 Rocky Linux 8.10 + Apache 2.4.37 环境,完整记录配置过程。
环境说明
| 项目 | 信息 |
|---|---|
| 操作系统 | Rocky Linux 8.10 (Green Obsidian) |
| Web 服务器 | Apache 2.4.37 |
| 模块状态 | mod_remoteip 已加载,未配置 |
| 目标 | 恢复 Cloudflare 后的真实访客 IP |
第一步:检查 mod_remoteip 模块
bash
# 检查模块是否已加载
httpd -M | grep remoteip
输出 remoteip_module (shared) 表示模块已启用。如果未加载,在 /etc/httpd/conf.modules.d/ 中添加:
apache
LoadModule remoteip_module modules/mod_remoteip.so
第二步:创建 remoteip 配置文件
创建 /etc/httpd/conf.d/remoteip.conf:
apache
# Cloudflare mod_remoteip 配置
# 从 CF-Connecting-IP 请求头恢复真实访客 IP
RemoteIPHeader CF-Connecting-IP
# Cloudflare IPv4 地址段
RemoteIPTrustedProxy 173.245.48.0/20
RemoteIPTrustedProxy 103.21.244.0/22
RemoteIPTrustedProxy 103.22.200.0/22
RemoteIPTrustedProxy 103.31.4.0/22
RemoteIPTrustedProxy 141.101.64.0/18
RemoteIPTrustedProxy 108.162.192.0/18
RemoteIPTrustedProxy 190.93.240.0/20
RemoteIPTrustedProxy 188.114.96.0/20
RemoteIPTrustedProxy 197.234.240.0/22
RemoteIPTrustedProxy 198.41.128.0/17
RemoteIPTrustedProxy 162.158.0.0/15
RemoteIPTrustedProxy 104.16.0.0/12
RemoteIPTrustedProxy 172.64.0.0/13
RemoteIPTrustedProxy 131.0.72.0/22
# Cloudflare IPv6 地址段
RemoteIPTrustedProxy 2400:cb00::/32
RemoteIPTrustedProxy 2606:4700::/32
RemoteIPTrustedProxy 2803:f800::/32
RemoteIPTrustedProxy 2405:b500::/32
RemoteIPTrustedProxy 2405:8100::/32
RemoteIPTrustedProxy 2a06:98c0::/29
RemoteIPTrustedProxy 2c0f:f248::/32
关键指令说明
| 指令 | 作用 |
|---|---|
RemoteIPHeader |
指定从哪个 HTTP 请求头获取真实 IP。Cloudflare 使用 CF-Connecting-IP |
RemoteIPTrustedProxy |
声明哪些代理 IP 是可信的,只有来自这些 IP 的请求才会被替换 IP |
⚠️ 安全提示 :不要使用
RemoteIPTrustedProxy 0.0.0.0/0等通配规则,攻击者可以伪造CF-Connecting-IP请求头来欺骗服务器。
第三步:修改日志格式(推荐)
将 %h 替换为 %a,这让日志语义更明确:
bash
# 先备份
cp /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.bak
# 修改
sed -i 's/^ LogFormat "%h / LogFormat "%a /' /etc/httpd/conf/httpd.conf
修改前后对比:
diff
- LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+ LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
| 占位符 | 含义 |
|---|---|
%h |
远程主机名(默认情况下即对端 IP) |
%a |
经过 mod_remoteip 处理后的真实客户端 IP |
💡 实际上
mod_remoteip配置正确后,%h也会显示真实 IP。但使用%a语义更清晰,是 Cloudflare 官方推荐的最佳实践。
第四步:测试并重启
bash
# 1. 检查配置语法
apachectl configtest
# 输出: Syntax OK
# 2. 重启 Apache
systemctl restart httpd
# 3. 确认服务状态
systemctl status httpd
第五步:验证效果
方法一:curl 模拟测试
bash
curl -s -H "CF-Connecting-IP: 1.2.3.4" http://localhost/ -o /dev/null
tail -1 /var/log/httpd/access_log
访问日志中应显示 1.2.3.4 而非 127.0.0.1。
方法二:实际访问验证
从外部访问网站,检查日志中的 IP 是否为真实访客 IP(而非 Cloudflare 的 IP 段)。
常见问题
Q: 配置后仍然显示 Cloudflare IP?
- 确认
remoteip.conf放在了/etc/httpd/conf.d/目录下 - 检查 Cloudflare IP 段是否最新:https://www.cloudflare.com/ips/
- 确认请求确实经过了 Cloudflare(检查是否存在
CF-Connecting-IP请求头)
Q: mod_remoteip 和 mod_cloudflare 有什么区别?
| 对比 | mod_cloudflare | mod_remoteip |
|---|---|---|
| 维护状态 | 已弃用 | 活跃维护 |
| 来源 | 第三方模块 | Apache 内置 |
| 安装方式 | 需手动编译 | 系统自带 |
Q: 需要定期更新 Cloudflare IP 段吗?
建议定期检查。Cloudflare 的 IP 段不常变动,但偶尔会有新增。可以考虑编写 cron 脚本自动拉取更新:
bash
# 示例:每月自动更新 Cloudflare IP 段
curl -s https://www.cloudflare.com/ips-v4/ > /tmp/cf-ips.txt
总结
通过三步即可完成配置:
- 创建
remoteip.conf--- 信任 Cloudflare IP 段,使用CF-Connecting-IP头 - 修改 LogFormat ---
%h→%a(最佳实践) - 重启 Apache --- 使配置生效
配置完成后,Apache 日志将正确记录访客的真实 IP,便于后续的日志分析和安全审计。