Nginx需借助ngx_http_geoip2_module模块与GeoLite2数据库实现地理IP路由,核心流程为:加载数据库→提取变量→map映射→proxy_pass转发,并须设default兜底及定期更新数据库。

Nginx 本身不内置地理 IP 解析能力,但可以通过第三方模块(如 ngx_http_geoip2_module)结合 MaxMind GeoLite2 数据库,提取客户端所在国家、地区、城市等信息,并基于这些变量在 proxy_pass 中实现条件转发。关键在于:先获取地理信息 → 存入变量 → 在 location 或 if 中做判断 → 路由到对应后端。
安装并配置 GeoIP2 模块
官方 Nginx 不含 GeoIP2 支持,需编译时添加模块或使用预编译支持该模块的发行版(如 nginx-plus,或 Ubuntu/Debian 的 nginx-extras 包)。确认已启用后,在 http 块中加载数据库:
http {
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
$geoip2_data_country_code source=$remote_addr country iso_code;
$geoip2_data_country_name source=$remote_addr country names en;
$geoip2_data_city_name source=$remote_addr city names en;
}
}
注意路径需与实际 GeoLite2-Country.mmdb 文件位置一致;变量名可自定义,但需与后续引用保持一致。
在 proxy_pass 中按地域做转发
利用 map 指令将地理变量映射为上游服务器地址,比在 if 中直接判断更高效、更安全:
map $geoip2_data_country_code $backend_upstream {
default "http://default-backend";
CN "http://cn-backend";
US "http://us-backend";
JP "http://jp-backend";
}
server {
listen 80;
location / {
proxy_pass $backend_upstream;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
这样所有请求自动按国家代码路由,无需重复写多个 location 或 if 块。若需更细粒度(如按省份),需使用 GeoLite2-City 数据库并映射 subdivisions.0.iso_code 等字段。
验证与兜底处理
地理库无法识别时,$geoip2_data_country_code 为空或未定义,可能导致 map 匹配失败。务必设置 default 分支,并建议开启日志记录用于调试:
- 在
log_format中加入$geoip2_data_country_code和$backend_upstream,方便排查未命中情况 - 用
curl -H "X-Real-IP: 8.8.8.8" http://your-domain/模拟不同 IP 测试(确保真实 IP 未被代理覆盖) - 定期更新 GeoLite2 数据库(MaxMind 每月发布新版本),避免地理位置误判
替代方案:用 Lua 脚本增强灵活性
若需复杂逻辑(如“CN 用户优先走上海节点,次选北京”或“同一国家内按延迟选节点”),可集成 nginx-lua-module,在 access_by_lua_block 中读取 ngx.var.geoip2_data_country_code 并动态设置 ngx.var.upstream_server,再在 proxy_pass 中引用该变量。但需权衡可维护性与性能开销。










