Skip to content
User Guide

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

ComponentWho runs itRole
One core per regionYou (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 databaseYou (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 storeYou (external)One S3/Azure bucket for recordings from every region.
Per-region workersYou (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_URL resolves 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:

VariableUS coreEU core
THIS_CORE_URLhttp://core.us-east.internal:8000http://core.eu-west.internal:8000
THIS_CORE_REGIONus-easteu-west
DATABASE_URLcentral DB (same for both)central DB (same for both)
APP_REDIS_URLcentral App Redis (same for both)central App Redis (same for both)
DB_ENCRYPTION_KEYsame secretsame 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 7222 between 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_URL at 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 coreDistributed with HA
Redundancy but only one regionHA Cluster
A single-host workspaceAll in One