EasyTier 组网设备上线 / 下线 → 群机器人通知(飞书/钉钉/企业微信/Telegram 四渠道可选),带单页 WebUI 的轻量监控小工具。
单容器、无状态依赖(SQLite)、不改动任何现有 EasyTier 部署。适合无头 Linux / NAS / Docker 环境。
easytier-core RPC (127.0.0.1:15888, 容器内自带 easytier-cli 查询)
↑ 每 poll_interval 秒
et-notify 容器(host 网络)
├─ 采集:easytier-cli -o json peer list
├─ 状态机:快照对比 + 双向确认防抖
├─ 通知:飞书/钉钉/企业微信/Telegram 群机器人 webhook(按所选渠道)
└─ WebUI:设备列表 / 事件历史 / 设置 / 测试发送
防抖设计(可调):默认 5 分钟轮询,下线需连续 2 轮未检出才推送(≈10 分钟,吸收网络抖动),上线 1 轮即推。同类工具(gatus / uptime-kuma)同款思路。
设备身份:以 hostname 为主键。EasyTier 的 peer id 是进程活体身份,easytier-core 每次重启都会重新生成——设备重启组网进程不会被误报为"下线+上线",只记一条 process_restart(默认不推送,事件历史可查)。
观察者保护:当受监控设备大面积同轮消失(达到 max(2, ceil(50%)) 且连续 2 轮),更可能是本机与组网失联而非设备集体下线——只记 observer_degraded 并推送一条汇总,不逐台误报。
PublicServer 中继默认不监控(中继闪断常见),可在设置中开启。
| 上线 | 🟢 EasyTier | 设备上线:主机名 |
| 下线 | 🔴 EasyTier | 设备下线:主机名(附"已连续 N 轮未检出") |
字段:主机名 / EasyTier IPv4 / peer id / 版本 / 延迟与丢包(最后观测值)/ 事件时间(Asia/Shanghai)。
四渠道同一套标题与字段:飞书为 interactive 卡片,钉钉/企业微信为 markdown 消息,Telegram 为 HTML 消息。
前置:一台与 easytier 容器同机的 Docker 宿主机(任何架构;easytier 以 --network host 运行,RPC portal 在 127.0.0.1:15888)。
| 渠道 | 创建要点 |
|---|---|
| 飞书 | 目标群 → 设置 → 群机器人 → 添加自定义机器人;安全模式选自定义关键词填 EasyTier;复制 Webhook 地址 |
| 钉钉 | 群设置 → 智能群助手 → 添加机器人(自定义);安全模式选自定义关键词填 EasyTier;复制 Webhook 地址 |
| 企业微信 | 群聊 → 添加群机器人,直接复制 Webhook 地址 |
| Telegram | 找 @BotFather 建 bot 拿 token;把 bot 拉进目标群,用 @userinfobot 等查询群 chat id(负数) |
git clone https://github.com/mydelren/et-notify.git
cd et-notify
# 本机构建运行(与 easytier 同机)
mkdir -p data
docker compose up -d # 默认 linux/arm64,x86 机器: PLATFORM=linux/amd64 docker compose up -d --build
# 或从开发机远程部署到目标机
./deploy.sh <ssh-target> # 可用 BUILD_DIR/DATA_DIR/PLATFORM 环境变量覆盖打开 http://<host>:8390,在设置页选择通知渠道、填写对应地址,先保存,再点"测试推送"(测试使用已保存的设置)。
- 设备列表应与
easytier-cli peer一致(减去本机 Local 行) - 首启只建基线不刷屏
- 重启组网里任一设备的 easytier → 事件历史记
process_restart,无上下线误报
| 设置 | 默认 | 说明 |
|---|---|---|
| notify_channel | feishu | 通知渠道:feishu/dingtalk/wecom/telegram |
| feishu_webhook_url | 空 | 飞书渠道 webhook(仅飞书渠道使用) |
| dingtalk_webhook_url | 空 | 钉钉机器人 webhook |
| wecom_webhook_url | 空 | 企业微信群机器人 webhook |
| telegram_bot_token | 空 | Telegram bot token |
| telegram_chat_id | 空 | 目标 chat id(群为负数) |
当前渠道必填项齐全 = 通知开启;缺任一项则不发送(事件仍入历史)。 | poll_interval_sec | 300 | 轮询间隔,60–3600 | | offline_confirm_rounds | 2 | 下线确认轮数,1–10 | | online_confirm_rounds | 1 | 上线确认轮数,1–10 | | monitor_public_servers | 关 | 是否监控 PublicServer 中继 | | muted_devices | [] | 按设备静音(按 hostname) | | notify_on_offline / notify_on_online | 开 | 分事件类型开关 |
多阶段构建:阶段 1 从 easytier/easytier:v2.6.4 镜像只拷贝静态编译的 easytier-cli 二进制(与 easytier-core 版本锁死),阶段 2 基于 python:3.12-alpine。
升级契约:easytier 容器升级版本后,需同步修改 Dockerfile 中的 tag 并重建本镜像(保证 cli 与 core 的 RPC 方言一致)。不要用 :latest。
- 监控进程与 easytier 同机,该机整机断电/断网不会发通知(观察者盲区,固有)
- 检出延迟最长约
poll_interval × offline_confirm_rounds - 服务宕机期间的短上下线会丢失(轮询固有)
- 真多机同轮消失达到观察者保护阈值时,只出一条汇总不逐台通知
- 改 hostname 会被视为旧设备下线 + 新设备上线
- Telegram 直连 api.telegram.org,大陆网络需自行解决可达性(如容器代理),本工具不提供代理设置
- Telegram / 钉钉 / 企微通知渠道(2026-08)
- amd64/arm64 双架构官方镜像发布
- easytier-web webhook 兼容层(easytier-web 管理的设备直接事件接入)
Lightweight EasyTier mesh device online/offline monitor that pushes group-bot notifications (Feishu / DingTalk / WeCom / Telegram — pick one channel), with a single-page WebUI.
Single container, SQLite only, zero changes to your existing EasyTier deployment. Built for headless Linux / NAS / Docker environments.
easytier-core RPC (127.0.0.1:15888, queried by the bundled easytier-cli)
↑ every poll_interval seconds
et-notify container (host network)
├─ collector: easytier-cli -o json peer list
├─ state machine: snapshot diff + two-way debounce
├─ notifier: Feishu / DingTalk / WeCom / Telegram group-bot webhook (selected channel)
└─ WebUI: device list / event history / settings / test send
Debounce (configurable): default 5-minute polling; a device must be missing for 2 consecutive rounds (~10 min) before an offline notification fires, absorbing network flaps. Online fires after 1 round. Same pattern as gatus / uptime-kuma.
Device identity is keyed by hostname. EasyTier peer ids are per-process (regenerated on every easytier-core restart), so a device restarting its EasyTier process is logged as a process_restart — never a false offline+online pair.
Observer protection: if a large share of monitored devices vanish in the same rounds (≥ max(2, ceil(50%)) for 2 consecutive rounds), it's more likely the observer host lost mesh connectivity than a mass outage — one observer_degraded summary is recorded instead of per-device false alarms.
PublicServer relays are not monitored by default (relay flapping is common); toggle in settings.
| Online | 🟢 EasyTier | Device Online: hostname |
| Offline | 🔴 EasyTier | Device Offline: hostname (with "missing for N rounds") |
Fields: hostname / EasyTier IPv4 / peer id / version / latency & loss (last observed) / event time.
All four channels share the same title and fields: Feishu uses interactive cards; DingTalk/WeCom use markdown messages; Telegram uses HTML.
Prerequisite: a Docker host on the same machine as your easytier container (any arch; easytier running with --network host, RPC portal at 127.0.0.1:15888).
| Channel | How |
|---|---|
| Feishu | Group → Settings → Group bots → Add custom bot; security mode custom keyword EasyTier; copy the webhook URL |
| DingTalk | Group settings → Group bot → add custom bot; security mode custom keyword EasyTier; copy the webhook URL |
| WeCom | Group chat → add a group-bot robot; copy the webhook URL directly |
| Telegram | Create a bot via @BotFather to get the token; add it to the target group and look up the group chat id with @userinfobot (negative number) |
git clone https://github.com/mydelren/et-notify.git
cd et-notify
mkdir -p data
docker compose up -d # defaults to linux/arm64; on x86: PLATFORM=linux/amd64 docker compose up -d --build
# or deploy remotely from a dev machine
./deploy.sh <ssh-target> # override with BUILD_DIR/DATA_DIR/PLATFORM env varsOpen http://<host>:8390, pick your notification channel in Settings, fill in its credentials, save first, then hit "Test send" (the test uses saved settings).
- Device list matches
easytier-cli peer(minus the local row) - First start builds a baseline without spamming
- Restart any peer's easytier → a
process_restartevent, no false offline/online
| Setting | Default | Notes |
|---|---|---|
| notify_channel | feishu | notification channel: feishu/dingtalk/wecom/telegram |
| feishu_webhook_url | empty | Feishu-channel webhook (used by the Feishu channel only) |
| dingtalk_webhook_url | empty | DingTalk bot webhook |
| wecom_webhook_url | empty | WeCom group-bot webhook |
| telegram_bot_token | empty | Telegram bot token |
| telegram_chat_id | empty | target chat id (negative for groups) |
Notifications are enabled when all required keys of the selected channel are filled; otherwise nothing is sent (events still land in history). | poll_interval_sec | 300 | 60–3600 | | offline_confirm_rounds | 2 | 1–10 | | online_confirm_rounds | 1 | 1–10 | | monitor_public_servers | off | monitor PublicServer relays | | muted_devices | [] | per-device mute (by hostname) | | notify_on_offline / notify_on_online | on | per-event toggles |
Multi-stage: stage 1 copies only the statically-linked easytier-cli binary from easytier/easytier:v2.6.4 (version-pinned with easytier-core); stage 2 is python:3.12-alpine.
Upgrade contract: after upgrading your easytier container, bump the tag in the Dockerfile and rebuild (keeps cli/core RPC dialects in sync). Never use :latest.
- The monitor runs on the same host as easytier — that host losing power/network means no notifications (inherent observer blind spot)
- Detection latency is up to
poll_interval × offline_confirm_rounds - Short online/offline blips during service downtime are lost (inherent to polling)
- Genuine mass disappearance meeting the observer threshold yields one summary, not per-device alerts
- Renaming a hostname reads as old-device-offline + new-device-online
- Telegram connects to api.telegram.org directly — mainland-network reachability (e.g. container proxy) is on you; this tool ships no proxy setting
- Telegram / DingTalk / WeCom channels (2026-08)
- Multi-arch official image publishing
- easytier-web webhook compatibility layer