Loading... # WireGuard 客户端流量与在线状态监控部署实录 # 一、任务概述 ## 1. 背景 办公网 WireGuard 网关(192.168.124.164,接口 office,网段 9.8.0.0/24)承载了 24 个客户端的远程接入,包含员工手机、笔记本电脑以及 xlab 机房的两台 MikroTik 路由器。此前该网关缺少监控能力:客户端是否在线、各自消耗多少流量、谁在抢占带宽均无从知晓,只能手工执行 wg show 排查。 ## 2. 目标 通过 Categraf exec 插件采集 WireGuard 客户端指标并上报夜莺(N9E),实现三类观测能力:客户端在线状态可判断、流量总量可统计、实时速率可排名,并据此设计分组化、条目化的监控仪表盘与告警规则。 ## 3. 环境信息 | 项目 | 值 | |------|------| | 服务器 | 192.168.124.164(mlab-gfw-wireguard) | | 操作系统 | Debian GNU/Linux 12(bookworm),x86_64 | | WireGuard | wireguard-tools v1.0.20210914,接口 office,监听端口 51820 | | 客户端配置 | /etc/wireguard/office.conf,24 个 Peer,地址段 9.8.0.0/24 | | Categraf | v0.4.6,安装于 /opt/categraf,systemd 托管 | | 数据出口 | https://n9e.op123.ren/prometheus/v1/write | | 全局标签 | endname=mlab-wireguard、project=mlab、service=ops | | 采集间隔 | 全局 15 秒,exec 实例 interval_times = 1 | # 二、方案设计 ## 1. 总体架构 ### A. 架构图 ```mermaid graph LR A[wg 内核接口 office] -->|wg show dump 运行时数据| C B[/etc/wireguard/office.conf 静态配置/] -->|注释中的客户端名| C C[wireguard_monitor.sh 每 15 秒执行] --> D[/var/tmp 状态文件 速率差分/] D --> C C -->|Prometheus 文本格式| E[Categraf exec 插件] E -->|远程写入 加全局标签| F[N9E n9e.op123.ren] F --> G[仪表盘 分组面板] F --> H[告警规则] ```  ### B. 数据流说明 运行时数据来自 wg show office dump 输出,每个 Peer 一行,含公钥、预共享密钥、endpoint、AllowedIPs、最近握手时间戳、接收字节数、发送字节数共 8 个字段。静态配置 office.conf 中每个 Peer 上方的注释(如 for jacky android)承载了客户端的友好名称。脚本将两份数据按公钥关联,输出带 interface、name、vip、pubkey 四个标签的 Prometheus 指标,由 Categraf 以 prometheus 数据格式解析并附加全局标签后远程写入 N9E。 ## 2. 关键设计点 ### A. 指标来源与命名 指标统一以 wireguard_ 前缀命名,peer 级指标携带四个标签:interface(接口名)、name(配置注释中的客户端名)、vip(客户端隧道地址,如 9.8.0.4)、pubkey(完整公钥,用于唯一标识)。标签组合保证序列唯一,重复名称的客户端(如多个 jacky)靠 vip 区分。 ### B. 在线判定 WireGuard 本身没有会话概念,判定依据为最近握手时间:脚本将 now 减去 latest handshake 得到握手年龄,年龄小于等于 180 秒(阈值可用环境变量 WG_ONLINE_SEC 调整)判定在线并输出 `wireguard_peer_online` 为 1,否则为 0;从未握手过的客户端年龄输出 -1。 ### C. 速率计算 `wg show` 只提供累计字节数,脚本将每次采样结果写入状态文件 /var/tmp/categraf_wireguard.state(原子写入,且避开 systemd PrivateTmp 隔离),相邻两次采样差分除以间隔得到实时速率 `wireguard_peer_rx_bytes_per_second` 与 `wireguard_peer_tx_bytes_per_second`,与 15 秒采集周期匹配。计数器回绕或接口重启导致的负增量按 0 处理。 # 三、实施过程 ## 1. 环境勘察 确认接口 office 存在 24 个 Peer,多数客户端名称记录在配置注释中;发现 /opt/categraf 最初并不存在,服务器具备 GitHub 访问能力。随后用户自行安装 Categraf v0.4.6 并完成 N9E 出口配置,本任务聚焦采集脚本开发与部署。 ## 2. 脚本开发与问题修复 脚本开发过程中通过真实数据验证并修复了三个解析缺陷: | 问题 | 现象 | 修复方式 | |------|------|---------| | 公钥截断 | 全部客户端名称显示 unknown | WireGuard 公钥为 base64 且以等号结尾,awk -F 分隔符会截断末位,改用 `${line#*=}` 提取 | | 名称残留空格 | for haimeirenyong(双空格注释)解析出前导空格 | 去掉 for 前缀后二次去除前导空白 | | 注释指令误识别 | zhaoqian 名称变成旧公钥注释内容 | 该 Peer 上方存在被注释的旧 PublicKey 行,解析时跳过形如配置指令的注释行 | ## 3. 部署与配置 脚本部署于 /opt/categraf/conf/input.exec/wireguard_monitor.sh,exec 插件配置 exec.toml 要点如下: ```toml [[instances]] commands = [ "/opt/categraf/conf/input.exec/wireguard_monitor.sh" ] timeout = 10 interval_times = 1 data_format = "prometheus" prometheus_ignore_timestamp = true ``` 执行 systemctl restart categraf 生效。 ## 4. 验证结果 手工执行脚本输出 24 个 Peer 的完整指标,名称解析正确,当时 5 个客户端在线;`categraf --inputs exec --test` 解析全部序列无错误,全局标签正确附加;重启后日志出现 input: local.exec started,状态文件持续更新,无远程写入报错。日志中仅有的 4 条 E! 均为与本项目无关的预置插件(amd_rocm_smi、arp_packet、jolokia)不支持提示。 # 四、监控指标体系(分组与条目化) ## 1. 分组总览 监控指标按观测目的划分为五个分组,仪表盘与告警均按此组织: | 分组 | 观测目的 | 指标数 | 面板形态 | |------|---------|-------|---------| | 一、服务总览与可用性 | 采集链路与接口是否正常 | 4 项原始 + 1 项派生 | 单值卡 + 曲线 | | 二、客户端在线状态 | 谁在线、掉线多久、从哪接入 | 3 项 | 状态表格 + 曲线 | | 三、流量总量统计 | 每客户端累计与周期用量 | 2 项原始 + 派生查询 | 柱状量规 + 表格 | | 四、实时流量速率 | 当前带宽占用与排名 | 2 项 + 派生查询 | 时序曲线 + TopN 表格 | | 五、连接库存信息 | endpoint 与地址分配台账 | 1 项 | 标签表格 | ## 2. 分组一:服务总览与可用性 | 条目 | 指标 | 类型 | 单位 | 标签 | 面板类型 | 查询语句 | |------|------|------|------|------|---------|---------| | 1.1 | `wireguard_up` | gauge | 无 | 无 | 单值卡 | wireguard_up | | 1.2 | `wireguard_interface_up` | gauge | 无 | interface | 单值卡 | wireguard_interface_up{interface="office"} | | 1.3 | `wireguard_total_peers` | gauge | 个 | interface | 单值卡 | wireguard_total_peers{interface="office"} | | 1.4 | `wireguard_online_peers` | gauge | 个 | interface | 单值卡 + 曲线 | wireguard_online_peers{interface="office"} | | 1.5 | 在线率(派生) | 派生 | % | interface | 仪表盘 | wireguard_online_peers / wireguard_total_peers * 100 | 说明:1.1 为 0 表示脚本未能发现任何接口(采集链路故障);1.2 为 0 表示接口未在内核中运行,此时客户端仍会以离线状态上报而非序列消失。 ## 3. 分组二:客户端在线状态 | 条目 | 指标 | 类型 | 单位 | 标签 | 面板类型 | 查询语句 | |------|------|------|------|------|---------|---------| | 2.1 | `wireguard_peer_online` | gauge | 0/1 | interface, name, vip, pubkey | 状态表格 | wireguard_peer_online{interface="office"} | | 2.2 | `wireguard_peer_handshake_age_seconds` | gauge | 秒 | 同上 | 曲线 | wireguard_peer_handshake_age_seconds{interface="office"} | | 2.3 | `wireguard_peer_remote_ip` | gauge | 恒为 1 | interface, name, vip, pubkey, remote_ip, remote_port | 标签表格(仅在线) | wireguard_peer_remote_ip{interface="office"} | 说明:2.2 取值 -1 表示该客户端从未握手成功,可直接识别闲置配置;2.1 建议按 name 分组渲染为红绿状态墙;2.3 仅在客户端在线时上报,从 endpoint 解析出远程 ip 与端口(兼容 [IPv6]:port 格式),用于回答“谁在从哪里接入”,下线后序列自然消失。 ## 4. 分组三:流量总量统计 | 条目 | 指标 | 类型 | 单位 | 标签 | 面板类型 | 查询语句 | |------|------|------|------|------|---------|---------| | 3.1 | `wireguard_peer_rx_bytes_total` | counter | 字节 | interface, name, vip, pubkey | 柱状量规 | increase(wireguard_peer_rx_bytes_total[1d]) | | 3.2 | `wireguard_peer_tx_bytes_total` | counter | 字节 | 同上 | 柱状量规 | increase(wireguard_peer_tx_bytes_total[1d]) | | 3.3 | 周期用量(派生) | 派生 | 字节 | 同上 | 表格 | increase(wireguard_peer_rx_bytes_total[30d]),按 name 分组 | | 3.4 | 全接口总量(派生) | 派生 | 字节 | interface | 单值卡 | sum(increase(wireguard_peer_rx_bytes_total[1d])) | 说明:counter 需以 increase 或 rate 消费,禁止直接绘图;周、月周期将 [1d] 替换为 [7d]、[30d] 即可。 ## 5. 分组四:实时流量速率 | 条目 | 指标 | 类型 | 单位 | 标签 | 面板类型 | 查询语句 | |------|------|------|------|------|---------|---------| | 4.1 | `wireguard_peer_rx_bytes_per_second` | gauge | 字节/秒 | interface, name, vip, pubkey | 时序曲线 | wireguard_peer_rx_bytes_per_second{interface="office"} | | 4.2 | `wireguard_peer_tx_bytes_per_second` | gauge | 字节/秒 | 同上 | 时序曲线 | wireguard_peer_tx_bytes_per_second{interface="office"} | | 4.3 | 带宽 TopN(派生) | 派生 | 字节/秒 | name | 排序表格 | topk(5, wireguard_peer_rx_bytes_per_second{interface="office"}) | | 4.4 | 接口总速率(派生) | 派生 | 字节/秒 | interface | 曲线 | sum by (interface) (wireguard_peer_rx_bytes_per_second) | 说明:速率由脚本侧差分计算(15 秒粒度),面板无需再包 rate;网络突发在 15 秒粒度下会被平均,属预期行为。 ## 6. 分组五:连接库存信息 | 条目 | 指标 | 类型 | 单位 | 标签 | 面板类型 | 查询语句 | |------|------|------|------|------|---------|---------| | 5.1 | `wireguard_peer_info` | gauge | 恒为 1 | interface, name, vip, pubkey, endpoint, allowed_ips | 标签表格 | wireguard_peer_info{interface="office"} | 说明:作为 info 型台账指标,表格列直接展示 name、vip、endpoint(客户端出口地址与端口)、allowed_ips(如 9.8.0.35/32, 192.168.86.0/24),可快速判断 MikroTik 子网路由类客户端的地址段。 # 五、仪表盘布局设计 ## 1. 面板分组布局 N9E 仪表盘建议按分组分五行排布,每行使用 Row 折叠组件组织: ```mermaid graph TB R1[Row 1 服务总览 5 个单值卡 + 在线数曲线] --> R2[Row 2 在线状态 状态表格 握手年龄曲线 远程IP表格] R2 --> R3[Row 3 流量总量 日用量柱状量规 + 月度表格] R3 --> R4[Row 4 实时速率 收发曲线 + TopN 排序表] R4 --> R5[Row 5 连接台账 info 标签表格] ```  ## 2. 面板条目清单 | 行 | 面板 | 尺寸建议 | 变量绑定 | |----|------|---------|---------| | Row 1 | 采集状态、接口状态、客户端总数、在线数、在线率 | 五等分单值卡 | 无 | | Row 1 | 在线客户端数趋势曲线 | 整行 | $interface | | Row 2 | 客户端在线状态表(按 name 排序,0/1 着色) | 半行 | $interface | | Row 2 | 握手年龄曲线(阈值线 180) | 半行 | $interface、$name | | Row 2 | 在线客户端远程 IP 表(name、vip、remote_ip、remote_port) | 整行 | $interface | | Row 3 | 日接收量柱状量规、日发送量柱状量规 | 各半行 | $interface | | Row 3 | 月度用量明细表 | 整行 | $interface | | Row 4 | 实时收发速率曲线 | 整行 | $interface、$name | | Row 4 | 带宽 Top5 排序表格 | 整行 | $interface | | Row 5 | 连接台账表格(name、vip、endpoint、allowed_ips) | 整行 | $interface | 仪表盘变量建议定义 $interface(取值 label_values(wireguard_peer_online, interface))与 $name(取值 label_values(wireguard_peer_online, name)),全部面板复用。 # 六、告警规则建议 | 编号 | 规则 | PromQL 表达式 | 持续时间 | 级别建议 | |------|------|--------------|---------|---------| | W1 | 采集链路故障 | wireguard_up == 0 | 3 分钟 | P2 | | W2 | 接口掉线 | wireguard_interface_up == 0 | 1 分钟 | P1 | | W3 | 重点客户端掉线 | wireguard_peer_online{name=~"xlab.*"} == 0 | 5 分钟 | P2 | | W4 | 普通客户端掉线 | wireguard_peer_online == 0 | 15 分钟 | P3 | | W5 | 单客户端带宽异常 | wireguard_peer_rx_bytes_per_second > 10485760 | 5 分钟 | P3 | | W6 | 采集进程消失 | absent(wireguard_up) | 3 分钟 | P2 | 说明:xlab 两台 MikroTik 为机房互联链路,掉线影响子网互通,建议单独高级别告警;W5 阈值 10 MB/s 可按实际带宽调整。 # 七、验证结果与遗留事项 ## 1. 验证结论 部署完成时验证快照:24 个 Peer 全量上报,名称解析正确(含 zhaoqian、双空格注释等边界情况),5 个客户端在线,mac air 13 arm 实时速率约 600 B/s 且随采样刷新,Categraf 解析零错误,N9E 远程写入无报错。 ## 2. 遗留事项 - 仪表盘与告警规则需在 N9E 控制台按第四、五、六章条目手工创建; - 客户端在线判定阈值 180 秒基于默认 25 秒 keepalive 周期,如后续启用 PersistentKeepalive 可适当收紧; - 脚本仓库副本存于本地项目目录 mlab/wireguard(wireguard_monitor.sh、exec.toml、README.md),与服务器部署版本一致,后续修改需双向同步。 # 八、变更记录 ## 1. v1.1(2026-09-17) ### A. 修复:表格时间列显示为 1.789606 G 仪表盘表格面板将 `wireguard_peer_latest_handshake_seconds` 的 unix 时间戳(约 1.79×10⁹)自动格式化为吉咖(G)单位,不可读。处理方式:移除该原始时间戳指标,时间语义统一由 `wireguard_peer_handshake_age_seconds`(握手年龄,单位秒,-1 表示从未连接)承载,数值量级可读。 ### B. 新增:在线客户端上报远程 ip 新增指标 `wireguard_peer_remote_ip`,仅在客户端在线时输出,从内核 endpoint(形如 119.181.52.251:13236)解析出 remote_ip 与 remote_port 两个标签(兼容 [IPv6]:port 格式),用于在表格中直接查看“谁在从哪个公网地址接入”。脚本已同步部署服务器并重启 Categraf 验证,当时 4 个在线客户端均正确上报。 *** ## 参考资料 1. [wireguard_monitor.sh 采集脚本本地副本](/mydata/code/projects/mlab/wireguard/wireguard_monitor.sh) 2. [Categraf 官方仓库](https://github.com/flashcatcloud/categraf) 3. [夜莺监控 N9E 官方文档](https://n9e.didiyun.com/) 最后修改:2026 年 09 月 17 日 © 允许规范转载 赞 如果觉得我的文章对你有用,请随意赞赏