「Nginx」- 屏蔽 IP 地址、屏蔽国家地区

  CREATED BY JENKINSBOT

问题描述

我们需要屏蔽来自国外的站点访问,不单纯是屏蔽某个地址,而是屏蔽所有来自国外的访问。

该笔记将记录:在 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/IPv4Maxmind – 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/IPv4Maxmind – 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 GeoIP 笔记。

第三步、修改 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