Skip to content

Hosting your own relay

You don’t have to use the public relay — the relay server (manabrew-server) is self-hostable. It handles lobbies, matchmaking, and message relay between players; it never runs games itself. Every player’s client (web or desktop) runs the engine, and the relay just passes messages between them.

The relay authenticates every client with a single shared key (MANABREW_SERVER_KEY, default forge). The same key must be given to the web client (RELAY_PASSWORD) and to any self-hosted node (SELF_HOSTED_NODE_SERVER_KEY). It is a shared access token, not a per-user secret.

The image is published on Docker Hub, so no checkout is needed. Create a compose.yml:

services:
relay:
image: ghcr.io/witchesofthehill/manabrew-server:latest
environment:
MANABREW_SERVER_KEY: "${MANABREW_SERVER_KEY:-forge}"
RUST_LOG: "manabrew_server=info"
ports:
- "9443:9443" # WebSocket lobby/game traffic
- "9444:9444" # health endpoint
restart: unless-stopped

Then bring it up:

Terminal window
MANABREW_SERVER_KEY=pick-a-key docker compose up -d

To build the image yourself instead of pulling, replace the image: line with a build: block (needs a repo checkout):

build:
context: .
dockerfile: manabrew-rs/crates/manabrew-server/Dockerfile

The relay now accepts WebSocket connections on ws://your-host:9443 and serves http://your-host:9444/health. Point your clients and any node at ws://your-host:9443.

All settings are environment variables:

VariableDefaultPurpose
FORGE_HOST0.0.0.0Bind address
FORGE_PORT9443WebSocket listen port
FORGE_HEALTH_PORT9444HTTP /health port
FORGE_MAX_ROOMS100Maximum concurrent rooms
MANABREW_SERVER_KEYforgeShared key clients and nodes must present
RUST_LOGinfotracing env-filter (e.g. manabrew_server=debug)

The relay speaks plain ws:// and does no TLS itself. For a public deployment, put it behind a TLS-terminating reverse proxy (Caddy, nginx, …) and connect over wss://. The web client dials wss:// automatically when its relay port is 443 — see Hosting the web client. The full-stack example wires the relay and web client together behind one Caddy instance, and compose.production.yml in the repo root is the complete production deployment.