
作者简介
感谢本文作者蔡斯,Zabbix社区签约专家,Zabbix6.0、7.0官方译者。
一
背景:免费穿透工具的管理之痛
本文以「穿透工具A」为例,演示如何借助 Zabbix 低级别发现(LLD)+ HTTP 代理打造一次配置、"终身"自治的监控体系,支持无限横向扩展。
二
HTTP 代理:Zabbix 的
"万能数据采集器"
通过「穿透工具A」 REST 接口我们把它“拉”进Zabbix监控,实现多账号多设备零侵入纳管。
三
「穿透工具A」接口长什么样?
注:本文中不涉及任何用户隐私数据或敏感信息,所有数据均为示例数据,使用这些浏览器暴露接口的行为是基于技术研究和学习目的,并且不用于任何商业或非法用途。
POST/user/flow_stat
{
"rtn": 0,
"data": {
"ddnsBytes": 1782357604,
"relayBytes": 259885
}
}
字段 | 说明 |
|---|---|
ddnsBytes | 累计直流流量(单位字节),需 ÷ 1024³ 转 GB |
relayBytes | 累计中转流量(单位字节),需 ÷ 1024³ 转 GB |
POST/ddns/cfg/list
作用:列出当前账号下所有已创建的 DDNS 映射条目,供 LLD 用。
{
"rtn": 0,
"datas": [
{
"id": xxxx,
"peerid": "xxxx",
"domain": "xxx.iepose.cn",
"protocolLan": "https",
"lanAddr": "192.168.0.xx:5001",
"status": true,
"uid": "xxxxx",
"comment": "群晖NAS",
....
}
]
}
字段 | 说明 |
|---|---|
rtn | 0 = 成功 |
datas[].id | 映射记录内部 ID(示例:xxxxx → MAP_ID) |
datas[].peerid | 节点唯一标识(示例:AD1***OW → NODE_ID) |
datas[].domain | 暴露给外网的域名(示例:xxx.iepose.cn → EXAMPLE_DOMAIN) |
datas[].lanAddr | 内网地址端口(示例:192.168.0.19:1234 → 192.168.x.x:PORT) |
datas[].status | true = 映射在线 |
datas[].checkin | true = 心跳正常 |
GET/jdis/bindget?作用:拉取账号下所有已绑定设备,含网卡、版本等信息,供 LLD 用。
{
"terms": [
{
"peerid": "xxxx",
"term": {
"nic": [
{
"mac": "xxxxxxxxxx",
.....
],
"name": "LAPTOP-MICLE",
"ip": xxxxxxx,
"isp": "联通",
"location": "深圳",
..........
},
"role": 1
},
{
"peerid": "XXXXXXXXXXXXXXXXX",
.....
}
字段 | 说明 |
|---|---|
terms[].peerid | 设备唯一 ID |
terms[].term.name | 设备别名 |
terms[].term.status | 设备在线状态,出现status则表示掉线 |
terms[].term.ip | 大端序格式 → 需结合预处理转为十进制 IP |
terms[].term.nic[].ipv4n | 网卡 IP(大端序整数格式) |
terms[].term.nic[].mac | 原始 MAC → 需格式化为 XX:XX:XX:XX:XX |
terms[].term.nbhttp / nbhttps | 「穿透工具A」对外 HTTP/HTTPS 端口 |
GET/jdis/servicelist?
作用:列出每台设备代理的内网的服务及端口,供 LLD 用。
{
"jd": [
{
"ip": 151038144,
"dtype": 999,
"status": 1,
"name": "grafana",
"ports": [
3000
],
"svs": [
{
"port": 3000
}
],
"peerid": "XXXXXXXXXXXXXXXXXXX",
},
......
]
}
字段 | 说明 |
|---|---|
jd[].ip | 大端序格式 → 需结合预处理转为十进制 IP |
jd[].name | 服务名称(如 grafana、DSM、路由器) |
jd[].ports | 端口数组,可一对多 |
jd[].status | 1 = 正常运行 |
将以上 JSON 汇总后喂给 Zabbix LLD,即可实现 账号-设备-流量-服务 四维自动发现。
四
LLD 规则:让「穿透工具A」接口
“自报家门”
flow.stathttps://xxx.xxx.com/user/flow_statPOST-H 'accept: application/json, text/plain, */*' -H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0'调试监控项

结合HTTP 代理采集回来的数据,我们可以自带相关项目方法关联它,单位是字节B。

然后通过预处理JSONPath将这些JSON格式的数据轻松分离作为一个单独的监控项,好处就是减少采集次数,充分利用已有数据。

接着我们来验证一下,配置的参数是否正确,毕竟这是Zabbix UI给我们提供极简的scriptsless,无需通过手写scirpts即可完成debug。

观察最新采集的数据,中转和直流流量已正确识别出来。

对比「穿透工具A」控制台的流量数据。

创建 LLD 规则的目标是暴露采集同类型不同规格的参数,为了减少对HTTP 代理的依赖,我们在创建LLD规则前,需要先建立一个普通的监控项。
cfg.listhttps://xxx.xxx.com/ddns/cfg/listPOST-H 'accept: application/json, text/plain, */*' -H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0'调试监控项

cfg.discovery{#NATID}{#NATDOMAIN}预处理(JavaScript 统一转换)暴露宏变量
var res = JSON.parse(value);
var lld = [];
res.datas.forEach(function(item){
lld.push({
"{#NATID}" : item.id,
"{#NATDOMAIN}" : item.domain
});
});
return JSON.stringify({data: lld});
老道理,同样通过测试步骤,输入RESP接口采集回来的JSON数据进行加工测试,得到{"data":[{"{#NATID}":xxxx,"{#NATDOMAIN}":"xxxx.iepose.cn"}]},如下图。

在LLD 自动发现规则中创建监控项原型,才能继用它暴露的宏变量,这里演示如何获取穿透的内网地址。
lanAddr[{#NATID}]如下图所示:

结合预处理JSONPath和正则匹配$.datas[?(@.id=="{#NATID}")].lanAddr,成功匹配到内网代理IP和端口

查看最新采集的数据,内网协议,内网地址,映射开启状态均已显示。

对比「穿透工具A」控制台的内网穿透配置,完全一样!

创建 LLD 规则的目标是暴露采集同类型不同规格的参数,为了减少对HTTP 代理的依赖,我们在创建LLD规则前,需要先建立一个普通的监控项。
bind.gethttps://xxx.xxx.com/jdis/bindgetGETuid=xxx&owcode=xxx&product=2581&cache_ver=0.29773539924079817调试监控项

dev.discovery{#PEERID}{#NAME}预处理(JavaScript 统一转换)暴露宏变量
// 只遍历顶级 terms,每台设备生成 1 条发现记录
var lld = [];
var root = JSON.parse(value);
root.terms.forEach(function(node){
var t = node.term;
lld.push({
"{#PEERID}" : node.peerid,
"{#NAME}" : t.name
});
});
return JSON.stringify({data: lld});
同样通过测试步骤,输入RESP接口采集回来的JSON数据进行加工测试,得到{"data":[{"{#PEERID}":"xxx","{#NAME}":"xxx"},{"{#PEERID}":"xxx","{#NAME}":"xxx"}]},如下图。

在LLD 自动发现规则中创建监控项原型,才能继用它暴露的宏变量,这里演示如何获取穿透的公网IP。
ip["{#NAME}"]如下图所示:

结合预处理JSONPath和正则匹配$.terms[?(@.peerid=="{#PEERID}")].term.ip,可获取到大端序的IP地址。
预处理(JavaScript 统一转换)
function intToIP(i){
return [
i & 0xFF, // 最低字节 → 第 1 段
(i >>> 8) & 0xFF, // 次低字节 → 第 2 段
(i >>> 16) & 0xFF, // 次高字节 → 第 3 段
(i >>> 24) & 0xFF // 最高字节 → 第 4 段
].join('.');
}
return intToIP(parseInt(value));
再结合JavaScrips进行转换,可得出最终IP地址。

因篇幅原因,本节不做展开,和以上同理。
五
基于自动发现创建监控原型和触发器
「穿透工具A」 API
│
├─ HTTP Agent → LLD 规则 → 生成宏 {#PEERID} {#NAME} {#NATDOMAIN} …
│ │
│ ├─ Item Prototype
│ ├─ Trigger Prototype
│ └─ Graph Prototype
│
└─ 新节点上线 → 自动纳入监控,无需人工干预
字段 | 示例 |
|---|---|
Item Prototype Key | net.tcp.service[tcp,{#SERVICEIP},{#SERVICEPORT}] |
Trigger Prototype | last(/OWJDXB by HTTP/net.tcp.service[tcp,{#SERVICEIP},{#SERVICEPORT}])=0 |
实践得知,Linux和Docker系的「穿透工具A」客户可以获取宿主机的总内存和已用内存,指令类似free -m 单位 MB ,需要通过预处理倍数 1024x1024进行转换,单位Units 填 B,因为Zabbix不支持MB。

通过HTTP 代理我们还可以将内网穿透条目中的公网域名纳入监控,判断其标题如果出现:XX无法打开页面即表示网络或者客户端出现问题。
HTTP 代理web.title.check[{#NATID}]{#PROTOCAL}://{#NATDOMAIN}(?i)<title[^>]*>([^<]*)</title>

六
「穿透工具A」监控实战
首次需登录「穿透工具」控制台,打开F12找到list链接,点击负载获取你的UID和OWCODE。

回到Zabbix添加主机,关联我们制作好的「穿透工具A」监控专用模板。

配置宏变量,其中·{UID}和{OWCODE}是前面获取的,{

在仪表盘中,我们添加TOP主机类型组件,即可得到多个账号多个设备在线状态、账号级的流量数据。后续结合Grafana,可扩展出更多的列表数据,如设备的出口IP,映射公网域名等。


中转设备代理的服务,即内网服务掉线则会发出告警:

中转设备掉线,通过HTTP 代理及JavaScrip匹配映射出来的DDNS条目(访问域名)进行实时访问的页面标题,判断是否在线。

七
总结
HTTP 代理结合预处理中的JSONPath和JavaScript,模拟浏览器将「穿透工具A」的REST接口返回的Json数据进行过滤和匹配,结合Zabbix LLD规则将多中转设备的数据纳管到监控原型中,实现一个都不能少的目标。作为抛砖引玉,笔者选「穿透工具A」作为功能演示,提供一种零侵入、零配置的监控思路和实现方案。
笔者注:文中所提及的工具名称仅为示例,不代表任何特定品牌或产品;使用本文中的方法和技术时,请确保遵守相关法律法规和服务条款。