Nginx 的 geo 模块本身不支持国家识别,需配合 GeoIP2 模块与 MaxMind 数据库实现;通过 geoip2 指令加载数据库并提取国家代码,再用 if + return 或正则匹配拦截指定国家流量,同时建议结合 real_ip 配置和 geo 模块做可信白名单与兜底控制。

直接用 Nginx 的 geo 模块本身无法识别国家,它只支持静态 IP 段匹配,比如内网、机房段或已知代理段。要禁止“特定国家”的流量,必须配合 GeoIP 或 GeoIP2 这类基于 IP 地理数据库的模块——geo 模块负责变量定义和逻辑分发,真正做国家识别的是 geoip 或 ngx_http_geoip2。
确认 Nginx 是否支持地理识别模块
运行以下命令检查当前 Nginx 编译参数:
nginx -V 2>&1 | grep -o with-http_geoip_module(旧版 GeoIP)
nginx -V 2>&1 | grep -o with-http_geoip2_module(推荐新版 GeoIP2)
若无输出,说明模块未编译进 Nginx。Ubuntu/Debian 可安装预编译包:
- sudo apt install nginx-module-geoip2
- CentOS/RHEL 需启用 EPEL 后安装
nginx-mod-http-geoip2
安装后在 /etc/nginx/nginx.conf 的 http 块中启用:
load_module modules/ngx_http_geoip2_module.so;
配置 GeoIP2 数据库与国家变量
下载免费的 MaxMind GeoLite2 Country 数据库(需注册获取 License Key):
- 创建目录:sudo mkdir -p /usr/share/GeoIP
- 下载并解压:wget https://github.com/maxmind/geoipupdate/releases/download/v5.3.0/geoipupdate_5.3.0-1_amd64.deb(或使用 geoipupdate 工具自动更新)
- 数据库路径示例:/usr/share/GeoIP/GeoLite2-Country.mmdb
在 http 块中添加:
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
$geoip2_data_country_code source=$remote_addr country iso_code;
}
该配置将客户端真实 IP 对应的国家代码(如 US、CN、RU)写入变量 $geoip2_data_country_code。
在 server 或 location 中拦截指定国家
禁止访问最简方式是用 if + return,放在 server 或 location 块内:
if ($geoip2_data_country_code = "KP") { return 403; }
if ($geoip2_data_country_code = "SY") { return 403; }
if ($geoip2_data_country_code ~ "^(KP|SY|IR|CU)$") { return 403; }
注意:
– 多个国家建议用正则匹配,避免重复 if;
– 不要对 root location 外部加全局 if,可能影响健康检查或静态资源;
– 若使用 CDN 或反向代理,需先配置 real_ip_header X-Forwarded-For; 和 set_real_ip_from 信任段,确保取到真实客户端 IP。
增强可靠性:结合 geo 模块做兜底或分层控制
geo 模块可用于补充场景,例如:
- 把已知攻击源 IP 段(如某 IDC 出口)强制标记为高风险,独立于 GeoIP 结果;
- 为内网、CDN 回源、监控探针等可信地址设置白名单,绕过国家限制;
- 构造复合变量:geo $is_blocked { default 0; include /etc/nginx/conf.d/blocked_ranges.conf; },再在 if 中叠加判断:if ($geoip2_data_country_code = "RU" && $is_blocked) { return 403; }
这种组合让策略更灵活,也避免单点失效导致误拦。

















