Nginx 原生不支持在 location 块中按国家过滤,必须通过 http 块加载 geoip2 或 ip2location 模块及地理数据库,再用变量(如 $geoip2_data_country_code)或 map 映射实现国家级访问控制。

直接在 location 块里无法识别国家地区——Nginx 原生不支持按国家过滤,必须借助第三方地理库(如 GeoLite2 或 IP2Location)配合模块,在 http 或 server 级预判后,再由 location 内部通过变量控制行为。
需要先启用地理信息模块
仅靠基础 Nginx 无法实现国家识别。你得编译或安装支持 IP 地理定位的模块:
-
推荐方案:安装
ngx_http_geoip2_module(配合 MaxMind GeoLite2 数据库),这是目前最主流、更新及时的选择; -
备选方案:使用
ip2location-nginx模块(需搭配 IP2Location 数据库),适合需要城市级或时区信息的场景; - 确认模块已加载:执行
nginx -V 2>&1 | grep -o geoip2\|ip2location,有输出才说明可用。
在 http 块中定义国家变量
地理判断必须放在 http{...} 块内(不能写在 location 里),例如:
http {
# 加载 GeoLite2 数据库(路径按实际调整)
geoip2 /etc/nginx/GeoLite2-Country.mmdb {
$geoip2_data_country_code source=$remote_addr country iso_code;
}
<pre class="brush:php;toolbar:false;"># 或用 IP2Location(若用该模块)
# ip2location /var/lib/ip2location/IP2LOCATION-LITE-DB1.BIN;
server {
listen 80;
server_name example.com;
location / {
# 根据国家码做拦截
if ($geoip2_data_country_code = "CN") {
return 403;
}
if ($geoip2_data_country_code = "RU") {
return 403;
}
# 其他正常处理
proxy_pass http://backend;
}
}}
更安全的写法:避免 if + return
直接在 location 中用 if 可能引发意外行为(如与 rewrite 冲突)。建议改用 map 提前映射,再统一拦截:
http {
geoip2 /etc/nginx/GeoLite2-Country.mmdb {
$geoip2_data_country_code source=$remote_addr country iso_code;
}
<pre class="brush:php;toolbar:false;"># 将黑名单国家映射为 1,其余为 0
map $geoip2_data_country_code $blocked_country {
default 0;
CN 1;
RU 1;
KP 1;
IR 1;
}
server {
location / {
# 一行拦截,清晰且兼容性好
if ($blocked_country = 1) {
return 403;
}
proxy_pass http://backend;
}
}}
注意数据更新与 fallback 处理
地理数据库不是一劳永逸的:
- GeoLite2 免费版需每月手动下载更新(MaxMind 官网提供);
- IP 归属可能不准,尤其代理、CDN、移动运营商出口 IP;
- 建议加 fallback:当
$geoip2_data_country_code为空时(如数据库未加载或 IP 无匹配),默认放行或记日志排查,避免误杀; - 可加日志记录被拦截的国家:
log_format blocked '$remote_addr - $geoip2_data_country_code $request';,便于后续审计。


















