Nginx实现地理位置维度限流需先启用GeoIP2模块加载GeoLite2数据库,再用map将$geoip2_data_country_code等字段映射为策略变量(如$rate_level、$block_asn),最后通过limit_req_zone按地理维度建区或用if+return进行条件拦截,所有map和limit_req_zone必须定义在http块内。

在 Nginx 中,仅靠 $remote_addr 或简单 UA 判断无法实现地理位置维度的流量控制。真正可行的方式是:先通过 GeoIP(或 GeoIP2)模块获取客户端所在国家、地区甚至城市,再用 map 指令将地理信息映射为可参与条件判断的变量,最后结合 limit_req、if 或 return 实现差异化限流或路由策略。
启用地理信息识别模块
Nginx 官方不内置 GeoIP,需确认已编译并启用对应模块:
- 旧版用
ngx_http_geoip_module(基于 MaxMind Legacy 格式,已停止更新) - 推荐使用
ngx_http_geoip2_module(支持 GeoLite2 City/ASN 数据库,精度高、维护活跃) - 安装后,在
http块中加载数据库:
geoip2 /usr/share/GeoIP/GeoLite2-City.mmdb {
$geoip2_data_country_code source=$remote_addr country iso_code;
$geoip2_data_city_name source=$remote_addr city name;
$geoip2_data_asn source=$remote_addr autonomous_system_number;
}
用 map 构建地理策略变量
map 指令必须定义在 http 块内,它把原始地理字段转为带业务语义的变量,便于后续复用:
- 按国家分组限流等级:
map $geoip2_data_country_code $rate_level {
default "low";
"CN" "high";
"US" "medium";
"JP" "high";
} - 屏蔽高风险 ASN(如已知代理/IDC网段):
map $geoip2_data_asn $block_asn {
default 0;
12345 1; # 某代理AS号
67890 1; # 另一可疑AS号
}
结合限流与访问控制生效
地理变量本身不可直接限流,需绑定到 limit_req_zone 或用于条件拦截:
- 为不同地区配置独立限流区域:
limit_req_zone $geoip2_data_country_code zone=by_country:10m rate=10r/s;
limit_req_zone $rate_level zone=by_tier:10m rate=5r/s;
在location中选择其一:
limit_req zone=by_tier burst=10 nodelay; - 直接拒绝高风险 ASN 请求:
if ($block_asn = 1) {
return 403 "Access denied by geo policy";
} - 对重点地区(如 CN)启用更严格的防刷策略:
if ($geoip2_data_country_code = "CN") {
set $limit_key "$binary_remote_addr$uri";
limit_req zone=cn_strict burst=3 nodelay;
}
验证与调试技巧
上线前务必验证地理变量是否正确解析,避免因数据源或配置错误导致误控:
- 临时添加响应头输出调试信息:
add_header X-Country $geoip2_data_country_code;
add_header X-Rate-Level $rate_level;
add_header X-ASN $geoip2_data_asn; - 用 curl 测试(配合代理或真实海外 IP):
curl -I https://yoursite.com --proxy http://jp-proxy:8080 - 检查 error log 是否报错:
tail -f /var/log/nginx/error.log | grep geoip
常见错误包括数据库路径错误、权限不足、字段名拼写错误等。


















