Skip to content

Cluster

Paco5687 edited this page Jul 13, 2026 · 5 revisions

Cluster

Run secwatch on several boxes and join them into a peer-to-peer cluster — there is no central hub to stand up or defend. Every node stays fully autonomous (it detects and bans itself); nodes gossip bans so a hit on one hardens all, and any peer can view the whole fleet from its own dashboard.

How it works

  • Explicit join, shared secret — like a Proxmox cluster. A node only joins if it has the secret; there's no auto-discovery, so a random box on the LAN can't join, read, or inject.
  • HMAC-signed peer traffic — the secret never crosses the wire; requests are timestamped to bound replay. Use TLS or a WireGuard tunnel if the inter-node path isn't trusted.
  • Ban gossip, two ways — a new ban is pushed to reachable peers immediately and every node periodically pulls each peer's blocklist, so convergence is robust and a firewalled node still hardens itself by pulling. Received bans are applied locally and are poison-safe: secwatch refuses to ban a trusted or shared-edge (e.g. Cloudflare) IP, so a bad entry can't take out a legit address.
  • Federated view — open any peer's Cluster tab and it assembles the fleet by querying its peers; no data is centralized.

Roles

Set cluster.role per node — nothing is hard-coded:

Role For Behavior
standalone not clustered (default) no cluster activity
peer internal / trusted boxes full member: shares bans, is queryable, reads peers
leaf exposed / less-trusted boxes push-only: contributes its bans + events and pulls the blocklist, but is not queryable and can't read peers

Why a leaf? Your internet-facing box is your riskiest one. As a leaf it still contributes to fleet hardening and stays visible, but a compromise of it can't be used to read your internal fleet's telemetry or poison the shared blocklist. A leaf also only makes outbound connections, so its port can stay firewalled — ideal for a box on an isolated VLAN.

Setup

The easy way — the dashboard. Open the Cluster tab on any node and:

  • Create cluster — pick a role, click Create, and copy the shared secret it shows you.
  • Join cluster — paste a peer's URL and that secret.

No CLI and no restart — the node starts participating immediately. Manage peers, reveal the secret to add more nodes, or leave the cluster, all from that tab.

The CLI below does the same thing if you prefer the shell or are scripting it.

On the first node:

# secwatch.yaml:  cluster: { role: peer, url: http://THIS-NODE:8931 }   → restart
python -m secwatch.cluster init          # prints the shared secret — copy it

On each other internal node (peer):

# secwatch.yaml:  cluster: { role: peer, url: http://THIS-NODE:8931 }   → restart
python -m secwatch.cluster join http://FIRST-NODE:8931 '<secret>'

On an exposed node (leaf):

# secwatch.yaml:  cluster: { role: leaf }   (no url — a leaf isn't queried)   → restart
python -m secwatch.cluster join http://A-PEER:8931 '<secret>'

CLI: python -m secwatch.cluster {init | join <url> <secret> | list | leave <name> | ping <url>}.

Networking

  • Peers reach each other on their secwatch port (default 8931).
  • A leaf needs only outbound reach to a peer's port — nothing inbound — so an exposed box can keep its port firewalled from everything, including the cluster.
  • Keep secwatch's port off the public internet.

Verify

Open a peer's dashboard → Cluster tab (it appears only when clustered) → all nodes are listed with liveness, role, event and ban counts. Ban an IP on one box and watch it appear on the others within a gossip cycle (cluster.gossip_secs, default 60s), attributed as cluster:<origin-node>.

Clone this wiki locally