geo指令仅支持静态IP段匹配,无法自动识别国家或城市;需手动维护CIDR、IP范围等地理映射规则,并配合realip模块还原真实客户端IP,或与geoip2模块协同实现精准地域控制。

直接用 http 块里的 geo 指令无法识别国家或城市——它只认 IP 段,不查数据库,也不懂地理信息。想靠 geo 实现“基于地理位置”的控制,本质是用它做静态 IP 归属映射,比如把已知的中国公网段、某云厂商机房段、公司内网段单独标出来,再配合其他指令做策略分发。
geo 指令只能匹配已知 IP 范围
geo 模块本身不联网、不调库、不解析 IP 归属,它就是一个本地查表工具。你得自己整理好哪些 IP 段属于哪类区域,写进配置或外部文件:
- 支持 CIDR 表示法(如
1.0.128.0/17)、IP 范围(127.0.0.0-127.255.255.255)、单 IP(192.168.1.1) - 支持
include引入外部文件,适合管理大量 IP 段(例如把中国所有 BGP 段存为geo-cn.conf) - 匹配遵循“最长前缀优先”,所以
192.168.1.0/24会比192.168.0.0/16先命中
典型用法:标记区域 + 分流或拦截
在 http 块中定义变量,例如用 $is_cn 标记是否为中国 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 查的就全是错的。必须提前还原真实 IP:
- 在
http块顶部启用realip模块(通常已内置) - 用
set_real_ip_from明确声明可信代理网段(如 Cloudflare 的 IP 段、阿里云 SLB 网段) - 指定原始 IP 所在请求头:
real_ip_header X-Forwarded-For;或X-Real-IP - 开启递归解析:
real_ip_recursive on;,确保取到最左边的真实客户端地址
和 GeoIP2 配合用更实用
纯 geo 维护成本高,且无法覆盖动态分配的海外住宅 IP。推荐组合方案:
- 用
geoip2模块自动识别国家代码(如$geoip2_data_country_code) - 用
geo指令打标高可信内网/专线/白名单 IP(绕过 GeoIP 查询开销) - 用
map把国家码转为布尔值(如map $geoip2_data_country_code $allowed { default 0; CN 1; JP 1; }) - 最终用
if ($allowed = 0) { return 403; }统一拦截

















