LNMP 网站启用 Cloudflare CDN 之后获取并记录用户真实 IP 地址的方法

已关闭留言

网站开启 CDN 之后,再去看看网站的访问日志,会发现全是 CDN 的 IP,这样其实挺难受的,都看不到真实的 IP 访问情况。所以老唐就花了些时间研究了一下怎么获取并记录用户访问的真实 IP 地址,因为老唐是基于 LNMP 搭建的网站环境,所以就是基于 NGINX 的方法。主要分为三步,第一是需要安装 NGINX 的一个模块,然后是修改 NGINX 配置来设置并启用这个模块,最后就是将获取到的真实 IP 地址记录到日志里。

下面教程都是基于 LNMP 一键包进行的。(一键安装 LNMP 建站环境,部署 PHP + MySQL)

文章目录
隐藏
一、安装 NGINX http_realip_module 模块
二、修改 LNMP 配置启用模块
三、记录真实 IP 到日志
四、封禁真实 IP 地址

一、安装 NGINX http_realip_module 模块

首先,我们需要安装 NGINX 的一个模块,叫 http_realip_module

在 LNMP 安装目录下找到 lnmp.conf 这个文件,编辑这个文件,在 Nginx_Modules_Options 里加上 realip,修改的命令如下:

Nginx_Modules_Options='--with-http_realip_module'

保存后执行 ./upgrade.sh nginx 来升级下 NGINX 就可以了。升级需要输入新的 NGINX 版本号,如果不想改动版本,直接输入原来的版本号即可。

这样就算是装好了。

二、修改 LNMP 配置启用模块

安装好之后,需要启用 realip 模块。如果想为所有网站启用,那么直接修改 nginx.conf 文件(/usr/local/nginx/conf/nginx.conf),如果只想对某些网站启用,那么修改对应的网站的 conf 文件即可。

方法一(推荐):

首先,在 nginx 配置目录创建下面文件:

touch /usr/local/nginx/conf/cloudflare_ip.conf

然后,以修改 nginx.conf 为例,在 server {} 里面加上下面这一行:

include cloudflare_ip.conf;

在 /root 目录下创建下面文件:

update_cloudflare_ip.sh

输入下面内容(直接复制粘贴即可):

#!/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 每周更新一次 Cloudflare 的 IP 地址(crontab -e):

0 5 * * 1 /bin/bash /root/update_cloudflare_ip.sh

这样就算配置好 Cloudflare IP 的自动更新了,最后我们需要先手动运行一下这个文件先初始化一次:

/bin/bash /root/update_cloudflare_ip.sh

方法二:

如果不想搞这么麻烦,那么直接在 nginx.conf 的 server {} 里面加入下面几行即可:

location / {
 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/12;
 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 199.27.128.0/21;
 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 了,我们需要重启一下:

lnmp nginx restart

如果不报错就是成功了,报错的话根据错误信息自己再看看哪里有问题。

三、记录真实 IP 到日志

上一步结束我们只是启用并且配置了 realip 这个模块,但是还没有真正记录到 log 日志中,所以我们现在去看日志的话,会发现还是看不到真实 IP 地址。

接下来就继续修改一下日志格式,把真实 IP 地址记录到日志中。

还是修改 /usr/local/nginx/conf/nginx.conf 这个文件,在 http {} 中间加入下面几行:

map $HTTP_CF_CONNECTING_IP  $clientRealIp {
    ""    $remote_addr;
    ~^(?P[0-9.]+),?.*$    $firstAddr;
}
log_format  main  '$clientRealIp [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '$http_user_agent $remote_addr $request_time';

主要是为了通用性,如果关闭了 CDN,可以不需要修改获取IP的方式,所以才这么修改,不然直接用 $HTTP_CF_CONNECTING_IP 就行了(这个时候就不需要在日志格式里使用 $clientRealIp

然后在网站记录的日志定义使用 main 这个日志格式,比如(需要在网站单独的配置文件中修改):

access_log /home/wwwlogs/abc.com.log main;

然后我们再次重启一下 NGINX,就可以在网站日志中看到真实的 IP 地址了。

参考:

  • https://blog.rhilip.info/archives/256/
  • https://wzfou.com/cdn-real-ip/
  • https://support.cloudflare.com/hc/en-us/articles/200170786-How-do-I-restore-original-visitor-IP-with-Nginx
  • https://docs.nginx.com/nginx/admin-guide/monitoring/logging/
  • https://www.bbsmax.com/A/A7zgbXXWd4/

四、封禁真实 IP 地址

后续如果我们还想更进一步封禁真实 IP 地址,可以使用下面的方法,因为开了 CDN 之后使用 iptables 是没法封禁真实 IP 地址的。

在强大的 Nginx 面前只要想得到,你就做得到!通过对 $clientRealIP 这个变量的判断,Nginx 就能实现隔山打牛的目的,而且规则简单易懂:

#如果真实IP为 121.42.0.18、121.42.0.19,那么返回403
if ($clientRealIp ~* "121.42.0.18|121.42.0.19") {
        #如果你的nginx安装了echo模块,还能如下输出语言,狠狠的发泄你的不满(但不兼容返回403,试试200吧)!
        #add_header Content-Type text/plain;
        #echo "son of a bitch,you mother fucker,go fuck yourself!";
        return 403;
        break;
}

把这个保存为 deny_ip.conf ,上传到 Nginx 的 conf 文件夹,然后在要生效的网站 server 模块中引入这个配置文件,并 Reload 重载 Nginx 即可生效:

#禁止某些用户访问
include deny_ip.conf;

如果再想添加其他要禁止的 IP,只需要编辑这个文件,插入要禁止的 IP,使用分隔符 | 隔开即可,记得每次修改都需要 reload 重载 Nginx才能生效。

更多方法也可以参考:

  • https://zhang.ge/5096.html