Nginx按地区访问控制的核心是通过本地IP库(如geoip2模块+GeoLite2数据库)识别客户端国家代码,再结合if判断实现精准放行或拦截;也可用内置geo模块做粗粒度IP段分组;支持Referer双重校验及Redis动态更新策略。

在 Nginx 中按地区实施访问控制,核心是识别客户端 IP 所属地理区域,再结合条件判断执行放行或拦截。这不依赖外部 API 调用,而是通过本地 IP 库 + 模块匹配实现,响应快、可控性强。
使用 geoip2 模块识别国家/地区
这是最常用且准确的方式。需先编译安装 ngx_http_geoip2_module,并下载 MaxMind 的 GeoLite2 City 或 Country 数据库(注意:GeoLite2 免费版自 2024 年起需注册账号获取 License Key)。
配置示例如下:
在 http 块中加载数据库与定义变量
http {
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
$geoip2_data_country_code country iso_code;
$geoip2_data_country_name country names en;
}
<pre class='brush:php;toolbar:false;'>server {
location / {
# 禁止来自俄罗斯和朝鲜的访问
if ($geoip2_data_country_code = "RU") { return 403; }
if ($geoip2_data_country_code = "KP") { return 403; }
# 仅允许中国、日本、新加坡访问管理后台
location /admin/ {
if ($geoip2_data_country_code !~ ^(CN|JP|SG)$) {
return 403;
}
}
}
}}
用 geo 模块做粗粒度地域分组
若无需精确到国家,只按 IP 段划分“内网/外网”“国内/海外”,可用内置 geo 模块,无需额外模块或数据库。
例如将常见国内云厂商出口 IP 段归为 CHN,其余视为 OVERSEAS:
geo $region {
default OVERSEAS;
include /etc/nginx/ip_ranges/chn.conf; # 包含中国各运营商IP段
127.0.0.1 LOCAL;
::1 LOCAL;
}
<p>server {
location /api/v1/ {</p><h1>海外请求限速更严</h1><pre class='brush:php;toolbar:false;'> if ($region = "OVERSEAS") {
limit_req zone=overseas burst=5 nodelay;
}
proxy_pass http://backend;
}}
注意:geo 匹配遵循最长前缀原则,需确保高精度网段写在前面
结合 referer 和地理位置做双重校验
某些场景下,单纯靠 IP 地域可能被代理绕过。可叠加 Referer 检查,比如静态资源只允许来自本国域名的页面引用:
location /static/ {
valid_referers ~\.cn$ ~\.jp$;
if ($invalid_referer) {
# 同时检查是否为中国 IP,二者都满足才放行
if ($geoip2_data_country_code != "CN") {
return 403;
}
}
}这样既防直接盗链,也降低代理穿透风险。
动态更新地域策略(进阶)
当需要频繁调整封禁国家列表时,避免每次改配置 reload,推荐方式:
- 把国家码列表存入 Redis,如 key
blocked_countries,value 为逗号分隔字符串(RU,IR,SY) - 用 OpenResty + lua-resty-redis 在 access_by_lua_block 中查询并决策
- 或定期生成
blocked_geo.conf文件,配合 include + nginx -s reload 自动化


















