nginx通过geoip2实现区域流量分发的核心是三步:还原真实ip→加载geolite2地理数据→用map预映射地域到upstream集群;全程纯原生配置,无需lua或外部服务。

确认模块已加载并获取真实客户端 IP
如果用户经过 CDN、WAF 或负载均衡器,$remote_addr 就是代理 IP,GeoIP 查询会完全失效。
- 在 http 块顶部 添加可信上游网段:
set_real_ip_from 103.21.244.0/22;(填你实际使用的 CDN 或 LB CIDR) - 指定原始 IP 所在请求头:
real_ip_header X-Forwarded-For; - 开启递归解析,避免多层代理污染:
real_ip_recursive on; - 加一个测试接口验证:
location /realip { return 200 "$realip_remote_addr"; },访问后应返回用户真实公网 IP
加载 GeoLite2 数据库并定义地理变量
推荐使用 GeoLite2-City.mmdb(比 Country 版本支持城市、经纬度、时区等,精度更高)。
- 从 MaxMind 官网注册账号,免费下载数据库和 License Key,上传至服务器(如
/etc/nginx/geoip2/GeoLite2-City.mmdb) - 确保 ngx_http_geoip2_module 已编译或动态加载:
nginx -V 2>&1 | grep -o geoip2应有输出 - 在 http 块中配置:
geoip2 /etc/nginx/geoip2/GeoLite2-City.mmdb {<br> $geoip2_data_country_code source=$realip_remote_addr country iso_code;<br> $geoip2_data_city_name source=$realip_remote_addr city names en;<br> $geoip2_data_latitude source=$realip_remote_addr location latitude;<br> $geoip2_data_longitude source=$realip_remote_addr location longitude;<br>}
用 map 指令预映射地域到目标集群
不要在 location 里写 if 判断,性能差且易出错。统一在 http 块用 map 提前算好路由目标。
- 例如按国家码映射 upstream:
map $geoip2_data_country_code $backend_cluster {<br> default "us_backend";<br> CN "sh_backend";<br> JP "tk_backend";<br> KR "seoul_backend";<br> DE "frankfurt_backend";<br>} - 对应定义 upstream:
upstream sh_backend { server 192.168.1.10:8080; }<br>upstream tk_backend { server 192.168.1.11:8080; } - 在 server 或 location 中直接路由:
location /api/ { proxy_pass http://$backend_cluster; } - 如需更细粒度(如“CN-BJ”),可拼接:
map "$geoip2_data_country_code-$geoip2_data_subdivision_1_iso_code" $backend_cluster { ... }
验证与兜底建议
上线前务必检查几件事:
- 未命中地理库的 IP(如私有地址、新分配段)会返回空值,map 必须设 default 分支,否则 proxy_pass 报 502
- 临时加响应头调试:
add_header X-Geo-Country $geoip2_data_country_code;add_header X-Geo-City $geoip2_data_city_name; - 日志中记录地理字段便于分析:
log_format main "... $geoip2_data_country_code $geoip2_data_city_name"; - 定期更新 GeoLite2 数据库(MaxMind 每月发布新版),避免 IP 归属过期











