一、前排说明:为什么需要地区运营商级防护
飞牛NAS的漏洞风波之所以能波及如此广泛,根本原因在于大量用户将NAS直接暴露在公网,且缺乏基础防护措施。网络扫描器(如Shodan)只需输入特定关键词,就能轻松发现数千台未加防护的NAS管理后台,这些设备随即成为黑客眼中的”肥肉”。
我的防护思路很简单但极其有效:在网络入口层直接限制仅允许特定地区+特定运营商的IP访问,其他所有请求一律拒绝。这样做的好处是:
- 对扫描器隐形:拒绝连接(444状态码)不返回任何信息,扫描器无法识别服务类型
- 防护范围广:可阻止90%以上的恶意IP(包括所有IDC云服务器)
- 零漏洞风险:即使存在未知漏洞,攻击者也无法从网络外部触发
我之前在路由器层面配置过仅允许国内三大运营商IP访问,后来进一步细化为”仅限北京市电信”才能访问。这种方案虽然有效,但IP库维护繁琐。后来我转向在Nginx反向代理层配置GeoIP2,既能实现同样的防护效果,又能自动更新IP库,一举两得。

为什么不用雷池/宝塔WAF? 免费版无法实现地区+运营商级别的精细化控制(这是付费功能)。而且防漏洞需要”先发现漏洞→规则库更新→防护生效”的时间差,远不如在入口层直接拦截IDC IP来得直接。
二、核心工具解析:NPM与GeoIP2
Nginx Proxy Manager(NPM) 是一个基于Nginx的网页管理界面,提供了友好的反向代理配置面板。雷池等安全网关也是基于Nginx开发,但NPM更轻量、更易上手。
GeoIP2(Geographic IP Address Database) 是MaxMind公司维护的IP地理位置数据库,包含以下关键信息:
| 数据类型 | 用途 | 精度 |
|---|---|---|
| 城市/地区 | 精确到城市级别的地理位置 | 高 |
| ASN(自治系统号) | 识别运营商身份 | 高 |
| 国家 | 国家级地理位置 | 最高 |
| ISP类型 | 区分住宅IP/IDC IP | 中 |
我们需要读取GeoIP2数据库中的城市信息和ASN信息,只有同时满足”指定城市+指定运营商”的IP才被放行,其余一律返回444(连接重置)。
为什么用444而不是403/404?
- 403/404会返回HTTP响应头,暴露Nginx身份
- 444直接断开TCP连接,对端收不到任何信息,扫描器无法识别
三、注册MaxMind并获取许可
MaxMind提供免费的GeoLite2数据库(精简版IP库),虽然精度不如商业版,但对个人用户足够,且更新频率高。许多知名项目(如ELK Stack、Fail2Ban)都采用GeoLite2。
关键步骤:
- 注册账号:访问MaxMind官网注册⚠️ 重要提示:注册时国家选项必须选择非中国地区(包括港澳台)。这是因为MaxMind目前对中国用户限制了City(城市级)数据库的下载权限,仅开放Country和ASN库。由于我们需要精细化的城市级控制,必须绕过这个限制。

- 创建许可密钥:登录后进入”Manage license keys”,点击”Create new license key”
- 记录生成的 Account ID(用户ID)
- 记录生成的 License Key(密钥)


- 确认数据库许可:在”My Downloads”页面查看是否有GeoLite2-City和GeoLite2-ASN的下载权限
- 如无权限,需要在”Manage Subscriptions”中激活免费订阅


为什么不直接下载IP库? 因为IP数据会不断变化,需要定期更新。今天某个IP可能属于北京,明天就可能被重新分配到上海。因此IP库必须定期更新,人工更新显然不现实,这就是为什么我们需要自动化更新方案。
四、Docker部署GeoIPUpdate:自动化IP库更新
IP地理位置数据会不断变化。MaxMind官方提供了geoipupdate容器,可以按设定周期自动拉取最新数据,确保防护规则始终基于最新的IP库。
部署步骤(以绿联NAS为例):
- 拉取镜像:在Docker应用中搜索并下载
maxmindinc/geoipupdate如果下载缓慢,检查网络或更换Docker镜像源。 - 创建容器,配置以下必填环境变量:
GEOIPUPDATE_ACCOUNT_ID=刚刚建立密钥的用户id
GEOIPUPDATE_LICENSE_KEY=刚刚建立的密钥
GEOIPUPDATE_EDITION_IDS=GeoLite2-ASN GeoLite2-City
GEOIPUPDATE_FREQUENCY=24
| 参数 | 说明 | 建议值 |
|---|---|---|
| ACCOUNT_ID | MaxMind账户ID | 必填 |
| LICENSE_KEY | MaxMind许可密钥 | 必填 |
| EDITION_IDS | 要下载的数据库 | GeoLite2-ASN GeoLite2-City(注意空格) |
| FREQUENCY | 更新周期(小时) | 24(太短浪费流量,太长数据陈旧) |

- 配置存储卷(这一步至关重要):
- 容器内路径:
/usr/share/GeoIP - 本地路径:
/mnt/nas/docker/geoip(需与NPM容器共享) - 读写权限:必须同时可读可写
- 容器内路径:


- 网络配置:无需特殊配置,使用默认设置即可。如需此容器开机运行,记得勾选自启动。
- 验证部署:容器启动后,查看日志应显示”Successfully updated”,本地文件夹应出现
.mmdb格式的数据库文件

常见问题排查:
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 下载失败 | 网络连接问题 | 检查NAS网络,或更换Docker镜像源 |
| 权限错误 | 容器无写入权限 | 确保本地文件夹权限为777,或修改容器运行用户 |
| 文件为空 | 许可过期或账户无权限 | 登录MaxMind确认订阅状态 |
五、Docker部署NPM:安装反向代理管理器
部署步骤:
- 拉取镜像:搜索并下载
jc21/nginx-proxy-manager - 创建容器,配置存储卷:
| 容器内路径 | 本地路径 | 用途 |
|---|---|---|
| /data | /mnt/nas/docker/npm/data | NPM配置和证书存储 |
| /etc/letsencrypt | /mnt/nas/docker/npm/letsencrypt | Let’s Encrypt证书 |
| /geoip | /mnt/nas/docker/geoip | GeoIP数据库(与geoipupdate共享) |


- 端口映射:
- NPM管理界面:
8081:81(或其他端口) - HTTPS反向代理:
443:443 - HTTP反向代理:
80:80
- NPM管理界面:
- 启用自启动
- 初始化:
- 访问
http://NAS_IP:8081 - 默认账户:
admin@example.com/changeme - 首次登录后立即修改密码
- 右上角可切换语言为中文
- 访问

六、配置Nginx GeoIP2模块与访问规则
NPM部署完成后,需要停止容器进行Nginx配置。这是整个方案的核心部分。
步骤1:启用GeoIP2模块
进入本地路径 /mnt/nas/docker/npm/data/nginx/custom,新建文件 root_top.conf:
load_module /usr/lib/nginx/modules/ngx_http_geoip2_module.so;
load_module /usr/lib/nginx/modules/ngx_stream_geoip2_module.so;
这两行指令加载GeoIP2模块,使Nginx能够读取和解析IP地理位置数据。

步骤2:配置拒绝规则
同目录下新建 server_proxy.conf:
if ($allow_access = 0) {
return 444;
}
当访问IP不符合规则时,返回444(连接重置)。

步骤3:定义地区与运营商规则(核心配置)
同目录下新建 http.conf:
# ===== 第一层:内网IP白名单 =====
# 用于本地回环和内网访问(如从NAS本地访问)
geo $is_lan {
default 0;
# 根据你的内网网段取消注释
# 0.0.0.0/0 1; # 全网(测试用,生产勿用)
192.168.0.0/16 1; # 常见内网段
# 192.168.8.0/24 1; # 绿联NAS默认网段
# 127.0.0.1/32 1; # 本地回环
# 10.0.0.0/8 1; # 内网段
# 172.16.0.0/12 1; # 内网段
# 172.17.0.0/16 1; # Docker内网段
}
# ===== 第二层:读取GeoIP2数据库 =====
# 从IP库读取城市信息(中文名称)
geoip2 /geoip/GeoLite2-City.mmdb {
$geo_city city names zh-CN;
}
# 从IP库读取运营商ASN信息
geoip2 /geoip/GeoLite2-ASN.mmdb {
$geo_asn_org autonomous_system_organization;
}
# ===== 第三层:允许的城市列表 =====
# 根据你所在城市配置(使用中文)
# 建议同时允许相邻城市,因为4G/5G信号可能跨越城市边界
map $geo_city $is_city_allowed {
default 0;
"广州" 1; # 主要城市
"佛山" 1; # 相邻城市(可选)
# "深圳" 1; # 其他城市
# "珠海" 1;
}
# ===== 第四层:允许的运营商列表 =====
# 根据你使用的运营商配置
# 注意:IDC云服务器的IP不属于三大运营商ASN,会被自动拦截
map $geo_asn_org $is_operator_allowed {
default 0;
# --- 中国电信 (China Telecom) ---
"~*Telecom" 1;
"~*ChinaNet" 1;
# --- 中国移动 (China Mobile) ---
# "~*Mobile" 1;
# "~*CMC" 1;
# "~*CMNET" 1;
# "~*TieTong" 1;
# --- 中国联通 (China Unicom) ---
"~*Unicom" 1;
"~*China169" 1;
"~*CNCGROUP" 1;
# --- 其他小众运营商 ---
# "~*珠江宽频" 1;
# "~*长城宽带" 1;
}
# ===== 第五层:综合判断逻辑 =====
# 规则:内网IP OR (指定城市 AND 指定运营商)
# 即:内网用户无条件放行,外网用户需同时满足城市和运营商条件
map "$is_lan:$is_city_allowed:$is_operator_allowed" $allow_access {
default 0; # 默认拒绝
"~^1" 1; # 内网IP($is_lan=1)直接放行
"0:1:1" 1; # 外网IP需同时满足城市和运营商条件
}

配置说明:
逻辑流程:
请求IP
↓
[检查是否内网IP] → 是 → 放行 ✓
↓ 否
[检查是否在允许城市] → 否 → 拒绝 ✗
↓ 是
[检查是否指定运营商] → 否 → 拒绝 ✗
↓ 是
放行 ✓
关键要点:
- 内网IP和外网规则是或关系(满足任一即可)
- 城市和运营商是与关系(需同时满足)
- 所有IDC云服务器IP会被自动拦截(因为ASN不属于三大运营商)
- 4G/5G流量可能显示为相邻城市,建议同时允许周边城市
验证配置文件:
完成后,/mnt/nas/docker/npm/data/nginx/custom 目录应包含以下三个文件:

custom/
├── root_top.conf # 加载GeoIP2模块
├── server_proxy.conf # 配置拒绝规则
└── http.conf # 定义地区运营商规则
七、启动NPM并验证防护效果
- 重启NPM容器:所有配置立即生效
- 在NPM管理界面添加反向代理:
- 进入”Proxy Hosts”
- 配置上游服务器地址(如NAS内部IP:8080)
- 启用SSL证书(可使用Let’s Encrypt免费证书)
- 保存配置

- 在路由器配置端口映射:
- 将外网80/443端口映射到NAS的80/443端口
- 实战验证:
| 测试场景 | 预期结果 | 验证方法 |
|---|---|---|
| 本地内网访问 | ✓ 正常访问 | 在NAS本地浏览器访问 |
| 指定城市+运营商 | ✓ 正常访问 | 用手机4G/5G访问 |
| 其他城市/运营商 | ✗ 连接被重置 | 用VPN切换到其他地区测试 |
| IDC云服务器IP | ✗ 连接被重置 | 用阿里云/腾讯云ECS访问 |
| 网络扫描器 | ✗ 无法识别 | 在Shodan上搜索你的域名 |
验证命令:
# 查看连接是否被重置(应显示Connection refused)
curl -v http://your-domain.com
# 查看Nginx日志中的GeoIP信息
docker logs npm-container | grep geoip
八、进阶优化与故障排查
常见问题:
Q1:配置后仍被扫描器发现
- 原因:可能未正确返回444,而是返回了403/404
- 解决:检查
server_proxy.conf是否正确加载,查看Nginx错误日志
Q2:正常用户被误拦截
- 原因:IP库数据陈旧或用户地理位置识别错误
- 解决:检查geoipupdate是否正常更新,可临时允许相邻城市
Q3:内网回环访问失败
-
- 原因:内网IP段配置错误
- 解决:运行
ip addr查看实际内网段,更新http.conf中的geo规则
性能优化:
- 缓存GeoIP查询结果:在高并发场景下,可配置Nginx缓存减少数据库查询
- 定期审计日志:监控被拦截的IP,识别异常访问模式
- 备用规则:配置备用的宽松规则,在主规则失效时自动切换
局限性说明:
- 仅限HTTP/HTTPS:此方案对TCP/UDP服务无效,这类服务建议在路由器层面配置防火墙规则
- VPN/代理绕过:用户可通过VPN连接到允许地区后访问,如需防止此情况,需配合其他认证方式
- IP库精度:GeoLite2的城市级精度约95%,个别IP可能识别错误
九、总结与安全建议
这套方案通过地区+运营商的双重过滤,在网络入口层构建了一道有效的防护墙:
✅ 优势:
- 对扫描器完全隐形(返回444不暴露服务信息)
- 自动拦截所有IDC IP(覆盖90%以上恶意来源)
- 配置一次全局生效,无需逐个服务配置
- 完全免费(GeoLite2数据库免费,自动更新)
⚠️ 局限性:
- 仅保护HTTP/HTTPS服务
- 无法防护已知漏洞(需配合WAF或及时补丁)
- 可被VPN/代理绕过(需配合认证机制)
完整安全方案建议:
- 网络层:本方案(地区+运营商过滤)
- 应用层:定期更新系统和应用,修复已知漏洞
- 认证层:启用强密码、双因素认证、IP白名单
- 监控层:部署监控工具,实时告警异常访问
这样多层防护的组合,才能真正保护你的内网安全。
原创文章,作者:kp51,如若转载,请注明出处:https://www.kepu51.com/instant-messaging/634.html
