Nginx + GeoIP2 可实现基于请求IP地域的智能流量分发:通过 geoip2 模块解析IP获取国家码与区域标识,结合 map 指令映射至对应 upstream 集群,再于 server 块中用 proxy_pass 动态路由,无需 reload 即可实时生效。

想让不同地区的用户访问离自己最近或最合适的服务器?Nginx + GeoIP 模块可以做到——它不依赖客户端IP上报,而是通过请求来源IP自动识别地域,再结合 upstream 和 map 指令把流量分发到对应集群。
一、确认Nginx是否支持GeoIP模块
较新版本的 Nginx(1.11.3+)已移除内置的 ngx_http_geoip_module,改用更灵活的 ngx_http_geoip2_module(需手动编译或安装)。检查方法:
- 运行
nginx -V 2>&1 | grep -o with-http-geoip2-module,有输出说明已编译支持 - 若无,需下载 ngx_http_geoip2_module 并重新编译Nginx,或使用支持该模块的发行版(如 Ubuntu 的
nginx-extras包) - 同时需下载 MaxMind 的 GeoLite2 City 或 Country 数据库(
.mmdb格式),注意免费版需每月更新
二、配置GeoIP2解析并映射地域标识
在 http 块中加载数据库并定义变量:
http {
geoip2 /path/to/GeoLite2-Country.mmdb {
$geoip2_data_country_code source=$remote_addr country iso_code;
$geoip2_data_country_name source=$remote_addr country names en;
}
<pre class="brush:php;toolbar:false;"># 可选:进一步归类为大区(如中国、亚太、北美等)
map $geoip2_data_country_code $region {
default "others";
CN "china";
JP "apac";
KR "apac";
US "na";
CA "na";
DE "eu";
FR "eu";
}
}
这样就得到了两个关键变量:$geoip2_data_country_code(如 "CN")和 $region(如 "china"),后续可用于条件路由。
三、按地域定义多组后端集群
在 http 或 stream 块中分别声明不同地域的 upstream:
upstream backend_china {
server 192.168.1.10:8080 weight=3;
server 192.168.1.11:8080;
}
<p>upstream backend_apac {
server 192.168.2.10:8080;
}</p><p>upstream backend_na {
server 192.168.3.10:8080;
}</p><p>upstream backend_eu {
server 192.168.4.10:8080;
}</p>
每个 upstream 可独立配置健康检查、权重、连接限制等策略,适配各地基础设施差异。
四、在server中实现动态上游选择
利用 map + proxy_pass 实现零延迟切换:
map $region $upstream_backend {
default backend_others;
china backend_china;
apac backend_apac;
na backend_na;
eu backend_eu;
}
<p>server {
listen 80;
server_name example.com;</p><pre class="brush:php;toolbar:false;">location / {
proxy_pass http://$upstream_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
注意:proxy_pass 后必须带变量且不加 URI 路径(如不能写成 http://$upstream_backend/),否则会导致路径拼接异常;Nginx 会在每次请求时实时解析变量并选择 upstream,无需 reload。
实际部署时建议配合日志记录地域信息,便于监控分发效果:
log_format geo_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'country:$geoip2_data_country_code region:$region';
<p>access_log /var/log/nginx/geo_access.log geo_log;</p>











