启用CDN后网站获取用户真实IP:Cloudflare CDN真实IP地址(Nginx,Apache)
近期在其云否维护客户的网站时,客户要求屏蔽国外IP的访问,因为从日志来看攻击的IP大部分都是来自国外,并且自己的目标用户为国内,所以只允许国内的IP访问网站可阻止绝大多数的CC和DDoS攻击。实际测试后,发现效果还是不错,攻击想要再次攻击成本增加了不少。
不过,随后发现了一个问题,就是使用了Cloudflare CDN后,网站获取到的IP地址都是Cloudflare的CDN节点的,不能得到真实用户的IP地址,防御效果大大折扣。好在Cloudflare已经为我们想到这一点了,将访问者的 IP 地址包含在 X-Forwarded-For 标头和 CF-Connecting-IP 标头。
源站直接接 Cloudflare 时,优先用只包含一个访客地址的 CF-Connecting-IP,并且只接受来自 Cloudflare 回源网段的该请求头,如果是Nginx可以使用ngx_http_realip_module模块,如果是Apache,则可以使用mod_remoteip模块来获取用户的真实IP。本篇文章就来分享一下如何编译和启用ngx_http_realip_module模块和mod_remoteip模块来获取用户的真实IP地址。
用其他 CDN 或中间还有负载均衡的朋友,先弄清源站实际连到哪一层代理、访客地址由哪一层写入,再决定信任谁。更多的关于 CDN 加速和服务器优化加速的方法,这里有:
- Cloudflare Partner接入管理Cloudflare CDN-启用Railgun动态加速
- 又拍云CDN加速申请使用教程-一键镜像,静态动态CDN和免费SSL
- WordPress开启Nginx fastcgi_cache缓存加速方法-Nginx配置实例
PS:2026年11月4日更新,更新了 Cloudflare 回源网段和 Nginx、Apache 的访客 IP 配置,补充了源站限制和伪造请求头的处理方法。
一、Nginx编译ngx_http_realip_module
先执行 nginx -V 看参数,有 --with-http_realip_module 就可以直接看第二节。下面的 OneinStack、LNMP 和宝塔编译命令是当时的 Nginx 1.14/1.15 示例,仅供查旧安装记录。
1.1 Oneinstack编译
如果用的是Oneinstack一键包,则可以用以下命令来编译ngx_http_realip_module:
#下编译安装nginx的时候,都编译安装的哪些模块
[root@wzfoume ~]# nginx -V
nginx version: nginx/1.14.2
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-23) (GCC)
built with OpenSSL 1.1.1a 20 Nov 2018
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --user=www --group=www --with-http_stub_status_module --with-http_v2_module --with-http_ssl_module --with-http_gzip_static_module --with-http_realip_module --with-http_flv_module --with-http_mp4_module --with-openssl=../openssl-1.1.1a --with-pcre=../pcre-8.42 --with-pcre-jit --with-ld-opt=-ljemalloc
#进入到oneinstack的nginx安装目录下,如果没有请先解压
[root@wzfoume src]# cd /root/oneinstack/src
[root@wzfoume src]# tar xzf nginx-1.14.2.tar.gz
[root@wzfoume src]# cd /root/oneinstack/src/nginx-1.14.2
[root@wzfoume nginx-1.14.2]# ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_stub_status_module --with-http_v2_module --with-http_ssl_module --with-http_gzip_static_module --with-http_realip_module --with-http_flv_module --with-http_mp4_module --with-openssl=../openssl-1.1.1a --with-pcre=../pcre-8.42 --with-pcre-jit --with-ld-opt=-ljemalloc --with-http_realip_module
make
#如果出现错误,应该是依赖路径不对,请cd ..到上一个目录解压相应的软件
tar xzf pcre-8.42.tar.gz
tar xzf openssl-1.0.2q.tar.gz
tar xzf openssl-1.1.1a.tar.gz
#编译完成,备份原先配置,然后替换nginx二进制文件
mv /usr/local/nginx/sbin/nginx{,_`date +%F`} #备份nginx
cp objs/nginx /usr/local/nginx/sbin
#查看是否已经把http_realip_module模块加入进去
nginx -V
1.2 LNMP编译
如果你用的是LNMP一键包,在lnmp安装目录下找到lnmp.conf编辑它,在Nginx_Modules_Options里加上realip,保存后执行./upgrade.sh nginx来升级下Nginx就可以了。命令如下:
Nginx_Modules_Options='--with-http_realip_module'
1.3 BT宝塔面板
如果你用的是BT宝塔面板,可以使用以下命令来编译ngx_http_realip_module:
#宝塔面板安装模块 #先查看一下本机的Nginx配置情况 [root@cs ~]# nginx -V nginx version: nginx/1.14.2 built by gcc 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC) built with OpenSSL 1.0.2l 25 May 2017 TLS SNI support enabled configure arguments: --user=www --group=www --prefix=/www/server/nginx --with-openssl=/www/server/nginx/src/openssl --add-module=/www/server/nginx/src/ngx_devel_kit --add-module=/www/server/nginx/src/lua_nginx_module --add-module=/www/server/nginx/src/ngx_cache_purge --add-module=/www/server/nginx/src/nginx-sticky-module --add-module=/www/server/nginx/src/nginx-http-concat --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_image_filter_module --with-http_gzip_static_module --with-http_gunzip_module --with-stream --with-stream_ssl_module --with-ipv6 --with-http_sub_module --with-http_flv_module --with-http_addition_module --with-http_realip_module --with-http_mp4_module --with-ld-opt=-Wl,-E --with-pcre=pcre-8.40 --with-ld-opt=-ljemalloc #开始下载Nginx,这里用的是1.15.1,你也可以下载其它的版本 wget http://nginx.org/download/nginx-1.15.1.tar.gz tar -xzvf nginx-1.15.1.tar.gz cd nginx-1.15.1 #下面的命令只是在上面的Nginx -v得到的配置详情后加上了--with-http_realip_module,目的是为了保持原来的配置不变同时又增加新的模块 ./configure --user=www --group=www --prefix=/www/server/nginx --with-openssl=/www/server/nginx/src/openssl --add-module=/www/server/nginx/src/ngx_devel_kit --add-module=/www/server/nginx/src/lua_nginx_module --add-module=/www/server/nginx/src/ngx_cache_purge --add-module=/www/server/nginx/src/nginx-sticky-module --add-module=/www/server/nginx/src/nginx-http-concat --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_image_filter_module --with-http_gzip_static_module --with-http_gunzip_module --with-stream --with-stream_ssl_module --with-ipv6 --with-http_sub_module --with-http_flv_module --with-http_addition_module --with-http_realip_module --with-http_mp4_module --with-ld-opt=-Wl,-E --with-pcre=pcre-8.40 --with-ld-opt=-ljemalloc --with-http_realip_module #只编译不安装 make #先停用Nginx,然后替换新的Nginx并查看模块是否已经加载。命令如下: mv /www/server/nginx/sbin/nginx /www/server/nginx/sbin/nginx-wzfou.backup cp objs/nginx /www/server/nginx/sbin/nginx nginx -V #重启Nginx
二、Nginx设置set_real_ip_from
编译好了ngx_http_realip_module,现在我们只需要在Nginx配置文件中添加set_real_ip_from代码,示例如下:
set_real_ip_from 222.222.222.222; #这里是需要填写具体的CDN服务器IP地址,可添加多个 set_real_ip_from 222.222.111.111; real_ip_header X-Forwarded-For; real_ip_recursive on;
源站直接接 Cloudflare 时,可在对应的 server 中配置下面的信任网段和请求头。按 Cloudflare 公布的 IPv4 和 IPv6 清单核对后,运行 nginx -t,通过再平滑重载。需要同时记录代理和访客地址时,可以在日志中分别使用 $realip_remote_addr 和 $remote_addr。
server {
# 以下指令合并到已有的 server 块,勿重复新建同名站点
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 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
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 2c0f:f248::/32;
set_real_ip_from 2a06:98c0::/29;
# use any of the following two
real_ip_header CF-Connecting-IP;
#real_ip_header X-Forwarded-For;
}
# 检查配置后再平滑重载
nginx -t && nginx -s reload
Cloudflare 网段会变动,完整列表见 https://www.cloudflare.com/ips/ 。下方是原来的自动更新脚本,仅供对照旧配置:它先截断旧文件,下载失败可能留下空文件或不完整的列表。日常可以按官方清单更新;已有自动化的,应先把两个清单写入临时文件并核验内容,再替换配置,检查通过后重载。
#在nginx配置目录创建cloudflare_ip.conf文件
touch /usr/local/nginx/conf/cloudflare_ip.conf
#修改原有的vhost配置,将原来第五步配置的信息改为
include cloudflare_ip.conf;
#创建自更新脚本update_cloudflare_ip.sh(假定该文件放在 /root 目录下),内容如下:
#!/bin/bash
echo "#Cloudflare" > /usr/local/nginx/conf/cloudflare_ip.conf;
for i in `curl https://www.cloudflare.com/ips-v4`; do
echo "set_real_ip_from $i;" >> /usr/local/nginx/conf/cloudflare_ip.conf;
done
for i in `curl https://www.cloudflare.com/ips-v6`; do
echo "set_real_ip_from $i;" >> /usr/local/nginx/conf/cloudflare_ip.conf;
done
echo "" >> /usr/local/nginx/conf/cloudflare_ip.conf;
echo "# use any of the following two" >> /usr/local/nginx/conf/cloudflare_ip.conf;
echo "real_ip_header CF-Connecting-IP;" >> /usr/local/nginx/conf/cloudflare_ip.conf;
echo "#real_ip_header X-Forwarded-For;" >> /usr/local/nginx/conf/cloudflare_ip.conf;
#配置crontab 每周一的上午5点更新
0 5 * * 1 /bin/bash /root/update_cloudflare_ip.sh
三、Apache配置mod_remoteip模块
3.1 apache 2.4
Apache 2.4 自带 mod_remoteip。先用 apachectl -M 检查是否已启用,再按实际安装路径配置。直接由 Cloudflare 回源时使用 RemoteIPTrustedProxy 信任官方网段;日志里的 %a 记录访客地址,%{c}a 记录底层连接地址。修改后先做配置语法检查再重载。
#启用模块
vim /usr/local/apache/conf/httpd.conf
Include conf/extra/httpd-remoteip.conf
#添加如下内容
vim /usr/local/apache/conf/extra/httpd-remoteip.conf
LoadModule remoteip_module modules/mod_remoteip.so
RemoteIPHeader CF-Connecting-IP
#CloudFlare IP Ranges
RemoteIPTrustedProxy 103.21.244.0/22
RemoteIPTrustedProxy 103.22.200.0/22
RemoteIPTrustedProxy 103.31.4.0/22
RemoteIPTrustedProxy 104.16.0.0/13
RemoteIPTrustedProxy 104.24.0.0/14
RemoteIPTrustedProxy 108.162.192.0/18
RemoteIPTrustedProxy 131.0.72.0/22
RemoteIPTrustedProxy 141.101.64.0/18
RemoteIPTrustedProxy 162.158.0.0/15
RemoteIPTrustedProxy 172.64.0.0/13
RemoteIPTrustedProxy 173.245.48.0/20
RemoteIPTrustedProxy 188.114.96.0/20
RemoteIPTrustedProxy 190.93.240.0/20
RemoteIPTrustedProxy 197.234.240.0/22
RemoteIPTrustedProxy 198.41.128.0/17 #你的CDN的IP,可以重复添加
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
#修改日志格式,在日志格式中加上%a,然后重启apache即可
LogFormat "%h %a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %a %l %u %t \"%r\" %>s %b" common
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combined
3.2 apache 2.2
下面是 Apache 2.2 的历史做法,仍用这个版本的站点可先按第一段检查迁移到 2.4 后的模块。
wget https://github.com/ttkzw/mod_remoteip-httpd22/raw/master/mod_remoteip.c /usr/local/apache/bin/apxs -i -c -n mod_remoteip.so mod_remoteip.c #启用模块 vim /usr/local/apache/conf/httpd.conf Include conf/extra/httpd-remoteip.conf #添加如下内容,然后重启apache即可 vim /usr/local/apache/conf/extra/httpd-remoteip.conf LoadModule remoteip_module modules/mod_remoteip.so RemoteIPHeader X-Forwarded-For RemoteIPInternalProxy 127.0.0.1 #你的CDN的IP,可以重复添加
四、网站仅允许Cloudflare CDN的IP访问
上面我们是通过安装ngx_http_realip_module和mod_remoteip模块获取到了用户真实的IP地址,但是有的时候我们需要借助Cloudflare 的安全防护功能来防止CC或者DDoS攻击,即仅允许Cloudflare CDN的IP访问我们的访问。
启用了 realip 后,Nginx 的 allow/deny 会按还原后的访客 IP 判断,直接填 Cloudflare 网段可能把正常访客也拦了。要限制谁能连到源站的 Web 端口,应在云防火墙或源站防火墙按 TCP 连接来源放行 Cloudflare 官方网段,并保留站点确实需要的其他来源。下面保留的是原先在 Nginx 里限制访问的示例,供排查旧配置。
location / {
deny 192.168.1.1;
allow 192.168.1.0/24;
allow 10.1.1.0/16;
allow 2001:0db8::/32;
#Railgun IP
deny all;
}
如果我们仅允许Cloudflare CDN的IP访问网站,我们可以直接在nginx配置中将Cloudflare CDN的IP添加到允许的范围内。
#直接加入 # https://www.cloudflare.com/ips # IPv4 allow 103.21.244.0/22; allow 103.22.200.0/22; allow 103.31.4.0/22; allow 104.16.0.0/12; allow 108.162.192.0/18; allow 131.0.72.0/22; allow 141.101.64.0/18; allow 162.158.0.0/15; allow 172.64.0.0/13; allow 173.245.48.0/20; allow 188.114.96.0/20; allow 190.93.240.0/20; allow 197.234.240.0/22; allow 198.41.128.0/17; # IPv6 allow 2400:cb00::/32; allow 2405:8100::/32; allow 2405:b500::/32; allow 2606:4700::/32; allow 2803:f800::/32; allow 2c0f:f248::/32; allow 2a06:98c0::/29;
旧版自动更新脚本。下列脚本保留作历史对照,适用限制与上面的例子相同,也有下载失败后覆盖配置的风险。
touch /usr/local/nginx/conf/allow_ip.conf
#修改网站nginx配置,加入以下代码:
include /usr/local/nginx/conf/allow_ip.conf;
vim /data/script/allow_cf_ip.sh
#!/bin/bash
echo "#Cloudflare" > /usr/local/nginx/conf/allow_ip.conf;
for i in `curl https://www.cloudflare.com/ips-v4`; do
echo "allow $i;" >> /usr/local/nginx/conf/allow_ip.conf;
done
for i in `curl https://www.cloudflare.com/ips-v6`; do
echo "allow $i;" >> /usr/local/nginx/conf/allow_ip.conf;
done
#添加定时任务
0 5 * * 1 /bin/bash /data/script/allow_cf_ip.sh
五、总结
使用 CDN 后,先在 Nginx 或 Apache 按可信代理的范围还原访客 IP,再把还原后的地址交给 WordPress 等应用。旧文下面这段 PHP 直接取 X-Forwarded-For 第一项,客户端可以伪造,别复制到 wp-config.php,也别用它做访问限制。Cloudflare 的配置说明:https://developers.cloudflare.com/support/troubleshooting/restoring-visitor-ips/restoring-original-visitor-ips/ 。
if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
{
$list = explode(‘,’,$_SERVER['HTTP_X_FORWARDED_FOR']);
$_SERVER['REMOTE_ADDR'] = $list[0];
}
原文还有 Cloudflare Railgun 动态加速的接入记录(挖站否的Cloudflare Partner接入管理有当时的做法),仅供对照老站。现在回源时经过自建代理的,要按实际代理链设置可信来源。
文章出自:挖站否 https://wzfou.com/cdn-real-ip/,部分内容参考自:rhilip(https://blog.rhilip.info/archives/256/)、nova(https://nova.moe/nginx-block-non-cloudflare-ips/)版权所有。本站文章除注明出处外,皆为作者原创文章,可自由引用,但请注明来源。
猜你喜欢
-
感谢分享!最后那段代码加入到 wp-config.php 配置文件中,貌似不起作用,日志里显示的仍是CF地址。
PS. 虚拟主机-Apache2.4if(isset($_SERVER[‘HTTP_X_FORWARDED_FOR’]))
{
$list = explode(‘,’,$_SERVER[‘HTTP_X_FORWARDED_FOR’]);
$_SERVER[‘REMOTE_ADDR’] = $list[0];
}2021年10月5日 11:04 -
Oneinstack用的OpenResty怎么编译鸭[威武]
2019年3月22日 15:45-
搞定了。
2019年3月22日 15:54
-
-
模块处理效率最好。
2019年3月11日 09:41 -
WordPress最方便了,一段代码就搞定了。
2019年3月11日 08:57


















你好,我是宝塔面板,已经重新编译nginx并配置。加入了文章中的两段脚本文件conf,虽然网站可以访问但是会出现第二张图的错误。 并且我尝试在nginx配置中把这两段Include包含在“location / {}”中,或者只是单独在隐藏真实IP的那段脚本Include后面添加“deny all;”网站就无法访问。请问我只是用Include导入是否正确。还有现在第二个我百度后尝试过kill所有nginx使用的端口重启还是有这个错误。[熊猫]

