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.
This is applied live — you do not re-run setup.sh anywhere. Adding a
site changes what every existing site’s peer list should contain, so any
design where replication config only lands via setup.sh means an operator
ritual on every node, and silently divergent replication until they perform
it. That is not how it works:
slapdruns from thecn=configdynamic backend (converted from the generatedslapd.confseed at container start), which makesolcServerIDandolcSyncreplmodifiable while it is serving.- Theta Directory converges its own running config whenever the cluster changes — a spoke registering or being removed, a join, a resync, a promotion, and at boot, plus a periodic sweep as a backstop. It reads the live config, computes the delta, and applies only what differs, so re-applying the same state is a no-op.
- No restart, no downtime, no operator step. A site that was offline while the cluster changed converges on its own when it comes back.
ServerID uniqueness is enforced by a unique index on the master’s registry,
not just by the allocation code. Two spokes registering at the same instant
used to be handed the same ID, which does not error anywhere – it quietly
breaks replication, because ServerID is how syncrepl tells originators
apart. A master upgrading from a build that had this bug repairs any existing
duplicates at startup (the oldest registration keeps its ID; the others are
moved and re-read theirs on the next reconcile) and logs each reassignment.
The Multi-Site modal still shows this node’s live ServerID/peer count, and
still badges Peer list out of sync if the running config and the cluster’s view
ever disagree. That badge is now a fault indicator, not an instruction: it
means the automatic path failed somewhere (a spoke that could not reach its
master, an ldapmodify that was rejected) and is worth investigating rather
than papering over. Under normal operation it never appears.
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.