问题描述
我们需要屏蔽来自国外的站点访问,不单纯是屏蔽某个地址,而是屏蔽所有来自国外的访问。
该笔记将记录:在 Nginx 中,如何屏蔽来自某个国家的访问,以及常见问题的解决方法。
解决方案
通过 GeoIP 数据库,以及 Nginx GeoIP Module,能够屏蔽或限制国家或地区的访问:
原理简述
1)GeoIP 数据库文件由 MAXMIND 提供,该数据库文件包含 IP 地址及其所属地域;
2)Nginx GeoIP Module 通过读取该数据库文件,Nginx 将获得访客 IP 转化得到地域信息;
3)最后,我们再配置 if {} 等等判断,来限制访问;
GeoIP Module vs. GeoIP2 Module
早期 GeoIP 数据库文件为 .dat 格式,Nginx GeoIP Module 能够读取该格式的文件,这也是 Nginx 内置模块(无需单独安装)。
现在(06/02/2021)官方已不提供 .dat 格式的数据文件,仅提供 .mmdb 和 CSV 格式的数据文件(参考 Retirement of GeoIP Legacy Downloadable Databases in May 2022 | MaxMind Blog 文章,以获取相关原因及说明),需要使用 Nginx GeoIP2 Module 来读取该格式的数据库文件,但是 Nginx GeoIP2 Module 需要编译安装(在 Ubuntu 20 中,能够 APT 安装)。
或者,需要使用 sherpya/geolite2legacy: MaxMind GeoLite2 (CSV) to Legacy format converter 进行文件的转化(.mmdb ⇒ .dat)。不过已有人完成这项工作,访问 GeoIP Legacy Databases 下载 Maxmind – Country/IPv4 和 Maxmind – City/IPv4 的 .dat 数据文件,然后解压即可使用。
Nginx + GeoIP Module(废弃)
第一步、启用 GeoIP 模块
安装 GeoIP 模块:
# Ubuntu 20.04 apt-get install libnginx-mod-http-geoip libnginx-mod-stream-geoip # Ubuntu 18.04 apt-get install libnginx-mod-http-geoip
检查模块已启用:
# nginx -V 2>&1 | grep --only-matching --color -- --with-http_geoip_module --with-http_geoip_module
第二步、下载 GeoIP 数据库
访问 GeoIP Legacy Databases 下载 Maxmind – Country/IPv4 和 Maxmind – City/IPv4 的 .dat 数据文件
第三步、修改 Nginx 配置
添加 GeoIP 数据库文件:
http { ... geoip_country /path/to/country.dat; geoip_city /path/to/city.dat; ... server { ... # 屏蔽中国以外的全部国家 if ($geoip_city_country_code != CN) { return 444; } ... } }
第四步、访问站点以验证
使用海外主机和国内主机访问该站点,判断配置是否成功。
补充说明
GeoIP 的准确性取决于数据库:在我们的实验环境中,MaxMind 的数据库定位比较准确,但是 DB-IP 的定位还是有所偏差。
这里仅演示在 http {} 中使用 GeoIP 的示例。而在 steam {} 中使用 GeoIP 是类似的(或许需要自行编译 GeoIP 模块)。
下面是我们的 GeoIP 配置:
http { ... geoip_country /etc/nginx/geoip/20210607/maxmind4-country.dat; geoip_city /etc/nginx/geoip/20210607/maxmind4-city.dat; map "$geoip_city_country_name $geoip_city" $allowed_city { default NO; "China Hangzhou" YES; "China Beijing" NO; } ... server { ... if ($allowed_city = NO) { return 444; } ... } }
Nginx + GeoIP2 Module(推荐)
Restricting Access by Geographical Location | NGINX Plus
GitHub – leev/ngx_http_geoip2_module: Nginx GeoIP2 module
Add the GeoIP2 module to NGINX.. A simple guide to add the GeoIP2 module… | by Maxime Durand | Medium
与 GeoIP Module类似,GeoIP2 Module 是对 mmdb 的支持,所以不再需要 GeoIP 模块。
第一步、启用 GeoIP 模块
安装 GeoIP 模块:
# Ubuntu 20.04 apt-get install libnginx-mod-http-geoip2 libnginx-mod-stream-geoip2 # 其他场景或许需要自行编译 # 参考文档:https://github.com/leev/ngx_http_geoip2_module/blob/master/README.md # 检查模块已启用: nginx -V 2>&1 | grep -i --color -- geoip2
第二步、下载 GeoIP2 数据库
MAXMIND 提供地址数据库,我们能够使用这个数据库文件进行查询。很多开源软件都在使用 MAXMIND 提供的 GeoLite 数据库,比如 Nginx ELasticsearch 组件。
首先,注册 MAXMIND 帐号(GeoLite2 Sign Up),否则无法下载数据库文件(以往无需注册)。
然后,访问 Download Files 页面,以下载数据库文件:https://www.maxmind.com/en/accounts/current/geoip/downloads
# 下载 GeoLite2 City .mmdb 文件(手动下载) # 下载 GeoLite2 Country .mmdb 文件(手动下载) # 解压数据库文件 tar -xf GeoLite2-City_20210525.tar.gz tar -xf GeoLite2-Country_20210525.tar.gz
数据库文件的自动更新,参考 Updating GeoIP and GeoLite Databases 文档。
第三步、修改 Nginx 配置
这里我们仅屏蔽国外流量,仅允许国内访问:
http { ... geoip2 /etc/maxmind-country.mmdb { auto_reload 5m; $geoip2_metadata_country_build metadata build_epoch; $geoip2_data_country_code default=US source=$remote_addr country iso_code; $geoip2_data_country_name country names en; } .... server { if ($geoip2_data_country_code != CN) { return 200 $geoip2_data_country_code; } } .... }
第四步、访问站点验证
在不同的区域访问站点,以检查我们的配置是正确的。
相关链接
NGINX Docs | Dynamic Denylisting of IP Addresses
Dynamic IP Denylisting with NGINX Plus and fail2ban – NGINX
参考文献
GeoIP Legacy Databases
geoip – How to Convert a Maxmind .MMDB to .DAT? – Stack Overflow
nginx: How To Block Visitors By Country With The GeoIP Module (Debian/Ubuntu)
Module ngx_http_geoip_module
Installing Nginx with GeoIP2 on Ubuntu | Ivan Dokov – Software architect and strategist