The published docs site had drifted from what actually shipped: - docs/sso/multi-site.md said the no-inbound relay was "designed but not automated" -- it's been automated since earlier this session. Also said "don't combine" multi-site join and LDAP replication -- they're integrated now (join auto-configures LDAP MMR). - docs/sso/replication.md (the actually-published/linked replication page -- distinct from theta-directory's own docs/replication.md, which isn't linked from this site's nav at all) still only described the old fully-manual LDAP_SERVER_ID/LDAP_REPLICATION_HOSTS setup, with zero mention of the new auto-config or CFG_LDAP_MMR_MANUAL. - docs/index.md's feature bullet described multi-site purely as "N-Way Multi-Master LDAP replication" -- the actual master/spoke join feature (the more commonly-used, higher-level mechanism) wasn't mentioned on the homepage at all. - CFG_PUBLIC_DOMAIN (shipped, never documented anywhere an operator would read it) now explained in multi-site.md. - spoke.env now discoverable from quickstart.md, not just multi-site.md. Also documents the real, load-bearing limitation from this session's promotion/LDAP-orphan fix: the master's own replication peer list only updates on its own next setup.sh run, not live the instant a spoke joins or a promotion happens.
4.3 KiB
layout, title
| layout | title |
|---|---|
| default | Geo-Location Scaling (Replication) |
Geo-Location Scaling (Replication)
Theta Directory bundles its own identity provider, but if you have multiple physical sites, you may want a local copy of the directory at each site to ensure low latency and high availability.
Why and when to use this?
- High Availability (HA): If your primary site goes completely offline, your other sites can still authenticate users locally without depending on a WAN link.
- Low Latency: Applications at a remote site can bind directly to their local LDAP server (
localhostor LAN IP) instead of traversing the internet to query the primary site, making logins blazing fast. - Independent Failure Domains: By replicating only the LDAP directory (the source of truth) and keeping session state (Redis) independent, you prevent complex "split-brain" scenarios in the web UI. A failure at Site A won't bring down Site B.
By default, the sso-manager Docker container runs a single, independent OpenLDAP instance. However, you can enable N-Way Multi-Master Replication via environment variables.
How it works
In an N-Way Multi-Master setup, every site runs a fully active OpenLDAP server (slapd).
- Reads and Writes anywhere: A user can change their password or update their profile at Site A, Site B, or Site C.
- Conflict Resolution: OpenLDAP's
syncreplengine uses Context Sequence Numbers (CSN) to track changes. If Site A goes offline and a user changes their password at Site B, Site A will automatically pull the newest changes the moment it rejoins the cluster. - Independent Redis: Session data, API Tokens, and OAuth Clients are stored in Redis. By design, Redis is NOT replicated in this geographic setup. This ensures that a failure at Site A never causes Site B's Redis to become read-only, which would break the web UI at Site B. OAuth clients must be configured per-site.
Configuration
The container's entrypoint reads two environment variables to configure this
-- LDAP_SERVER_ID (a unique integer for this node) and
LDAP_REPLICATION_HOSTS (a space-separated list of every other node's
LDAP URL) -- and, when both are set, automatically loads the syncprov
module, enables mirrormode, and generates the necessary syncrepl blocks
in /etc/openldap/slapd.conf.
Automatic config via Multi-Site join
If you're using Multi-Site join (CFG_MASTER_DIRECTORY_URL/spoke.env),
you don't set these by hand. The master assigns each spoke a unique
LDAP_SERVER_ID at join time (the same way it assigns a WireGuard mesh
index) and derives LDAP_REPLICATION_HOSTS from every site's already-known
HTTPS endpoint (ldaps://<same-host>:636) -- theta-suite's bootstrap/ site-ldap-register.js applies it and re-checks on every setup.sh run,
since the peer list grows as new spokes join, restarting sso-manager only
when the computed config actually changed.
Known limitation: the master's own LDAP_REPLICATION_HOSTS only gets
recomputed when its setup.sh is re-run — there's no live push telling an
already-running master about a spoke that joined five minutes ago. Re-run
setup.sh on the master after bringing up a new spoke (or after promoting
one to master) to pick up the current peer list. A spoke's own config, by
contrast, is re-checked and applied on every setup.sh run there, which is
the common/recurring event.
Manual configuration
Have a topology outside a theta-suite-managed cluster (fully independent,
always-writable sites, no master/spoke concept)? Set
CFG_LDAP_MMR_MANUAL=true to skip the automatic path entirely and set the
two variables directly -- without this, the automatic step runs on every
deployment (every fresh install starts as a master) and will overwrite them.
Site 1
LDAP_SERVER_ID=1
LDAP_REPLICATION_HOSTS="ldaps://sso.site2.com:636 ldaps://sso.site3.com:636"
Site 2
LDAP_SERVER_ID=2
LDAP_REPLICATION_HOSTS="ldaps://sso.site1.com:636 ldaps://sso.site3.com:636"
Site 3
LDAP_SERVER_ID=3
LDAP_REPLICATION_HOSTS="ldaps://sso.site1.com:636 ldaps://sso.site2.com:636"
User Locations
When creating or editing a user, you can specify their Location (Site). This maps directly to the standard LDAP l (localityName) attribute, allowing you to track which physical site a user belongs to natively within the directory.