Nginx 中用 geo 模块精准放行内部办公网段,需在 http 块顶层定义 $is_internal 变量(default 0,匹配 CIDR 设 1),再于 location 内用 if ($is_internal = 0) { return 403; } 实现访问控制,并配合 realip 模块确保 IP 正确识别。

在 Nginx 中用 geo 模块精准识别并放行内部办公网段 IP,核心是借助 geo 指令定义 IP 匹配规则,生成一个变量(如 $is_internal),再在 location 或 server 块中用 if 或 allow/deny 控制访问。关键在于:变量必须在 http 块顶层定义,且 geo 不支持正则、只支持 CIDR 和精确 IP,优先级由配置顺序决定(先匹配的生效)。
配置 geo 变量标识内部网段
在 nginx.conf 的 http 块内定义:
注意:默认值设为 0,匹配到的网段设为 1;不能写成字符串 "1",否则后续 if 判断会出错
geo $is_internal {
default 0;
192.168.10.0/24 1;
10.50.0.0/16 1;
172.16.0.0/12 1;
127.0.0.1 1;
}在 location 中放行内部流量并限制外部访问
推荐使用 allow/deny 组合(比 if 更高效、更安全):
- 先明确放行
$is_internal = 1的请求(需配合geo变量转为 IP 列表) - 更稳妥的做法是:用
map把$is_internal转成 IP 地址列表,或直接在location内用if+allow配合return 403 - 实际常用简洁写法(兼容性强,无需 map):
location /admin/ {
if ($is_internal = 0) {
return 403;
}
# 后续正常代理或静态服务
proxy_pass http://backend;
}⚠️ 注意:if 在 location 外不推荐,但在 location 内用于简单判断(如变量等于数值)是安全的
验证与调试技巧
- 用
nginx -t检查语法,确认 geo 块在 http 级且无嵌套 - 在日志中记录变量值便于排查:
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $is_internal'; - 测试时用 curl 模拟不同 IP:
curl -H "X-Real-IP: 192.168.10.100" http://your-domain/admin/(确保 realip 模块已启用并正确设置) - 若前端有 LB 或 CDN,需用
set_real_ip_from+real_ip_header正确提取原始客户端 IP,否则$remote_addr是代理地址,geo 无法匹配
补充:支持多级办公网或动态更新的建议
- 网段较多时,可把 IP 段写进独立文件(如
internal_geo.conf),用include internal_geo.conf;引入,便于运维维护 - 如需热更新网段(不停服),可用 Lua 模块(OpenResty)+ Redis 动态查表,但普通 Nginx 原生 geo 不支持运行时 reload 网段
- 避免把公网可访问的管理接口仅靠 IP 白名单保护——应叠加登录认证、Referer 校验或 Token 验证,IP 控制只是第一道防线


















