Multi-Region, One Core per Region (Distributed)
One mistershell/core per region, joined into a single core-to-core mesh, sharing one central set of data services. Users and workers connect to the core closest to them.
This is one of four supported topologies. For the shared reference (environment variables, TLS, web-session flags, worker registration, scaling, troubleshooting), see the Deployment overview.
Components involved
| Component | Who runs it | Role |
|---|---|---|
| One core per region | You (MisterShell) | Each region runs a single core. The cores federate through cross-region gateways into one mesh, so a session captured in one region is visible cluster-wide. |
| GSLB (geo load balancer) | You (external) | Steers each user/worker to the nearest healthy region and fails traffic over to another region when one is down. |
| Central database | You (external) | One shared relational store all regions read and write. Mandatory. |
| Central app-state store (App Redis) | You (external) | One shared live-session / lock / coordination store. Mandatory, maxmemory-policy noeviction. (Cluster leadership itself is coordinated through the central database.) |
| Central object store | You (external) | One S3/Azure bucket for recordings from every region. |
| Per-region workers | You (optional) | Workers attach to their regional core to reach local resources with low latency. |
What is NOT under MisterShell’s responsibility
- The GSLB and geographic steering. MisterShell does not decide which region a request lands in. You run a health-checked global DNS/anycast layer;
MISTERSHELL_URLresolves to it, and workers re-resolve it on reconnect, so the GSLB is the cross-region failover mechanism. - Inter-region network reachability between the cores on the cross-region gateway port
7222(TLS-secured). Open it between your regional core subnets. - The central data tier’s availability and its latency. All regions share one database and one App Redis. Their HA is yours, and so is the reality that regions far from the data tier pay a round-trip on writes — place the central store near your write-heavy region, or use a managed globally-distributed database.
- Object store durability.
- TLS termination / DNS / certificates for the regional entry points.
In-region redundancy: none — by design
This topology gives you geographic distribution, not per-region high availability. Each region is a single core:
- If a region’s core fails, that region is offline until it restarts. The GSLB should steer that region’s users/workers to another region in the meantime.
- Each region’s event streams are single-replica (
R=1), so any in-flight, not-yet-finalized data on a lost core is lost until it returns. Finalized recordings (already written to the central object store) are safe.
If you need a region to survive the loss of a core, use Distributed with HA.
Architecture
flowchart TB
uUS["Users / Workers · US"]
uEU["Users / Workers · EU"]
gUS["GSLB (VIP)"]
gEU["GSLB (VIP)"]
cUS["Core<br/>region = us-east"]
cEU["Core<br/>region = eu-west"]
uUS --> gUS
uEU --> gEU
gUS --> cUS
gEU --> cEU
cUS <-. "gateway :7222 · super-cluster (TLS federation)" .-> cEU
state[("Central external state<br/>Database · App Redis · Object store<br/>HA + latency are yours")]
cUS --> state
cEU --> state
Benefits
- Locality. Users and workers hit the nearest region, so interactive sessions and local task execution have low latency.
- Region-local capture. A session’s live I/O and recording stream stay within the capturing region until finalized, then land in the central object store — no cross-region hop on the hot path.
- Smaller blast radius per region. A regional outage is contained; the GSLB routes elsewhere.
- Simpler than full HA. One core per region is the lightest way to gain a geographic footprint when per-region redundancy isn’t required.
Prescriptive deployment guidance
Per-region core environment
Every core shares the same DB_ENCRYPTION_KEY, central DATABASE_URL, and central APP_REDIS_URL; each gets a distinct THIS_CORE_REGION and its own inter-core address:
| Variable | US core | EU core |
|---|---|---|
THIS_CORE_URL | http://core.us-east.internal:8000 | http://core.eu-west.internal:8000 |
THIS_CORE_REGION | us-east | eu-west |
DATABASE_URL | central DB (same for both) | central DB (same for both) |
APP_REDIS_URL | central App Redis (same for both) | central App Redis (same for both) |
DB_ENCRYPTION_KEY | same secret | same secret |
THIS_CORE_REGION must match ^[a-z0-9-]+$ (≤32 chars) and becomes the region’s cluster name. With one core per region, NATS_STREAM_REPLICAS naturally resolves to 1 — leave it unset.
Example: launch the two regional cores
# US region
docker run -d -p 443:443 -p 80:80 \
-e DB_ENCRYPTION_KEY=your-secret-key \
-e THIS_CORE_URL=http://core.us-east.internal:8000 \
-e THIS_CORE_REGION=us-east \
-e DATABASE_URL=postgresql+asyncpg://user:pw@db.central.example.com:5432/mistershell_db \
-e APP_REDIS_URL=redis://app-redis.central.example.com:6380/0 \
-v mistershell_us_data:/data \
--name mistershell-us \
mistershell/core:latest
# EU region — same central DATABASE_URL / APP_REDIS_URL, different region + inter-core URL
docker run -d -p 443:443 -p 80:80 \
-e DB_ENCRYPTION_KEY=your-secret-key \
-e THIS_CORE_URL=http://core.eu-west.internal:8000 \
-e THIS_CORE_REGION=eu-west \
-e DATABASE_URL=postgresql+asyncpg://user:pw@db.central.example.com:5432/mistershell_db \
-e APP_REDIS_URL=redis://app-redis.central.example.com:6380/0 \
-v mistershell_eu_data:/data \
--name mistershell-eu \
mistershell/core:latest
Each core keeps a persistent /data volume even with the data tier externalized: it holds the region’s event store — the in-flight session and recording streams this page’s redundancy note describes — so recreating the container without the volume discards any not-yet-finalized regional data.
Network
- Open the cross-region gateway port
7222between the regional core subnets so the super-cluster can federate. This is the only inter-region port the cores need. - Ensure both regions can reach the central database and App Redis.
GSLB
- Give each region a health-checked entry (
GET /health/ready), and configure the GSLB to steer to the nearest healthy region and fail over when one is down. - Point
MISTERSHELL_URLat the GSLB name so workers pick their nearest region and re-resolve on reconnect.
Recordings
Configure a shared cloud recording store (S3/Azure) under Govern → Recording Policy → Stores and point your recording rules at it — with regions this is effectively required, since any region’s core may finalize a recording. The built-in Local store writes to each core’s own disk and is not appropriate here. See Recording Policy → Add a cloud recording store.
When to choose something else
| If you need… | Move to |
|---|---|
| Each region to survive losing a core | Distributed with HA |
| Redundancy but only one region | HA Cluster |
| A single-host workspace | All in One |