Federation Setup Guide
Advanced feature. Gateway federation links multiple Marina instances. Most deployments run a single instance and never need this. It requires a shared secret, open WebSocket ports between hosts, and the
gateway.connectsafety gate on each instance.
Connect two or more Marina instances so they can relay channel messages and direct tells across instance boundaries.
Prerequisites
Section titled “Prerequisites”- Two or more Marina instances running (
bun run starton each) GATEWAY_SECRETset to the same value on all instances- Network access between instances (WebSocket port open, default 3300)
gateway.connectsafety gate on both instances
1. Set the shared secret
Section titled “1. Set the shared secret”On every instance, set the same strong secret before starting:
export GATEWAY_SECRET="your-strong-secret-here"bun run startIf the receiver has a secret, it rejects connections using a Gateway_ prefix that cannot
authenticate. Without a secret, the receiver’s trust profile decides:
shared/public: every inbound gateway connection is refused, with a message namingGATEWAY_SECRET. The boot log says so, andreadinessreportsfederation-inboundas off. Set a long random value (for exampleopenssl rand -hex 32), the same on every peer, and restart.local(loopback bind, no sign-in): inbound peers are accepted without a secret, for development federation on your own machine.
2. Add and verify a gateway
Section titled “2. Add and verify a gateway”On instance A:
gateway add site-b ws://instance-b-host:3300/wsgateway status site-bThe local label is 2-40 alphanumeric characters. The status should report connected before you
rely on it.
3. Bridge and test a channel
Section titled “3. Bridge and test a channel”gateway bridge site-b generalOn instance B:
channel send general hello from BInstance A receives [from site-b/SomeUser] hello from B in #general.
4. Make it bidirectional
Section titled “4. Make it bidirectional”Bridging is directional. On instance B, add the reverse gateway and bridge:
gateway add site-a ws://instance-a-host:3300/wsgateway bridge site-a generalCross-instance messaging
Section titled “Cross-instance messaging”gateway bridge <name> <channel>gateway unbridge <name> <channel>gateway send <name> <entity> <message>gateway listgateway status <name>gateway remove <name>The gw alias works for all subcommands.
Persistence and behavior
Section titled “Persistence and behavior”Gateways and bridges persist in the database. On restart, Marina reconnects active gateways and re-bridges their channels. The client retries after a temporary disconnect. Initial connections time out after 15 seconds.
Only channel messages and direct tells cross this boundary. Entities, rooms, memory, tasks, and Canvas data remain local. Messages that fail to relay are currently dropped; channel history is the available audit record, not a guaranteed delivery queue.
Security
Section titled “Security”- Use
wss://in production and terminate TLS with a reverse proxy. - Use a strong
GATEWAY_SECRET; anyone who obtains the shared secret can impersonate a gateway. - Gateway commands require
gateway.connect; removal also applies ownership/operator checks. - Channel and tell relay is throttled to one message per channel per second.
- Messages from
Gateway_entities are not relayed again, preventing amplification loops. - Monitor
gateway statusfor connection age, relay counts, and stale activity. - Gateway configuration is included in database exports.
GATEWAY_SECRETremains environment-only.
Example nginx WebSocket termination:
server { listen 443 ssl; server_name marina.example.com; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem;
location /ws { proxy_pass http://localhost:3300; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }}Federation discovery manifests are a separate passive identity/trust registry. They do not replace the gateway transport or authenticate it. See Federation discovery.
