YOLO813

Web服务器Nginx通过GeoIP实现禁止区域IP访问

环境介绍

    服务器:

Linux VM-20-14-centos 4.18.0-305.10.2.el8_4.x86_64 #1 SMP Tue Jul 20 17:25:16 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

    Nginx环境

/usr/local/nginx/sbin/nginx -V


    我们需要ngx_http_geoip2_module,但是现在nginx并不存在该模块,所以需要重新编译,可以参考我之前的文章-Nginx构建高可用集群,实现负载均衡应对高并发 来重新编译nginx。

    先来安装下ngx_http_geoip2_module,前往github(链接下方参考)自行下载解压即可,我放在如下目录中

/opt/ngx_http_geoip2_module-master
cd nginx-1.18.0/
./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --add-dynamic-module=/opt/ngx_http_geoip2_module-master

配置如果报错如下:

error: the geoip2 module requires the maxminddb library.

说明需要安装libmaxminddb,很多网络教程使用如下方法:

yum install libmaxminddb libmaxminddb-devel -y

    我实测是不行的(2021年12月15),按照这个报错日志打开链接是一个paypal付费链接,也就是这个库需要付费(订阅!)才能使用


    在互联网找到解决办法

wget https://github.com/maxmind/libmaxminddb/releases/download/1.3.2/libmaxminddb-1.3.2.tar.gz
tar -xzf libmaxminddb-1.3.2.tar.gz
cd libmaxminddb-1.3.2
./configure
make
make check
sudo make install
sudo ldconfig

    完成之后再进行配置就可以了。

    编译、备份、拷贝,可以看到成功添加了模块

make
# 备份
cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak
# 停止nginx -cannot create regular file '/usr/local/nginx/sbin/nginx': Text file busy
systemctl stop nginx.service
# 拷贝至nginx的二进制目录下
cp objs/nginx /usr/local/nginx/sbin/
# 再次查看安装情况
/usr/local/nginx/sbin/nginx -V

    此时,可以发现在objs目录下面还生成了一个ngx_http_geoip2_module.so文件,记住这个文件的目录

/usr/src/nginx-1.18.0/objs/ngx_http_geoip2_module.so


    接下来还需要下载城市和国家的IP,可以参考关于http网站包装ssl和https网站日志可视化,前往maxmind官网下载数据库,我下载了GeoLite2-City_20211214.tar.gz和GeoLite2-Country_20211214.tar.gz两个文件,
    在nginx的配置文件第一行,增加如下代码(加载刚刚生成的so文件)

load_module /usr/src/nginx-1.18.0/objs/ngx_http_geoip2_module.so;

http 段添加如下代码

geoip2 /opt/GeoLite2-Country_20211214/GeoLite2-Country.mmdb {
  auto_reload 5m;
  $geoip2_metadata_country_build metadata build_epoch;
  $geoip2_data_country_code default=US  country iso_code;
  $geoip2_data_country_name country names en;
}

server 段添加如下代码:

if ($geoip2_data_country_code = "AK") {
    return 403;
}

    关于各国的国家代码放在下方的参考链接中。
    至此,所有该地区的用户均无权访问该网站!

 

    解释:其实就是通过geoip2加载国家数据库GeoLite2-Country.mmdb,通过分析用户的ip,然后生成了几个变量,如geoip2_data_country_code (国家代码),默认为美国US,geoip2_data_country_name(国家名称)默认会在英文名称en的IP库中寻找(PS:可以修改成zh-CN试试,返回的将是UTF8的十六进制编码,例如“\xE4\xB8\xAD\xE5\x9B\xBD”),在下方的server段,只要国家代码符合,我统一返回403。


     上面我不是还下载了城市数据库GeoLite2-City.mmdb嘛,其实还可以分的更细致点,或者其它的玩法,例如在访问日志log中打印出来访者的地区代码和城市。

    http段添加如下代码

geoip2 /opt/GeoLite2-City_20211214/GeoLite2-City.mmdb {
   $geoip2_data_city_name default=London city names en;
}

    更改nginx的默认log_format

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent" "$http_x_forwarded_for" "$geoip2_data_country_code" "$geoip2_data_city_name"';

    再次跟踪访问日志,可以看到好玩的事出现了,日志里面直接打印出了所在国家和城市


    需要注意的是,因为是免费的地理位置数据库,难免有些IP没有记录(主要是城市),如果在测试的时候发现geoip2_data_city_name 这个变量一直打印不出来或者显示默认名称,不一定是代码出错,可以考虑换一个IP进行测试。

 

 

参考:

https://blog.csdn.net/baidu_38432732/article/details/90268625
# ngx_http_geoip2_module
https://github.com/leev/ngx_http_geoip2_module
# 解决libmaxminddb付费问题
https://github.com/leev/ngx_http_geoip2_module/issues/10
https://www.maxmind.com/en/accounts/520549/geoip/downloads
https://www.cnblogs.com/faberbeta/p/nginx_geoip2.html
# 关于各国国家代码简写
https://dev.maxmind.com/geoip/legacy/codes