核心在于通过MaxMind GeoIP2数据库解析客户端IP地理信息,结合map预计算变量与limit_req、return、proxy_pass等指令,实现按国家限速、拦截、灰度路由及动态响应头等精准控制。

使用 ngx_http_geoip2_module 实现基于地理位置的精准流量控制,核心在于:通过 MaxMind GeoIP2 数据库解析客户端 IP 的地理信息(如国家、省份、城市、ASN 等),再结合 Nginx 的 map、if、limit_req 或 return 等指令,对不同区域执行差异化策略——比如限速、拦截、灰度路由或内容重写。
一、编译安装模块并加载 GeoIP2 数据库
该模块不内置在官方 Nginx 中,需手动编译集成:
- 确认已安装
libmaxminddb开发库(如 Ubuntu 执行sudo apt install libmaxminddb-dev) - 下载并编译
ngx_http_geoip2_module(推荐从 GitHub 官方仓库 获取最新版) - 重新编译 Nginx,添加参数:
--add-module=/path/to/ngx_http_geoip2_module - 下载 GeoIP2 City 或 Country 数据库(
GeoLite2-Country.mmdb或GeoLite2-City.mmdb),建议定期更新(可用geoipupdate工具自动化) - 在
nginx.conf的http块中加载数据库:geoip2 /usr/share/GeoIP/GeoLite2-City.mmdb {<br> $geoip2_data_country_code source=$remote_addr country iso_code;<br> $geoip2_data_city_name source=$remote_addr city name;<br> $geoip2_data_asn_number source=$remote_addr autonomous_system_number;<br>}
二、用 map 构建可复用的地理标签变量
直接在 if 或限流条件中频繁调用 $geoip2_* 变量效率低且不可读。推荐先用 map 映射出业务语义变量:
- 定义国家白名单:
map $geoip2_data_country_code $allowed_country {<br> default 0;<br> CN 1;<br> JP 1;<br> KR 1;<br>} - 标记高风险 ASN(如已知代理/IDC):
map $geoip2_data_asn_number $is_proxy_asn {<br> ~^(12345|67890|24680) 1;<br> default 0;<br>} - 组合多维判断(例如“中国大陆 + 非主流 CDN”):
map $geoip2_data_country_code:$is_proxy_asn $cn_nonproxy {<br> "CN:0" 1;<br> default 0;<br>}
三、实施精准流量控制策略
利用上一步生成的变量,嵌入到具体指令中实现控制逻辑:
-
按国家限速:为不同地区配置独立限流区
limit_req_zone $geoip2_data_country_code zone=per_country:10m rate=5r/s;<br>limit_req zone=per_country burst=10 nodelay;
-
拦截特定区域请求:
if ($geoip2_data_country_code = "RU") { return 403; }
(注意:if在 location 外慎用;更推荐配合map + error_page或用auth_request模块做前置校验) -
灰度发布路由:将中国用户导向新版本 upstream
upstream backend_v2 { server 10.0.1.10:8080; }<br>upstream backend_v1 { server 10.0.1.20:8080; }<br>set $backend_backend_v1;<br>if ($cn_nonproxy) { set $backend backend_v2; }<br>proxy_pass http://$backend; -
动态响应头或日志标记(便于后端或监控识别):
add_header X-Geo-Country $geoip2_data_country_code;<br>log_format geo_log '$remote_addr - $remote_user [$time_local] "$request" '<br> '$status $body_bytes_sent "$http_referer" "$http_user_agent" '<br> '$geoip2_data_country_code $geoip2_data_city_name';
四、注意事项与优化建议
避免常见陷阱,提升稳定性和可维护性:
- 始终设置
source=$remote_addr;若前端有代理(如 CDN),需改用$http_x_forwarded_for并确保可信(配合set_real_ip_from) - GeoIP2 查询是同步阻塞操作,高并发下可能影响性能;建议搭配
resolver和缓存 DNS,或考虑用 OpenResty + lua-resty-maxminddb 异步加载 - 不要在
if中嵌套复杂逻辑(如多个geoip2字段判断),优先用map预计算 - 测试时用真实 IP(非 127.0.0.1)验证,本地环回地址无地理信息;可用
curl -H "X-Forwarded-For: 8.8.8.8" http://your.site模拟 - 敏感策略(如封禁)建议先记录日志 + 返回 403,观察一周再启用硬拦截

















