在 nginx 中限制区域访问,核心做法是加载 ngx_http_geoip2_module 模块,通过 geoip2 指令将 maxmind geolite2 数据库中的地理位置数据映射到变量,然后在 location 块中使用 if 或 allow/deny 指令判断这些变量来阻断请求。具体而言,你需要指定数据库文件路径、设置输出变量名(如 $geoip2_data_country_code),并在配置中根据该变量的值返回错误或拒绝连接。

如何配置 geoip2 指令以获取国家代码
要获取访问者的国家代码,需要在 http 块中定义 geoip2 指令,并指定 MaxMind 数据库的路径以及目标变量。该指令会自动处理 IP 查找逻辑,并将结果存入指定的变量中,供后续配置使用。

http {
# 加载 GeoIP2 模块
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
auto_reload 5m;
$geoip2_data_country_code default=CN source=$remote_addr country iso_code;
}
server {
listen 80;
server_name example.com;
location / {
# 如果国家代码不是 CN,则返回 403
if ($geoip2_data_country_code != "CN") {
return 403 "Access Denied";
}
proxy_pass http://backend;
}
}
}
上述配置中,geoip2 指令读取 /usr/share/GeoIP/GeoLite2-Country.mmdb 文件。变量 $geoip2_data_country_code 被赋值为 country 对象下的 iso_code 字段。默认值设为 CN 是为了防止因数据库缺失或解析错误导致所有请求被拒。在 location 块中,if 语句检查该变量,若非 CN 则直接返回 403 状态码。
如何基于城市名称进行更精细的限制
除了国家级别,还可以利用同一数据库中的城市信息来实现更细粒度的控制。这需要启用 City 数据库,并提取 city 对象下的 names 字段。由于城市名可能包含空格或多语言版本,通常建议使用英文标识符或特定语言代码来获取准确值。

http {
geoip2 /usr/share/GeoIP/GeoLite2-City.mmdb {
auto_reload 5m;
$geoip2_data_city_name default=Unknown source=$remote_addr city names en;
}
server {
listen 80;
server_name example.com;
location /api/ {
# 仅允许来自 "Beijing" 的请求
if ($geoip2_data_city_name != "Beijing") {
return 403 "Only Beijing Access Allowed";
}
proxy_pass http://backend_api;
}
}
}
在此示例中,使用了 City 数据库以获取更详细的地理位置。变量 $geoip2_data_city_name 从 city 对象的 names 字段中提取,并指定语言为英语 (en)。配置限制了 /api/ 路径仅对来自北京的用户开放。若用户所在城市不匹配,服务器将返回 403 错误。这种机制依赖于数据库中包含精确的城市名称映射,且需确保客户端 IP 能正确解析到对应城市记录。
当 IP 无法解析时如何处理默认行为
在实际部署中,部分 IP 地址可能不在数据库中,或者因网络结构导致无法准确定位。此时,geoip2 指令中设置的 default 参数将决定变量的值。若未设置默认值,变量将为空字符串,可能导致 if 条件判断意外放行或拒绝。因此,明确指定默认值是保障安全策略一致性的关键步骤。
,











