Nginx 加载 GeoIP2 模块,按访客 IP 归属地限制访问

网站被某些地区的垃圾请求刷屏时,比起在应用层判断,Nginx 直接按访客 IP 归属地放行或拒绝更省资源。GeoIP2 模块负责把 IP 解析成国家、省市,再配合规则做限制,配置完成后命中限制的访客直接收到 403。

403_01

GeoIP2 是什么

GeoIP2 是 MaxMind 提供的 IP 地址归属地查询服务的产品系列之一。GeoIP2 模块运行在 Nginx 上,用 MaxMind 的 GeoIP2 数据库识别客户端 IP,按国家、省、市和网络运营商等信息对 HTTP 请求做筛选和限制。典型用法:限制特定国家或地区的访问、拦截匿名代理和 TOR 网络的访问、限制特定运营商、拦截已知恶意 IP。

数据库分五个:GeoLite2 Country(国家位置和国家代码)、GeoLite2 City(城市位置、邮政编码、所在州和国家代码)、GeoLite2 ASN(自治系统信息)、GeoLite2 Connection Type(连接类型,例如 Cable/DSL)、GeoLite2 Domain Name(IP 所属域名)。做地域访问控制,用 Country 和 City 两个库就够。

装模块前的准备

先看 Nginx 已经加载了什么模块。rpm 包安装的直接执行:

nginx -V

源码编译安装的,假如装在 /usr/local/nginx,用完整路径:

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

注意是大写的 V。然后装依赖库 libmaxminddb。EL 是 Enterprise Linux 的缩写,对应 RHEL 的版本号:

yum -y install https://repo.aerisnetwork.com/pub/aeris-release-`rpm -E %rhel`.rpm
# EL 7
yum install -y libmaxminddb libmaxminddb-devel ccache libxml2-devel libxslt-devel GeoIP-devel

# EL 89
dnf install -y libmaxminddb libmaxminddb-devel ccache libxml2-devel libxslt-devel

# 安装整个开发工具组
dnf groupinstall "Development Tools

模块源码单独建目录存放,编译时再引用:

[root@localhost ~]# mkdir -p /opt/nginx/geoip2 && cd $_
[root@localhost geoip2]# git clone https://github.com/leev/ngx_http_geoip2_module.git

编译动态模块

先下载与当前 Nginx 版本一致的源码包,版本对不上会导致模块无法正常工作,只能重新编译:

# 查看当前使用的Nginx版本
[root@localhost ~]# NG_VER=$(nginx -v 2>&1 | awk -F "/" '{ print $2 }')
[root@localhost ~]# echo ${NG_VER}
1.24.0

# 下载对应的版本的nginx源码包到服务器上
[root@localhost ~]# wget https://nginx.org/download/nginx-${NG_VER}.tar.gz
[root@localhost ~]# tar -xf nginx-${NG_VER}.tar.gz

用 configure 编译动态模块有个硬性前提:原 Nginx 编译时带过 --with-compat(动态编译)参数,否则编出来的动态模块加载不了。这种情况下只能把原机器 configure 的完整参数原样抄出来,再追加 --add-dynamic-module=/path/to/module。从 nginx -V 里抽旧参数可以这么干:

# 通过下面的命令查看当前Nginx安装的模块,然后通过sh快速执行
[root@localhost ~]# nginx -V 2>&1 | grep configure | sed -e 's/^configure arguments: //' -e 's/ --add-module.*$//' -e 's/ --add-dynamic-module.*$//' > /tmp/nginx_build_options.txt

[root@localhost ~]# cd nginx-${NG_VER}

[root@localhost nginx-1.24.0]# sh -c "./configure $(< /tmp/nginx_build_options.txt) --add-dynamic-module=/opt/nginx/geoip2/ngx_http_geoip2_module"

构建只跑 make modules。已有 Nginx 的环境千万别顺手 make install,会覆盖原来的所有信息:

make modules
ls objs/*.so
403_02

把生成的 .so 拷进模块目录。下面这个路径是 rpm/yum 安装自动生成的模块存储位置,源码安装的 nginx 需要自己定:

cp objs/*.so /usr/lib64/nginx/modules/

在 /etc/nginx/nginx.conf 里加载两个模块:

vi /etc/nginx/nginx.conf

# Maxmind GeoIP2
load_module "/usr/lib64/nginx/modules/ngx_http_geoip2_module.so";
load_module "/usr/lib64/nginx/modules/ngx_stream_geoip2_module.so";
403_03

配置 IP 地址库

mmdb 数据库文件到 MaxMind 官网下载,放到 /usr/share/GeoIP2 目录(没有则创建),解压、归位、清掉压缩包、授权给 nginx 运行用户:

[root@localhost ~]# mkdir -p /usr/share/GeoIP2 && cd $_
[root@localhost GeoIP2]# tar -xf GeoLite2-City_20250715.tar.gz
[root@localhost GeoIP2]# tar -xf GeoLite2-Country_20250715.tar.gz

# 将解压目录下的.mmdb文件移动到当前目录下
[root@localhost GeoIP2]# mv GeoLite2-City_20250715/GeoLite2-City.mmdb ./
[root@localhost GeoIP2]# mv GeoLite2-Country_20250715/GeoLite2-Country.mmdb ./

# 删除其他不需要的文件
[root@localhost GeoIP2]# rm -rf *.gz *_*

# 授权给nginx运行用户
[root@localhost GeoIP2]# chown -R nginx. /usr/share/GeoIP2/

nginx.conf 里把库绑定成变量。Country 库开了 auto_reload 5m,Nginx 会按间隔检查数据库文件的修改时间,变了自动重载;City 库映射出国家、城市、省份等多个变量:

[root@localhost GeoIP2]# vi /etc/nginx/nginx.conf
    # geoip 模块变量绑定
    geoip2 /usr/share/GeoIP2/GeoLite2-Country.mmdb {
        # 启用自动重新加载将使 nginx 以指定的时间间隔检查数据库的修改时间,如果发生更改则重新加载。
        auto_reload 5m;
        $geoip2_country_code country names en;
    }
    geoip2 /usr/share/GeoIP2/GeoLite2-City.mmdb {
        $geoip2_data_country_name country names en;
        $geoip2_data_country_code default=China source=$remote_addr country iso_code;
        $geoip2_data_city_name city names en;
        $geoip2_data_province_name subdivisions 0 names en;
        $geoip2_data_province_isocode subdivisions 0 iso_code;
        $geoip2_continent_code continent code;
    }

再加一个测试用的 location,把这些变量原样回显:

[root@localhost GeoIP2]# vi /etc/nginx/conf.d/default.conf
    # 该路径显示当前请求访问地址信息
    location = /info {
       default_type text/plain;
       return 200 "$remote_addrn geoip2_country_code=$geoip2_country_coden geoip2_data_country_name=$geoip2_data_country_name n geoip2_data_country_code=$geoip2_data_country_code n geoip2_data_city_name=$geoip2_data_city_name n geoip2_continent_code=$geoip2_continent_code n geoip2_data_province_name=$geoip2_data_province_name n geoip2_data_province_isocode=$geoip2_data_province_isocode";
    }

验证与使用

站点地址后面跟 /info 访问,返回结果里能看到当前 IP 对应的国家和省市字段,说明 GeoIP2 模块生效、能正确识别 IP 数据库:

403_06

确认变量正常后,就可以在其他 location 里用 $geoip2_data_country_code 这类变量写拒绝访问的规则,实现按地区限制。数据库文件不会实时跟官方更新,隔段时间换一版即可,替换文件后不用重启 Nginx。

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容