nginx通过配置文件阻止海外ip访问
1. 说明
因为最近发现有不少刷评论的脚本,在nginx请求日志里面看了眼,都是海外的ip,反正我的博客也是全中文。所以干脆把海外ip禁止artalk评论。
在/etc/nginx/nginx.conf中可以看到默认的日志路径,在里面能找到每一个转发的请求和其源IP。其中artak新增评论的请求是/api/add路径
| 1
 | access_log  /var/log/nginx/access.log  main;
 | 
考虑到添加海外ip屏蔽可能会阻止一些真的在国外的朋友,如果你在阅读本站博客时,遇到相关问题无法直接评论与我交流,可以移步github随便找个我的仓库开个issue提问!
2. APNIC介绍
后文出现的网站是来自APNIC (Asia Pacific Network Information Center),其是IP地址管理机构之一,负责亚洲、太平洋地区。
| 12
 3
 4
 
 | APNIC提供了每日更新的亚太地区IPv4,IPv6,AS号分配的信息表:http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest
 该文件的格式与具体内容参见:
 http://ftp.apnic.net/pub/apnic/stats/apnic/README.TXT
 
 | 
3. 解决问题
3.1. 获取海外IP并进行屏蔽
初步解决方法参考:https://www.cnblogs.com/guoyabin/p/14263732.html
原博主提供的脚本如下,可以下载所有海外ip列表并生成一个nginx配置,写入/etc/nginx/blackip.conf中
| 12
 3
 4
 5
 6
 
 | #!/bin/bashrm -f legacy-apnic-latest black_`date +%F`.conf && wget http://ftp.apnic.net/apnic/stats/apnic/legacy-apnic-latest
 
 awk -F '|' '{if(NR>2)printf("%s %s/%d%s\n","deny",$4,24,";")}' legacy-apnic-latest > black_`date +%F`.conf && \
 rm -f /etc/nginx/blackip.conf && \
 ln -s $PWD/black_`date +%F`.conf /etc/nginx/blackip.conf
 
 | 
脚本执行后的效果如下
| 12
 3
 
 | [root@bt-7274:/etc/nginx]# lltotal 88
 lrwxrwxrwx 1 root root   34 Dec  9 16:03 blackip.conf -> /root/docker/black_2023-12-09.conf
 
 | 
文件内容如下
| 12
 3
 4
 5
 6
 7
 
 | [root@bt-7274:/etc/nginx/conf.d]# cat ../blackip.confdeny 128.134.0.0/24;
 deny 128.184.0.0/24;
 deny 128.250.0.0/24;
 deny 129.60.0.0/24;
 deny 129.78.0.0/24;
 ...后面的省略了
 
 | 
参考原博主的做法,你可以将这个blackip.conf在/etc/nginx/nginx.conf中的http模块里面include,这样会阻止当前服务器所有反代的海外的请求。
| 1
 | include /etc/nginx/blackip.conf;
 | 
还可以在单个配置文件的location里面引用
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 |   location / {proxy_redirect off;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_set_header Host $host;
 proxy_set_header Upgrade-Insecure-Requests 1;
 proxy_set_header X-Forwarded-Proto https;
 
 include /etc/nginx/blackip.conf;
 
 proxy_pass http://127.0.0.1:14722;
 }
 
 | 
修改后重启nginx,没有报错就是ok了
用海外的服务器试试能不能请求artalk,用artk.musnow.top/sidebar/…这个管理员登录页面来进行测试。
国内服务器请求结果如下,和浏览器打开的结果基本是一样(管理员登录界面)
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | [root@bt-7274:/etc/nginx/conf.d]# curl https://artk.musnow.top/sidebar/#/login<!DOCTYPE html>
 <html>
 <head>
 <meta charset="UTF-8" />
 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 <title>Artalk Sidebar</title>
 <script type="module" crossorigin src="./assets/index-5a0b3a93.js"></script>
 <link rel="stylesheet" href="./assets/index-84fdcf98.css">
 </head>
 <body>
 <div id="app"></div>
 
 </body>
 </html>
 
 | 
海外服务器请求结果也是上面这样……然后发现是因为我的海外服务器ip压根不在那个black的deny列表里面,说明列表内容不全。
尝试把海外服务器的ip的网段给加进去,重启nginx再试试。完美处理!添加前能正常请求到,添加后就变成403了。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | [root@RainYun-8aNbbsmA:~]# curl https://artk.musnow.top/sidebar/#/login<!DOCTYPE html>
 <html>
 <head>
 <meta charset="UTF-8" />
 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 <title>Artalk Sidebar</title>
 <script type="module" crossorigin src="./assets/index-5a0b3a93.js"></script>
 <link rel="stylesheet" href="./assets/index-84fdcf98.css">
 </head>
 <body>
 <div id="app"></div>
 
 </body>
 </html>
 [root@RainYun-8aNbbsmA:~]#
 [root@RainYun-8aNbbsmA:~]# curl https://artk.musnow.top/sidebar/#/login
 <html>
 <head><title>403 Forbidden</title></head>
 <body>
 <center><h1>403 Forbidden</h1></center>
 <hr><center>nginx/1.20.1</center>
 </body>
 </html>
 [root@RainYun-8aNbbsmA:~]#
 
 | 
3.2. 只放通国内IP
我前文提到了我的海外服务器的ip不在这个deny的ip列表里面,没有被屏蔽。说明这个博主提供的脚本虽然逻辑上是对的,但是下载到的文件中的海外IP并不完整。
考虑到网上搜不到legacy-apnic-latest文件存放的到底是什么ip的信息,我决定换一个思路:allow允许国内的ip,deny拒绝所有非国内的ip。
获取国内ip列表 https://www.cnblogs.com/sentangle/p/13201770.html
下面这个url里面的ip地址标明了地区,我们只需要将其提取出来即可
| 1
 | http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest
 | 
这个文件里面的内容结构如下
| 1
 | 等级机构|获得该IP段的国家/组织|资源类型|起始IP|IP段长度|分配日期|分配状态
 | 
我们只需要提取CN的所有IP,然后允许他们,再deny all阻止其他ip就可以了
| 12
 3
 4
 5
 6
 7
 8
 
 | #!/bin/bashrm -f delegated-apnic-latest blackcn_`date +%F`.conf;
 wget http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest
 
 awk -F\| '/CN\|ipv4/ { printf("%s %s/%d%s\n","allow",$4, 32-log($5)/log(2), ";") }' delegated-apnic-latest > blackcn_`date +%F`.conf;
 rm -f /etc/nginx/blackcn.conf;
 ln -s $PWD/blackcn_`date +%F`.conf /etc/nginx/blackcn.conf;
 
 
 | 
执行这个脚本后,会生成/etc/nginx/blackcn.conf文件
| 12
 3
 4
 
 | [root@bt-7274:/etc/nginx]# lltotal 88
 lrwxrwxrwx 1 root root   42 Dec  9 16:54 blackcn.conf -> /root/docker/nginx/blackcn_2023-12-09.conf
 lrwxrwxrwx 1 root root   40 Dec  9 16:56 blackip.conf -> /root/docker/nginx/black_2023-12-09.conf
 
 | 
内容如下
| 12
 3
 4
 5
 6
 7
 
 | allow 223.248.0.0/14;allow 223.252.128.0/17;
 allow 223.254.0.0/16;
 allow 223.255.0.0/17;
 allow 223.255.236.0/22;
 allow 223.255.252.0/23;
 ....
 
 | 
还是修改nginx单个站点配置文件的location中的内容
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 |   location / {proxy_redirect off;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_set_header Host $host;
 proxy_set_header Upgrade-Insecure-Requests 1;
 proxy_set_header X-Forwarded-Proto https;
 
 include /etc/nginx/blackcn.conf;
 deny all;
 
 proxy_pass http://127.0.0.1:14722;
 }
 
 | 
先来试试不修改配置文件(不做任何deny和allow操作的情况下)海外ip请求结果,符合预期,正常请求出了登录页面的html文件。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | [root@RainYun-8aNbbsmA:~]# curl https://artk.musnow.top/sidebar/#/login<!DOCTYPE html>
 <html>
 <head>
 <meta charset="UTF-8" />
 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 <title>Artalk Sidebar</title>
 <script type="module" crossorigin src="./assets/index-5a0b3a93.js"></script>
 <link rel="stylesheet" href="./assets/index-84fdcf98.css">
 </head>
 <body>
 <div id="app"></div>
 
 </body>
 </html>
 
 | 
添加如上配置文件的修改后,重启nginx,再次进行测试。这一次海外的请求已经403阻止了,完美!
| 12
 3
 4
 5
 6
 7
 8
 
 | [root@RainYun-8aNbbsmA:~]# curl https://artk.musnow.top/sidebar/#/login<html>
 <head><title>403 Forbidden</title></head>
 <body>
 <center><h1>403 Forbidden</h1></center>
 <hr><center>nginx/1.20.1</center>
 </body>
 </html>
 
 | 
4. 1panel的OpenResty应用此操作
如果是1panel安装的OpenResty,也可以用这种方式来屏蔽海外IP。默认状态下站点文件的配置文件在宿主机上是如下路径
| 1
 | /opt/1panel/apps/openresty/openresty/www/sites
 | 
在这个路径里面可以看到你在1panel里面添加的的所有网站,进入对应网站的目录,再进入proxy目录。 在proxy目录里面可以看到每一个路径的配置文件,参考上文所述,修改配置文件就可以了。
| 1
 | /opt/1panel/apps/openresty/openresty/www/sites/网站域名/proxy
 | 
在1panel前台,网站的每个反代的配置文件中也能直接编辑原文。

但是如果直接使用上文的配置,点击保存的时候会出现如下报错。报错的重点是找不到我们要添加的/etc/nginx/black.conf文件(No such file or directory 文件不存在)。

1panel上的网站配置基于openresty的docker容器,可以在openresty的docker容器配置中找到如下的目录绑定项(宿主机和openresty容器内的目录映射)
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | "Binds": ["/etc/localtime:/etc/localtime:rw",
 "/opt/1panel/apps/openresty/openresty/log:/var/log/nginx:rw",
 "/opt/1panel/apps/openresty/openresty/conf/conf.d:/usr/local/openresty/nginx/conf/conf.d:rw",
 "/opt/1panel/apps/openresty/openresty/conf/fastcgi-php.conf:/usr/local/openresty/nginx/conf/fastcgi-php.conf:rw",
 "/opt/1panel/apps/openresty/openresty/www:/www:rw",
 "/opt/1panel/apps/openresty/openresty/root:/usr/share/nginx/html:rw",
 "/opt/1panel/apps/openresty/openresty/1pwaf/data:/usr/local/openresty/1pwaf/data:rw",
 "/opt/1panel/apps/openresty/openresty/conf/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf:rw",
 "/opt/1panel/apps/openresty/openresty/conf/fastcgi_params:/usr/local/openresty/nginx/conf/fastcgi_params:rw"
 ]
 
 | 
其中比较重要的是这一条
| 1
 | /opt/1panel/apps/openresty/openresty/conf/conf.d:/usr/local/openresty/nginx/conf/conf.d:rw
 | 
我们需要将blackcn.conf文件移动到/opt/1panel/apps/openresty/openresty/conf/conf.d目录里面,才能被容器内的nginx读取到。注意必须移动或者复制文件,不能使用文件连接!因为文件连接之后的绝对路径还是宿主机的路径,容器内无法正常访问到文件!
移动了文件到该目录之后,对应location中的的nginx配置文件如下:
| 12
 3
 
 |    include conf.d/blackcn.conf;
 deny all;
 
 | 
在nginx的配置文件中,conf.d/blackcn.conf这种没有写绝对路径的方式,nginx都会从自己的配置文件目录开始找,也就是openresty容器内的/usr/local/openresty/nginx/conf/目录。而该目录下只有/usr/local/openresty/nginx/conf/conf.d目录被映射到了容器外,所以要借助这个目录配置我们的文件。
点击1panel配置编辑中的保存,保存成功了就是校验ok了。

可以用上文提到的办法测试一下是否生效。生效的话,得到的结果应该是403状态码。
| 12
 3
 4
 5
 6
 7
 8
 
 | $ curl https://artk.musnow.top/sidebar/#/login<html>
 <head><title>403 Forbidden</title></head>
 <body>
 <center><h1>403 Forbidden</h1></center>
 <hr><center>openresty</center>
 </body>
 </html>
 
 | 
5. The end
你可以写个crontab让其定时执行脚本并重启nginx,我个人还是选择人工处理了(什么时候想起来就去更新一下ip列表)
感谢本文中出现的博客的博主。没有他们的帮助,我无法编写出shell脚本。