Nginx动态编译GeoIP2模块
1 依赖
1.1 pcre和openssl
Nginx不支持pcre2, 另外Debian系Linux中, pcre
和openssl
的lib
包名和其他系统不一样。
CentOS:
sudo yum install pcre-devel openssl openssl-devel
Debian:
sudo apt install libpcre3 libpcre3-dev libssl-dev
1.2 MaxMind
sudo apt install libmaxminddb0 libmaxminddb-dev mmdb-bin
如果源仓库中没有libmaxminddb0
、libmaxminddb-dev
、mmdb-bin
中的某个包, Ubuntu可以通过添加PPA来解决:
sudo add-apt-repository ppa:maxmind/ppa
sudo apt-get update
sudo apt install libmaxminddb0 libmaxminddb-dev mmdb-bin
但PPA方式在Debian上不太好用, 可以先安装geoipupdate, geoipupdate
包含了上面缺失的某个包。
1.2.1 GeoIP Update
安装geoipupdate
, 推荐下载Release中的deb
包, 而不是sudo apt install geoipupdate
安装, 因为Release中的版本高于Debian仓库。关于geoipupdate
的相关配置, 本文后面的geoipupdate配置会讲到。
实在不行可以从libmaxminddb的源码直接编译安装libmaxminddb0
、libmaxminddb-dev
、mmdb-bin
这3个包。
2 编译
下载Nginx的源码包并解压:
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
:
git clone https://github.com/leev/ngx_http_geoip2_module.git /usr/lib/nginx/modules/ngx_http_geoip2_module
编译前使用nginx -V
命令先看一下已安装的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/
, 运行以下命令配置编译参数:
./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/
路径下。
应先备份旧版本Nginx以防万一:
sudo mv /usr/sbin/nginx ~/nginx_$(date +%F)
再将编译好的新版本替换上去:
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
中引用:
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/
3 配置
3.1 geoipupdate配置
参考官方文档, 创建License Keys, 下载GeoIP.conf保存到/etc/
下, 创建crontab
定时任务运行geoipupdate
, 比如:
0 3 * * 1 flock -xn /tmp/geoipupdate.lock -c '/usr/bin/geoipupdate > /dev/null 2>&1 &'
/usr/local/bin/geoipupdate
, 也可能是/usr/bin/geoipupdate
。geoipupdate
会将数据下载到/usr/share/GeoIP/
路径下。
3.2 Nginx配置
在/etc/nginx/nginx.conf
中引用ngx_http_geoip2_module.so
和GeoLite2免费数据库 (这里用的是GeoLite2-Country.mmdb
), 最终达到屏蔽来自海外连接, 且允许常见海外爬虫访问的效果。
...
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;
}
...
}
}