背景

  站点启用了 CDN 后,面向访问者会隐藏服务器的真实 IP 地址,同时服务器也无法看到来访用户的真实 IP 地址,只能看到 CDN 服务提供商的节点地址,这样不利于一些服务端的功能实现。好在 Cloudflare 将访问者的 IP 地址包含在了 X-Forwarded-For 和 CF-Connecting-IP 标头中,通过 Nginx 的 http_realip_module 模块配合,前端程序还是可以获取到来访用户的真实 IP 地址。

准备工作

首先要确认 Nginx 已安装了 http_realip_module 模块
nginx -V

configure arguments: ... --with-http_realip_module ...

如果未安装 http_realip_module 模块,则需要重新编译安装 Nginx 或为 Nginx 安装动态模块,方法参考 为 Nginx 添加 Brotli 动态模块

方法1

访问 https://www.cloudflare.com/ips/ 获取 Cloudflare 的所有节点最新 IP 地址:

173.245.48.0/20
103.21.244.0/22
103.22.200.0/22
103.31.4.0/22
141.101.64.0/18
108.162.192.0/18
190.93.240.0/20
188.114.96.0/20
197.234.240.0/22
198.41.128.0/17
162.158.0.0/15
104.16.0.0/12
172.64.0.0/13
131.0.72.0/22
2400:cb00::/32
2606:4700::/32
2803:f800::/32
2405:b500::/32
2405:8100::/32
2a06:98c0::/29
2c0f:f248::/32

打开站点配置文件 /etc/nginx/conf.d/<website>.conf 插入以下内容

# cloudflare ips
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;

# use any of the following two
#real_ip_header CF-Connecting-IP;
real_ip_header X-Forwarded-For;

real_ip_recursive on;

修改完毕,测试并重新加载配置文件:

nginx -t

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

nginx -s reload

方法2

一般来说 Cloudflare 的 IP 地址是不会变的,但是为了以防万一,可以创建一个脚本,自动获取最新的 Cloudflare 节点 IP 地址并输出到单独的 conf 文件,同时将这个 conf 文件 include 进 Nginx 的站点配置里。

新建用来存放 Cloudflare 节点 IP 地址的空文件:
mkdir /etc/nginx/others; touch /etc/nginx/others/ip_cloudflare.conf

编辑站点配置文件 /etc/nginx/conf.d/<website>.conf 插入以下内容:

include others/ip_cloudflare.conf;

然后创建脚本 update_ip_cloudflare.sh 写入以下内容:

#!/bin/bash
echo "# cloudflare ips" > /etc/nginx/others/ip_cloudflare.conf;
echo "set_real_ip_from 127.0.0.1;" > /etc/nginx/others/ip_cloudflare.conf;
for i in `curl https://www.cloudflare.com/ips-v4`; do
        echo "set_real_ip_from $i;" >> /etc/nginx/others/ip_cloudflare.conf;
done
for i in `curl https://www.cloudflare.com/ips-v6`; do
        echo "set_real_ip_from $i;" >> /etc/nginx/others/ip_cloudflare.conf;
done
echo "" >> /etc/nginx/others/ip_cloudflare.conf;
echo "# use any of the following two" >> /etc/nginx/others/ip_cloudflare.conf;
echo "#real_ip_header CF-Connecting-IP;" >> /etc/nginx/others/ip_cloudflare.conf;
echo "real_ip_header X-Forwarded-For;" >> /etc/nginx/others/ip_cloudflare.conf;
echo "" >> /etc/nginx/others/ip_cloudflare.conf;
echo "real_ip_recursive on;" >> /etc/nginx/others/ip_cloudflare.conf;

nginx -s reload

修改脚本权限 chmod +x update_ip_cloudflare.sh

最后添加定时任务,每天早上 6 点钟自动执行脚本:
crontab -e

添加如下行

0 6 * * * /bin/bash /root/update_ip_cloudflare.sh >/dev/null

重启 crond 服务 service crond restart