English | 简体中文
A clean Tailscale node monitoring dashboard.
index.html— the web dashboard frontend.widget/— NodeWidget, a floating desktop widget with a built-in control-panel backend.archive/— archived: the Python backendserver.pyand the standalone AI status card AiWidget (no longer maintained, seearchive/README.md).
- Overview stats: total / online / offline / exit nodes / keys expiring soon / updates available.
- Node cards: status, OS, version, IP, tags, connection path (direct/relay/local), latency + latency trend sparkline, rx/tx traffic.
- Node detail modal: click a card to see FQDN, IPv4/IPv6, owner, distro, version/updates, connection & latency trend, traffic, last handshake, key-expiry countdown, exit/subnet routes (enabled vs pending approval), SSH, and per-DERP-region latency.
- Ops alerts: keys expiring in ≤7 days turn yellow, ≤3 days red; nodes with updates get an
⬆ updatebadge; toasts pop up bottom-right when nodes go offline, recover, or join. - Search / filter: by hostname / IP / OS / tag; quick filters for all / online / offline / exit.
- Multi-language: switch between English / 简体中文 / 日本語 / Deutsch / Français / Español in the toolbar (defaults to English, saved in browser localStorage).
- Access highlighting: hover a node card to see which devices it can talk to, computed from your tailnet ACL policy — green
⇄mutual, amber→the hovered device can reach it, blue←it can reach the hovered device; unrelated cards dim. When there are too many cards to fit on screen, click the crosshair button in a card's bottom-right corner to focus: the grid collapses to just that device plus its related ones (sorted mutual → outbound → inbound). Esc / the focus bar / clicking the button again exits.
| source | condition | content |
|---|---|---|
live |
TS_API_KEY configured |
Admin API device list + local tailscale status --json overlay for real direct/relay paths |
local |
no API key, but tailscale is installed and connected locally | local tailscale status --json only (direct/relay available, no latency numbers) |
| other | backend not running / network down / no data source configured | the frontend shows no fake data — just a full-screen blur with an offline note, retrying every 8s |
Conn path detection (from the local machine's perspective): CurAddr non-empty → direct (shows the peer endpoint); otherwise Relay set → relay (shows the DERP region, e.g. via SIN); the machine itself → local.
A browser-free, always-on desktop mini window showing each node's basics (status light, hostname, IP, direct/relay, latency + mini latency sparkline, offline duration). Square-cornered window.
- Zero dependencies: C# built with the .NET Framework 4.8 toolchain that ships with Windows;
widget\build.cmdproduces a singleNodeWidget.exe(~19KB, ~35MB RAM, idle CPU ≈ 0) - Automatic data-source fallback: prefers the dashboard backend
/api/nodes; callstailscale status --jsondirectly when the backend is down; shows offline when neither is available - Interactions: drag with the left mouse button; right-click menu — always on top / pin to desktop (stays under all windows, above the wallpaper; mutually exclusive with always-on-top) / privacy mode (masks hostnames and IPs) / language (6 languages, default English) / refresh now / open control panel / exit
- Position and toggles are remembered in
widget.ininext to the exe
cd widget
build.cmd # build
NodeWidget.exe # run
- Generate an API access token (
tskey-api-...) in the Tailscale admin console. - Copy the config template (Windows PowerShell):
Edit
Copy-Item .env.example .env.envand fill in at leastTS_API_KEY(TS_TAILNETcan stay-). - Start the backend: run
widget\NodeWidget.exe, right-click it and check "Open control panel" (built-in backend, bound to 127.0.0.1, local access only). - Open http://localhost:8787 in your browser.
| variable | description | default |
|---|---|---|
TS_API_KEY |
Tailscale API token, required | — |
TS_TAILNET |
tailnet name, - means the token's default |
- |
PORT |
listen port | 8787 |
TS_DETECT_EXIT |
detect exit nodes (reads advertisedRoutes, no extra requests) |
1 |
TS_CACHE_TTL |
/api/nodes cache TTL in seconds |
5 |
TS_CA_BUNDLE |
custom/corporate root CA PEM path (for TLS-intercepting proxies; archive/server.py only) |
— |
TS_INSECURE |
1 disables TLS verification, debugging only (insecure) |
0 |
- Latency: from the Admin API's
clientConnectivity(latency to DERP); shows—when unavailable. No latency numbers inlocalmode. - Connection path: from local
tailscale status --json, i.e. the path from this machine to that node (results differ on another machine). Showsn/awithout the local CLI. - Online detection:
connectedToControlfirst, thenonline, falling back tolastSeenfreshness (within 5 minutes). - TLS-intercepting networks: the built-in backend uses the Windows certificate store — once the proxy's root certificate is installed system-wide, verification just works.
- Access highlighting: a simplified frontend evaluation of the ACL policy (fetched via the backend's
/api/aclproxy, requiresTS_API_KEY; disabled inlocalmode). Supports*, user emails,group:,tag:,autogroup:member/tagged/self, IPv4/CIDR andhostsaliases; port granularity is ignored (any allowed port counts as access). Unsupported selectors (role autogroups,ipset:, posture,via) are treated as no-match — it may under-highlight, never falsely highlights.
GET /api/nodes returns:
{
"source": "live",
"tailnet": "your-org.ts.net",
"nodes": [
{
"host": "ts-gateway-01",
"os": "linux",
"ip": "100.64.0.1",
"status": "online",
"lastSeen": null,
"conn": null,
"latency": 8,
"tags": ["server", "exit-node"],
"exit": true,
"version": "1.78.1"
}
]
}source is one of live (real data), local (local CLI only), or error (no key configured or API error).
