目录

Nginx动态编译GeoIP2模块

系列 - Security Config of Nginx

Nginx不支持pcre2, 另外Debian系Linux中, pcreopenssllib包名和其他系统不一样。

CentOS:

bash

sudo yum install pcre-devel openssl openssl-devel

Debian:

bash

sudo apt install libpcre3 libpcre3-dev libssl-dev

bash

sudo apt install libmaxminddb0 libmaxminddb-dev mmdb-bin

如果源仓库中没有libmaxminddb0libmaxminddb-devmmdb-bin中的某个包, Ubuntu可以通过添加PPA来解决:

bash

sudo add-apt-repository ppa:maxmind/ppa
sudo apt-get update 
sudo apt install libmaxminddb0 libmaxminddb-dev mmdb-bin

但PPA方式在Debian上不太好用, 可以先安装geoipupdate, geoipupdate包含了上面缺失的某个包。

安装geoipupdate, 推荐下载Release中的deb包, 而不是sudo apt install geoipupdate安装, 因为Release中的版本高于Debian仓库。关于geoipupdate的相关配置, 本文后面的geoipupdate配置会讲到。

实在不行可以从libmaxminddb的源码直接编译安装libmaxminddb0libmaxminddb-devmmdb-bin这3个包。

下载Nginx的源码包并解压:

bash

cd ~
wget http://nginx.org/download/nginx-1.22.1.tar.gz
tar -zxvf nginx-1.22.1.tar.gz

克隆仓库ngx_http_geoip2_module.git/usr/lib/nginx/modules/ngx_http_geoip2_module:

bash

git clone https://github.com/leev/ngx_http_geoip2_module.git /usr/lib/nginx/modules/ngx_http_geoip2_module

编译前使用nginx -V命令先看一下已安装的Nginx的参数作为参考, 输出类似:

nginx

nginx version: nginx/1.18.0
built with OpenSSL 1.1.1n  15 Mar 2022
TLS SNI support enabled
configure arguments: --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_sub_module

cd ~/nginx-1.22.1/, 运行以下命令配置编译参数:

bash

./configure --prefix=/usr/share/nginx \
--conf-path=/etc/nginx/nginx.conf \
--http-log-path=/var/log/nginx/access.log \
--error-log-path=/var/log/nginx/error.log \
--lock-path=/var/lock/nginx.lock \
--pid-path=/run/nginx.pid \
--modules-path=/usr/lib/nginx/modules \
--http-client-body-temp-path=/var/lib/nginx/body \
--http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
--http-proxy-temp-path=/var/lib/nginx/proxy \
--http-scgi-temp-path=/var/lib/nginx/scgi \
--http-uwsgi-temp-path=/var/lib/nginx/uwsgi \
--with-compat \
--with-debug \
--with-pcre-jit \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_realip_module \
--with-http_auth_request_module \
--with-http_v2_module \
--with-http_dav_module \
--with-http_slice_module \
--with-threads \
--with-http_addition_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_sub_module \
--with-stream \
--add-dynamic-module=/usr/lib/nginx/modules/ngx_http_geoip2_module

使用make命令编译, 编译完成的文件在~/nginx-1.22.1/objs/路径下。

不要make install

应先备份旧版本Nginx以防万一:

bash

sudo mv /usr/sbin/nginx ~/nginx_$(date +%F)

再将编译好的新版本替换上去:

bash

sudo cp ~/nginx-1.22.1/objs/nginx /usr/sbin/

看一下当前Nginx的参数nginx -V, 输出中应该已经包括--add-dynamic-module=/usr/lib/nginx/modules/ngx_http_geoip2_module

复制编译好的模块到指定位置, 以便后续在nginx.conf中引用:

bash

sudo cp ~/nginx-1.22.1/objs/ngx_http_geoip2_module.so /usr/lib/nginx/modules/
sudo cp ~/nginx-1.22.1/objs/ngx_stream_geoip2_module.so /usr/lib/nginx/modules/

参考官方文档, 创建License Keys, 下载GeoIP.conf保存到/etc/下, 创建crontab定时任务运行geoipupdate, 比如:

bash

0 3 * * 1 flock -xn /tmp/geoipupdate.lock -c '/usr/bin/geoipupdate > /dev/null 2>&1 &'
geoipupdate安装路径
安装路径不一定是官方说的/usr/local/bin/geoipupdate, 也可能是/usr/bin/geoipupdate

geoipupdate会将数据下载到/usr/share/GeoIP/路径下。

/etc/nginx/nginx.conf中引用ngx_http_geoip2_module.so和GeoLite2免费数据库 (这里用的是GeoLite2-Country.mmdb), 最终达到屏蔽来自海外连接, 且允许常见海外爬虫访问的效果。

nginx

...
load_module /usr/lib/nginx/modules/ngx_http_geoip2_module.so;
load_module /usr/lib/nginx/modules/ngx_stream_geoip2_module.so;
...
http {
    ...
    geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
        # 启用自动重载将使nginx在指定的时间间隔内检查数据库的修改时间, 并在数据库已更改时重新加载它。
        auto_reload 168h;
        $geoip2_metadata_country_build metadata last_check;
        $geoip2_data_country_code country iso_code;
    }
    map $geoip2_data_country_code $allowed_country {
        # 默认拒绝连接, 只允许来自中国的连接
        default no;
        CN yes;    
    }
    ...
    server {
        ...
        if ($allowed_country = no) {
           set $blocked A;
        }
        # 允许常见海外爬虫访问
        if ($http_user_agent !~* (bingbot|DuckDuckBot|Googlebot|YandexBot)) {
           set $blocked "${blocked}B";
        }
        # 来自海外的连接, 且不是允许的海外爬虫, 即拒绝连接
        if ($blocked = AB){
           return 444;
        }
        ...
    }
}