Files
theta-suite/docs/sso/multi-site.md
T
wmantly ace7b441c2 docs(site): publish multi-site + gateway mesh to the actual docs website
Everything shipped this pass (live replication, master/spoke join,
gateway-to-gateway WireGuard mesh) had real spec docs in the repo
(docs/MULTI_SITE_SPEC.md, sso-manager-node's docs/site-join.md) but
nothing on the actual published docs site (theta42.github.io/theta-suite/)
-- a reader landing there would find no mention of it at all beyond a
vague, unlinked "multi-site replication" bullet on the homepage.

- New docs/sso/multi-site.md: the operator-facing master/spoke join guide
  (why, how, promoting a spoke, what replicates, current limits), with an
  explicit section distinguishing it from the pre-existing N-way LDAP MMR
  replication page (replication.html) -- two different mechanisms that
  were at real risk of being conflated with nothing to tell them apart.
- New docs/jump-host/mesh.md: the gateway-to-gateway WireGuard mesh guide,
  linked from a "WireGuard mesh routing" bullet that already existed on
  the jump-host homepage but pointed nowhere.
- docs/sso/index.md, docs/jump-host/index.md: link the new pages from
  each component's Features list.
- docs/index.md: replaced the oversold, unlinked "multi-site replication
  running in seconds" homepage copy with an accurate, linked claim.
2026-08-10 19:54:25 -04:00

5.3 KiB

layout, title
layout title
default Multi-Site (Master/Spoke Join)

Multi-Site (Master/Spoke Join)

If you run more than one physical site, Theta Directory can run one site as the master (single write authority for the shared catalog) and any number of spokes — read-only replicas that stay in sync automatically and run local authentication with zero WAN dependency.

This is a different, higher-level mechanism than raw LDAP N-way replication — see How this relates to LDAP replication below if you're deciding between the two.

Why and when to use this

  • Zero-touch spoke setup. One join key, one URL, and a spoke adopts the whole directory (users, groups, resource catalog) in one step — no manual syncrepl configuration.
  • Single write authority, no split-brain. Only the master accepts directory writes. A spoke that loses WAN connectivity keeps working for local reads/auth and unconditionally stays read-only — it never silently promotes itself. Changing which site is master always requires an explicit, authenticated action by a god_admin.
  • Stays in sync, not just a one-time copy. Once joined, a spoke keeps receiving live updates whenever the master's catalog changes — you don't re-run the join to pick up new hosts/apps/users.

How it works

  1. On the master, an admin mints a site join key (Directory → the Master Site modal → Site Join Keys → Mint key). It's shown once, stored hashed, and revocable.
  2. On the spoke (must be a fresh install — no users beyond the bootstrap admin, no enrolled agents), either:
    • Paste the master's URL and the join key into the Master Site modal's Join an Existing Site form, or
    • Set CFG_MASTER_DIRECTORY_URL / CFG_MASTER_DIRECTORY_JOIN_KEY in setup.env before the first ./setup.sh run.
  3. The spoke pulls the master's full export (LDAP tree, resource catalog, agent-signing key) and adopts it, then registers its own reachable URL with the master so it can receive live updates going forward.
  4. From then on, every change to the master's catalog pushes to every registered spoke automatically. A spoke's own directory-write requests are rejected with a 403 pointing at the master — writes always go there.

Promoting a spoke to master

If the master site goes down for good (or you're relocating write authority), a god_admin can promote any spoke from its own Master Site modal. Promotion is one coordinated action: it demotes the previous master as part of the same request (best-effort — an unreachable old master never blocks the promotion, since that's exactly the scenario this exists for), and every other spoke gets pointed at the new master automatically.

What replicates

Data How
LDAP (users, groups) Full export on join; live push on every master change
Resource catalog (hosts, apps, sites) Same
Agent-signing key Same — every site can validly sign a command for any agent enrolled at any site

The agent-signing key being identical everywhere is a deliberate tradeoff for small, trusted deployments (a handful of sites, not hundreds) — it means compromising the least-secured spoke has the same agent-command blast radius as compromising the master. If that tradeoff doesn't fit your deployment, don't rely on this mechanism as-is.

Secrets beyond the agent-signing key (LDAP admin password, JWT secret, and so on) are not currently synced — each site still generates its own.

Requirements and current limits

  • Both sites need a network path to each other's HTTP(S) API — the master to pull an export from, the spoke to push replication updates back to. A site with no inbound path at all (e.g. behind CGNAT) can't join yet on its own; a relay mechanism for that case is designed but not automated (see the architecture spec for the current status).
  • Joining only ever happens on a fresh install. There's no way to merge an already-populated directory into a master's — re-provision the host first.

How this relates to LDAP replication

N-way LDAP replication is a lower-level, different mechanism: every site runs a fully independent, fully writable slapd, wired together with raw syncrepl environment variables, and there's no concept of a master or a managed join. It predates this feature and is still there for deployments that specifically want every site independently writable.

Multi-site join (this page) is the opposite design: one write authority, a managed onboarding flow, and automatic ongoing sync — closer to what most "add a second office" or "add a home-lab spoke" setups actually want. Don't combine the two — pick one per deployment.

See also