Skip to content

Self-hosting the relay

The short version, stated up front: you can self-host the whole connective tier. The open repo ships a selfhost/ bootstrap that brings up the relay, the API, and Postgres with one command, and a tally seat pointed at it provisions, syncs, and runs rooms end to end. This page shows that path, and it still says plainly what the packaged experience does not cover.

This page is the trust escape hatch, so it holds itself to the same discipline as the security model: what works is shown, what does not work is said plainly.

What self-hosting buys, and what it does not

Section titled “What self-hosting buys, and what it does not”

Confidentiality does not depend on who runs the relay. The relay handles ciphertext whether we run it or you do; that is the structural property, and it is already yours on the hosted relay. What self-hosting removes is your dependence on us for availability (nobody can withhold your ciphertext) and metadata (channel names, sizes, timing stop flowing through our infrastructure). Those are real reasons, and they are the honest ones.

Licensing, factually: the protocol, relay, SDK, and kernel crates are Apache 2.0. The API service directory (api/) is BSL 1.1 with a grant that expressly allows exactly this: self-hosting for yourself or your organization. What the BSL forbids is offering it to third parties as a hosted or managed service. Details on the licensing page.

From the open source tree:

Terminal window
cd skytale/selfhost
./up.sh

The script generates the shared secrets once (JWT secret linking API to relay, an internal secret, a database password; all kept out of git), renders the two config files from their examples, builds the release binaries, provisions a private Postgres cluster, starts relay and API, runs the database migrations, and waits for both health endpoints. ./down.sh reverses all of it. A --docker variant with a compose file exists; it is authored but not yet runtime-verified on our side, and the script path is the proven one.

Then point a tally seat at your stack:

Terminal window
tally config set api_url http://127.0.0.1:3100
tally config set relay_url http://127.0.0.1:8443
tally signin
tally connect

Explicit --api-url/--relay-url flags and the SKYTALE_API_URL environment variable override the config keys when present (flag beats env beats config).

What has been verified end to end against exactly this stack, with nothing pointing at skytale.sh: account mint, the full device-grant provisioning flow, tally push and tally pull restoring a log onto a second home, and a two-seat room (create, invite, join, admit, messages decrypting in both directions). The relay archive was checked afterward: ciphertext only.

One honest note on that flow: a second device with the same identity recovers via tally signin --recover plus copying the relay credential file; a same-identity second connect is refused by the seat-uniqueness guard by design.

The open relay serves the WebSocket at both shapes: bare /ws with subscribe frames (the historical surface for custom clients) and per-channel /ws/<channel> (the shape tally speaks, matching the hosted relay), plus HTTP catch-up at GET /v1/messages and GET /v1/sync and a bounded per-channel ciphertext archive. The one setting that matters most is jwt_secret: when set, the relay requires a valid HS256 Bearer JWT on the WebSocket and catch-up endpoints; the bootstrap generates and wires this for you.

Terminal window
curl http://localhost:8443/health
{"status":"ok","uptime":42}

What the packaged experience does not cover

Section titled “What the packaged experience does not cover”
  • TLS is your reverse proxy. The bootstrap serves plain HTTP on loopback, which is also the only plain-HTTP mode the tally client permits. Anything beyond one machine needs your proxy terminating TLS in front of both services.
  • No signup email, no billing. The self-hosted API mints accounts directly; email verification and Stripe routes are non-functional behind placeholder keys, deliberately.
  • The hosted directory will not validate your tokens. Your stack signs JWTs with your own secret; the hosted api.skytale.sh signs with ours. The two do not mix, by design.
  • Custom clients over your own relay: works today, from the open source, with your own JWT minting.
  • Tally seat sync and rooms over your own stack: works today, via the selfhost/ bootstrap and the flags shown above, verified end to end.