如何从 Cloudflare 获取真实客户端 IP?

Cloudflare 可以为网站提供免费的 CDN 和 DDoS 防护,但在使用时 Apache 获取到的 IP 地址将是 Cloudflare 的,而不是访问者的真实客户端 IP。如果希望在 Web 服务器的日志中记录真实客户端 IP 或者根据 IP 进行访问控制的配置,则可以使用 mod_remoteip 模块来获取真实客户端 IP,本文将在 CentOS 7上完成这一个过程。

启用 mod_remoteip 模块

Apache 2.4.6默认已经包含了 mod_remoteip 模块,打开 /etc/httpd/conf/httpd.conf 配置文件,添加以下配置即可加载 mod_remoteip

1
LoadModule remoteip_module modules/mod_remoteip.so

定义可信代理地址

新建 /etc/httpd/conf.d/remoteip.conf 文件,包含 RemoteIPHeader CF-Connecting-IP,然后再添加可信代理地址,在 Cloudflare 已经给出了其当前 IP 范围的 IPv4IPv6 列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
RemoteIPHeader CF-Connecting-IP
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 172.64.0.0/13
RemoteIPTrustedProxy 131.0.72.0/22
RemoteIPTrustedProxy 104.16.0.0/13
RemoteIPTrustedProxy 104.24.0.0/14
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

自定义日志格式

打开 /etc/httpd/conf/httpd.conf 文件,默认的日志格式如下:

1
2
3
4
5
6
7
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common

<IfModule logio_module>
# You need to enable mod_logio.c to use %I and %O
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
</IfModule>

如果在日志中记录真实客户端 IP 就将远程主机 IP %h 替换为访问的客户端 IP %a。如下所示:

1
2
3
4
5
6
7
LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%a %l %u %t \"%r\" %>s %b" common

<IfModule logio_module>
# You need to enable mod_logio.c to use %I and %O
LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
</IfModule>