需用geoip2因旧版geoip已被弃用,不支持IPv6且MaxMind自2018年停供免费GeoIP Legacy数据;geoip2基于mmdb格式,支持IPv4/IPv6及国家、城市、经纬度等细粒度信息,是当前唯一推荐方案。

为什么需要 geoip2 而不是旧版 geoip
旧版 ngx_http_geoip_module 早已被 Nginx 官方弃用,依赖过时的 MaxMind GeoIP 数据库(dat 格式),不支持 IPv6,且自 2018 年起 MaxMind 停止免费提供 GeoIP Legacy 数据。而 geoip2 模块基于现代 GeoLite2/GeoIP2 数据库(mmdb 格式),支持 IPv4/IPv6、更细粒度的地理信息(国家、省份、城市、经纬度、时区等),更新频繁,是当前唯一推荐的地理 IP 解析方案。
编译安装支持 geoip2 的 Nginx
官方源码不内置 geoip2,需手动添加第三方模块:maxmind/libmaxminddb(C 库) + leev/ngx_http_geoip2_module(Nginx 模块)。关键步骤如下:
- 安装 libmaxminddb:从 https://github.com/maxmind/libmaxminddb 下载源码,
./configure && make && sudo make install,确保libmaxminddb.so可被链接 - 下载并解压 Nginx 源码(如 1.24.0),同时获取 https://github.com/leev/ngx_http_geoip2_module 模块代码
- 在 Nginx 源码目录执行:
./configure --add-dynamic-module=/path/to/ngx_http_geoip2_module --with-compat(启用动态模块便于后续加载) -
make && sudo make install;若需动态模块,运行make modules后将生成的ngx_http_geoip2_module.so复制到nginx/modules/
配置 geoip2 数据库与变量映射
从 https://dev.maxmind.com/geoip/geolite2-free-geolocation-data 注册账号下载 GeoLite2-Country.mmdb(免费)或 GeoLite2-City.mmdb(含城市级信息)。在 nginx.conf 的 http 块中加载:
load_module modules/ngx_http_geoip2_module.so;
<p>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;
$geoip2_data_continent_code source=$remote_addr continent code;
}</p><pre class="brush:php;toolbar:false;">geoip2 /usr/share/GeoIP/GeoLite2-City.mmdb {
$geoip2_data_postal_code source=$remote_addr postal code;
$geoip2_data_latitude source=$remote_addr location latitude;
$geoip2_data_longitude source=$remote_addr location longitude;
}
}
注意:source=$remote_addr 表示解析客户端真实 IP;若使用 CDN 或反向代理,需先通过 real_ip_header 和 set_real_ip_from 正确获取原始 IP。
实现精准区域访问控制
利用 geoip2 提供的变量,结合 map 和 if(慎用)或 return 实现灵活策略。例如只允许中国大陆用户访问后台接口:
map $geoip2_data_country_code $allowed_country {
default 0;
CN 1;
}
<p>server {
listen 80;
server_name api.example.com;</p><pre class="brush:php;toolbar:false;">location /admin/ {
if ($allowed_country = 0) {
return 403 "Access denied: not from China";
}
proxy_pass http://backend;
}
}
更健壮的做法是用 map 预定义拒绝规则,避免 if 在 location 中的限制:
map $geoip2_data_country_code $block_request {
~^(US|GB|CA|AU)$ 1; # 屏蔽美英加澳
default 0;
}
<p>server {
location / {
if ($block_request) {
return 444; # 直接关闭连接,更安静
}
...
}
}</p>
还可组合多维条件,比如仅放行北京(CN-BJ)且使用移动运营商的请求(需额外 ASN 数据库),或按城市半径做灰度发布。











