nginx批量封禁黑名单ip
所以之前我们手动处理的策略是:
(1)把甲方给来的所有文件 IP 数汇总成一个文件(给来的文件会有中文,然后每个 IP 为一行),然后排序、去重
(2)对 IP 进行分割,阿里、电信用英文逗号,联通是空行
二、问题解决
甲方要我们封禁,不一定要用云厂商的防火墙,封禁可以从操作系统、nginx去处理。试过操作系统的 iptables,没有效果,估计跟防火墙、云安全组的配置有点关系,因为赶着处理,所以决定从nginx出发。
注意,这里不能直接在location 写 deny,allow,因为服务器前面是防火墙,你这样添加来源都是防火墙的IP。我们应该从真实客户端 IP 去出发。可以通过 nginx 的 X-Forwarded-For 来识别原始请求者的真实 IP 地址,然后提取出第一个 IP 地址,并将其存储在变量 $real_remote_addr,最后定义一个名为
$access_check
的变量映射,用于根据 $real_remote_addr
来决定是否允许或拒绝访问。
下面是nginx配置文件片段
1 nginx配置文件nginx.conf,有配置: 2 3 http { 4 ... 5 map $http_x_forwarded_for $real_remote_addr { 6 "" $remote_addr; 7 ~^(?P<firstAddr>[0-9\.]+),?.*$ $firstAddr; 8 } 9 10 map $real_remote_addr $access_check { 11 default "allow"; 12 "xxx" "deny"; 13 } 14 ... 15 } 16 17 18 然后虚拟主机配置文件,有配置 19 server 20 ... 21 location / { 22 if ($access_check = "deny") { 23 return 403; 24 } 25 } 26 ... 27 }
之前 IP 少的时候,我是直接添加 "xxx" "deny"; 但如果几千上万的话呢,一会导致文件不好看(密密麻麻的 IP 铺排整个nginx主配置文件),二会维护成本高,于是我问chatgpt,希望以文件方式存储需要封禁 的 黑名单 IP,然后nginx去加载。
分享链接如下:https://chatgpt.com/share/dbdb364f-7931-4def-ba98-5f7600e1c372
后面就是它给的参考代码,我直接贴上来,其中需要设置 map 的空间大小参数,不然添加不了那么多IP,而且设置的位置也有考究,具体参考文档:nginx: [emerg] “map_hash_bucket_size” directive is duplicate in /etc/nginx/nginx.conf:60
前面说到需要对原始 IP 进行处理:排序、去重,然后有个数据库存着到当前为止甲方给来的所有 IP,对于新增 IP,我们需要先看下是否在数据库存在过,不存在需要插入数据库,最后会得到一个处理好的 blocked_ips.conf,格式如下:(这是开发帮忙弄的,感激感激~~)
我只需要加载这个nginx文件,做相应的配置就行。后续说是开发的程序把处理好的文件放到oss上,服务器定时拉取这个文件,重新加载nginx。
1、nginx主配置文件 nginx.conf
1 http { 2 ... 3 ## map 指令生成的哈希表需要更多的空间来存储映射关系 4 ## 放在 map $http_x_forwarded_for 前设置 5 map_hash_max_size 2048; 6 map_hash_bucket_size 2048; 7 8 map $http_x_forwarded_for $real_remote_addr { 9 "" $remote_addr; 10 ~^(?P<firstAddr>[0-9\.]+),?.*$ $firstAddr; 11 } 12 13 include /path/blocked_ips.conf; 14 ... 15 }
2、虚拟主机配置文件
server{ ... location / { if ($access_check = "deny") { return 403; } proxy_pass http://后端服务; ... error_page 404 403 /haha_404; location ~* /haha_404 { root /path; index index.html; } }
最后我贴下 chatgpt 的脚本 generate_nginx_conf.sh
blocked_ips.txt 是一个你去重完的 ip 文件,格式是
1.11.11.11 192.168.1.100 10.0.0.1 ...
generate_nginx_conf.sh
1 #!/bin/bash 2 3 # 定义输入和输出文件路径 4 INPUT_FILE="blocked_ips.txt" 5 OUTPUT_FILE="blocked_ips.conf" 6 7 # 初始化输出文件 8 echo "map \$real_remote_addr \$access_check {" > $OUTPUT_FILE 9 echo " default \"allow\";" >> $OUTPUT_FILE 10 11 # 读取输入文件并生成输出文件内容 12 while IFS= read -r ip 13 do 14 echo " \"$ip\" \"deny\";" >> $OUTPUT_FILE 15 done < "$INPUT_FILE" 16 17 # 关闭 map 块 18 echo "}" >> $OUTPUT_FILE
实际就是把 ip 文件变成 这种方式:
map $real_remote_addr $access_check {
default "allow";
"被封禁 IP" "deny";
"被封禁 IP-2" "deny";
}