Nginx增加基于地理位置的日志和限制

需求

如标题所说,有两个需求,一个是在日志里记录客户端的粗略地理位置(比如精确到国家),一个是对某些地理位置的客户加以限制(比如拒绝来自中国大陆的请求免得给自己带来麻烦)。

地理日志

此功能依赖Nginx的geoip模块。一般文档都说需要编译Nginx,加上--with-http_geoip_module选项,不过如果要求不高的话,我试了一下用动态模块也可以。

apt install -y libnginx-mod-http-geoip

然后修改Nginx的配置文件,在http段里加入:

http {
    ....
    geoip_country /usr/share/GeoIP/GeoIP.dat;
    ....
}

其中/usr/share/GeoIP/里的IP地理数据库是来自于geopip-database这个软件包(被libnginx-mod-http-geoip依赖而自动安装)。当然还有更准确的第三方数据,比如MaxMind,但那个就需要收费了,而且用的是GeoIP2格式。

现在就可以在log_format里使用geoip_country_code变量来把国家代码记录到日志里,比如可以用于ELK或PLG中的日志分析。

地理限制

跟日志一样依赖geoip模块,限制的方式跟以前这篇《在nginx中限制某些agent的访问》说的方法一样:

先建一个全局的map:

map $geoip_country_code $deny_country {
    default    0;
    CN    1;
}

再在相应的server配置里加上:

if ($deny_country) {
    return 404;
}

即可。

补充:CDN问题

配置完发现新问题:如果用了CDN就不行了,因为这里的地理信息都是基于客户端IP的,但是在CDN后面的话,客户端的IP是CDN的服务器地址,结果全不对了。

解决方法当然是有的,那就是用realip模块——这个就不用装了,默认一般都编译在内,如果你的nginx没有,那就只能自己编译一个了,加上--with-http_realip_module 选项。

主要的配置就两句:

set_real_ip_from  173.245.48.0/20;
real_ip_header    CF-Connecting-IP;

其中173.245.48.0/20这个是CDN的服务器地址,可能有多个,比如CloudFlare的地址列表见官网

CF-Connecting-IP是CloudFlare提供的请求头参数,记录真实的客户端IP。

这两个配置可以全局,也可以配置在server段里,配置过后Nginx就会对所有来自CDN服务器的请求使用指定的请求头参数作为客户端IP,这样地理信息就对了——顺便日志里记录的客户端IP也会是对的。

推送到[go4pro.org]