W Watchflare docs
Cette page n'est pas encore disponible en français. Vous lisez la version anglaise.

Architecture

How the Hub, agents, database, and dashboard fit together.

Watchflare is built around four components: agents, the Hub, a time-series database, and a browser dashboard connected via Server-Sent Events.

┌──────────────────────────────────────────────────────┐
│                   Monitored Hosts                    │
│   [ Agent ]      [ Agent ]      [ Agent ]            │
└──────────┬───────────┬──────────────┬───────────────┘
           │           │              │
           │    gRPC / TLS 1.3        │
           ▼           ▼              ▼
┌──────────────────────────────────────────────────────┐
│                       Hub (Go)                       │
│                                                      │
│   gRPC server   ──▶   HeartbeatCache                 │
│   HTTP server   ──▶   TimescaleDB                    │
│   SSE broker    ──▶   Browser                        │
└──────────────────────────────────────────────────────┘

Components

Hub

The Hub is a single Go binary that embeds the frontend and exposes two ports:

  • :8080 — HTTP server: REST API, web dashboard, SSE stream
  • :50051 — gRPC server: receives heartbeats, metrics, and package inventory from agents

The Hub runs alongside a TimescaleDB instance (PostgreSQL with time-series extensions) for persistent storage. Both are deployed as Docker containers.

Agent

The agent is a lightweight Go daemon installed on each monitored host. It communicates outbound only — no inbound ports are opened. On Linux it runs as a dedicated system user (watchflare); on macOS it is managed by Homebrew as the current user.

The agent runs three loops independently:

LoopIntervalWhat it does
Heartbeat5 sSends a presence ping with current IP addresses
Metrics30 sCollects and sends system metrics
Package inventory60s after start, then daily at 03:00Scans installed packages, sends delta

Database

TimescaleDB stores metrics in a hypertable automatically partitioned by time. Continuous aggregates pre-compute 10-minute, 15-minute, 2-hour, and 8-hour buckets — the dashboard queries these instead of raw rows for longer time ranges.

Browser dashboard

The frontend (SvelteKit) receives all live updates via a persistent SSE connection to the Hub. Host status, metrics, and aggregates are pushed as events — the page never polls.


Data flows

Heartbeat & online/offline detection

Agent (every 5s)  ──▶  Hub  ──▶  HeartbeatCache (memory)

                         └──▶  SSE → browser (status: online)

StaleChecker (every 10s):
  no heartbeat > 15s  ──▶  mark offline in cache
                      └──▶  SSE → browser (status: offline)

SyncWorker (every 5min):
  flush cache (status, last_seen, IPs) ──▶  database

On each heartbeat, the Hub updates the in-memory cache and immediately broadcasts an SSE event to the dashboard. No database write occurs — credentials are verified with a single read. The SyncWorker flushes status, timestamps, and IP addresses to the database every 5 minutes. When the StaleChecker detects a missed heartbeat, it marks the agent offline in the cache and broadcasts the offline event directly.

Metrics collection

Agent:
  1. Collect metrics
  2. Append to WAL (local file)
  3. Send to Hub via gRPC
  4. Clear WAL only if send succeeds

Hub:
  → INSERT into TimescaleDB
  → SSE metrics_update → browser

If the Hub is unreachable, metrics accumulate in the agent’s Write-Ahead Log. On the next successful connection, all pending records are replayed in order before new metrics are sent.

Package inventory

Agent (60s after start, then daily at 03:00):
  First run  → full inventory   → Hub upserts all packages
  Next runs  → delta only       → Hub processes added/removed/updated

The delta approach keeps daily payloads small regardless of how many packages are installed.

Agent registration

Registration is a one-time bootstrap that establishes trust between an agent and the Hub:

1. Admin creates a host in the dashboard
   → Hub generates a registration token (wf_reg_...) valid for 24 hours

2. Token is pasted into the install command on the target host
   → Agent calls RegisterHost gRPC (TLS without cert verification — the agent has no CA cert yet;
     authentication relies on the registration token)
   → Hub validates token, returns: agent_id, agent_key, CA certificate

3. Agent saves credentials + CA cert to disk
   → CA is pinned immediately — the agent will reject any certificate not signed by this CA
   → All future gRPC calls use mutual auth (HMAC-SHA256 + pinned CA)

Security model

  • TLS 1.3 on all agent↔Hub communication
  • HMAC-SHA256 signs every gRPC request (agent_id + timestamp + payload). Requests outside a ±5 minute window are rejected.
  • CA pinning — the agent pins the Hub’s CA certificate at registration. It will reject any certificate not signed by that CA.
  • Unprivileged agent — on Linux, runs as system user watchflare with no shell, no home directory, and write access only to its own data directory. On macOS, managed by Homebrew as the current user.
  • One-time tokens — registration tokens are stored as SHA-256 hashes. The plaintext is shown once and never persisted.

Note

The Hub auto-generates its own TLS CA and server certificate on first startup. You can bring your own certificates by setting TLS_MODE=custom. See TLS certificates.


Environment detection

The agent adapts what it collects based on where it runs:

EnvironmentSkips
ContainerDisk, disk I/O, network, swap, temperature
Virtual machineTemperature sensors (no physical hardware access)
Physical hostNothing — full collection