nginx需借助ngx_http_geoip2_module模块和geolite2数据库才能实现按国家过滤访问;通过geoip2指令获取$geoip2_data_country_code变量,再用map定义黑白名单并配合return 403控制访问。

Nginx 本身不内置 IP 地理位置识别能力,需借助 ngx_http_geoip2_module(推荐)或旧版 ngx_http_geoip_module,配合 MaxMind 的 GeoIP2 或 GeoLite2 数据库,才能实现按国家过滤访问。原生 geo 模块仅支持静态 IP 段映射(如手动定义某段 IP 属于“CN”),无法自动识别真实国家,所以“结合 geo 模块实现按国家过滤”实际是指:用 GeoIP2 模块获取 $geoip2_data_country_code 变量,再通过 geo、map 或 if 配合 deny/allow 实现控制。
1. 安装 GeoIP2 模块并加载数据库
这是前提。Ubuntu/Debian 可用包管理安装,CentOS 建议源码编译 Nginx 时加入 --add-dynamic-module=../ngx_http_geoip2_module。下载免费的 GeoLite2 Country 数据库(GeoLite2-Country.mmdb),放在如 /usr/share/GeoIP/GeoLite2-Country.mmdb。
在 nginx.conf 的 http 块中添加:
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
$geoip2_data_country_code source=$remote_addr country iso_code;
$geoip2_data_country_name source=$remote_addr country names en;
}
这样就将客户端真实 IP 对应的国家代码(如 CN、US)存入变量 $geoip2_data_country_code。
2. 用 map 指令定义允许/拒绝名单(推荐方式)
map 比 if 更高效、更安全,适合做黑白名单映射。例如只允许中国和日本访问:
map $geoip2_data_country_code $allowed_country {
default 0;
CN 1;
JP 1;
}
然后在 server 或 location 中使用:
if ($allowed_country = 0) {
return 403;
}
注意:return 403 比 deny all 更明确,且兼容所有上下文;deny 在 location 中可用,但在 if 内不可用。
3. 用 geo 指令做静态国家白名单(适用于简单场景)
如果不想依赖外部数据库,可手动维护 IP 段与国家的映射(不推荐用于生产,因 IP 归属变动频繁)。例如:
geo $remote_addr $allowed {
default 0;
include conf/ip_ranges_cn.conf; # 内容如:1.0.1.0/24 1;
include conf/ip_ranges_jp.conf;
}
但这种方式需持续更新 IP 段文件,维护成本高,且无法覆盖 CDN 或代理后的真实用户地域。仅建议测试或内网环境使用。
4. 注意事项与常见问题
- 确保使用
$remote_addr获取真实 IP;若前端有 CDN 或反向代理,需先用real_ip模块还原(设置set_real_ip_from和real_ip_header X-Forwarded-For) - GeoIP2 数据库需定期更新(MaxMind 提供每周更新链接),可写脚本自动下载 + reload nginx
- 避免在
if中直接写deny,Nginx 官方明确说明deny在if中行为不可靠 - 测试时用不同地区代理或手机热点验证,不要仅靠本地 IP 判断











