nginx 的 geo 指令仅支持静态 ip 段匹配,不识别国家或城市,需手动维护 ip 归属规则;支持 cidr、ip 范围、单 ip 和 include 外部文件,按最长前缀优先匹配;须配合 realip 模块还原真实客户端 ip;精准地理控制应使用 geoip2 模块。

Nginx 的 geo 指令本身不能识别国家或城市,它只做静态 IP 段匹配。所谓“基于地理位置”的控制,本质是把已知地理归属的 IP 段(比如中国公网段、某云厂商出口段、公司办公网段)手动整理成规则,再用 geo 建立映射变量,最后配合其他指令实现分流或拦截。
geo 指令只能处理已知 IP 范围
它不联网、不查库、不解析 IP 归属,就是一个本地查表工具。支持的格式包括:
- CIDR 表示法,例如
1.0.128.0/17 - IP 范围写法,例如
127.0.0.0-127.255.255.255 - 单个 IP,例如
192.168.1.1 - 用
include引入外部文件,适合管理大量条目(如把中国所有 BGP 段存为geo-cn.conf)
匹配按“最长前缀优先”原则,192.168.1.0/24 会比 192.168.0.0/16 先命中。
典型配置:定义区域变量并使用
在 http 块中定义变量,例如标记是否为中国 IP:
geo $is_cn {
default 0;
include /etc/nginx/geo-cn.conf;
}
之后可在 server 或 location 中使用该变量:
- 分流到不同后端:
proxy_pass http://backend_$is_cn;(需提前定义upstream backend_0和backend_1) - 简单拒绝访问:
if ($is_cn = 0) { return 403; }(仅限布尔判断,避免嵌套逻辑) - 透传区域信息给上游:
proxy_set_header X-Region $is_cn;
必须还原真实客户端 IP
如果 Nginx 前有 CDN、WAF 或负载均衡器,$remote_addr 就是代理地址,geo 查的全是错的。要确保准确,需启用 realip 模块并配置:
- 用
set_real_ip_from明确声明可信代理网段(如 Cloudflare、阿里云 SLB 的 IP 段) - 指定原始 IP 所在请求头:
real_ip_header X-Forwarded-For;或X-Real-IP - 开启递归解析:
real_ip_recursive on;,确保取到最左边的真实客户端地址
想识别国家或城市?得换方案
纯 geo 维护成本高,且无法覆盖动态分配的海外住宅 IP。若真要按国家、省份、城市做控制,应改用 geoip2 模块 + MaxMind 的 .mmdb 数据库。它能提取 $geoip2_country_code、$geoip2_city_name 等变量,再配合 if 或 map 实现精准策略。而 geo 可作为兜底白名单或内网标识补充使用。











