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

  CREATED BY JENKINSBOT

问题描述

我们需要屏蔽国外的访问,不单纯是屏蔽某个地址,而是屏蔽整个国外的访问。

该笔记将记录:在 Nginx 中,如何屏蔽 IP 地址访问、如何屏蔽某个国家的访问,以及常见问题的解决方法。

解决方案

我们将记录多种不同的解决方案:
1)通过网络地址,来屏蔽或允许特定 IP 地址的访问;
2)通过 GeoIP 数据库,以屏蔽国家或地区的访问;

通过网络地址屏蔽

这里我们还是会记录如何通过 IP 地址进行屏蔽:

server {
  server blog.example.com;
  
  deny 45.43.23.21;
  deny 45.43.23.0/24;
  allow all;
  ...
  
  # 针对地址进行屏蔽
  location /accounts/login {
      deny 45.43.23.21;
  }
}

Nginx + GeoIP Module(废弃)

第一步、检查 Nginx 已启用 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 数据库

MAXMIND 提供 GeoIP 数据库文件,该数据库文件包含 IP 地址及所属地域。通过读取该数据库文件,Nginx 将获得访客 IP 的地域信息。

但是 Nginx 仅能识别 .dat 数据文件,而现在(06/02/2021)官方已经不提供 .dat 格式的数据文件,仅提供 .mmdb 和 CSV 格式的数据文件(相关原因及说明,参考 Retirement of GeoIP Legacy Downloadable Databases in May 2022 | MaxMind Blog 文章)。需要使用 sherpya/geolite2legacy: MaxMind GeoLite2 (CSV) to Legacy format converter 进行文件的转化(.mmdb => .dat)。

不过,已有人完成这项工作,访问 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

与 GeoIP Module类似,GeoIP2 Module 是对 mmdb 的支持,因此不再需要 GeoIP 模块。

第一步、检查 Nginx 已启用 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=$variable_with_ip country iso_code;
        $geoip2_data_country_name country names en;
    }

    geoip2 /etc/maxmind-city.mmdb {
        $geoip2_data_city_name default=London city names en;
    }
    ....

    fastcgi_param COUNTRY_CODE $geoip2_data_country_code;
    fastcgi_param COUNTRY_NAME $geoip2_data_country_name;
    fastcgi_param CITY_NAME    $geoip2_data_city_name;
    ....
}

第四步、访问验证

在不同的区域访问站点,以检查我们的配置是正确的。

相关链接

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