Self-host
The relay is dumb, zero-knowledge transit: it moves ciphertext and queues it
for offline devices, and never holds a key. That’s true whether it’s the
managed relay at api.chime.sh or one you run yourself — self-hosting is a
deployment choice, not a different security posture. See
Security for exactly what the relay can and can’t see.
The default: managed, at api.chime.sh
Section titled “The default: managed, at api.chime.sh”Out of the box, chime points at the managed relay — zero infra for you.
This is what Quickstart uses. If you want zero third
parties in the path, or you’re offline/air-gapped, run your own relay
instead; the two paths below are for that.
Local relay for development
Section titled “Local relay for development”chime init --localStarts a local chime relay instance and prints its URL. Subsequent pairing
uses it once you export CHIME_RELAY_URL=... as instructed. This is the
fastest way to develop against Chime without touching the managed relay.
Run the relay directly
Section titled “Run the relay directly”chime relay [-addr :8080] [-db PATH]The relay is a sub-command of the same single chime binary you already
installed — there’s nothing extra to download. It’s a self-contained
zero-knowledge transit server with an embedded SQLite store (-db :memory:
for an ephemeral instance, useful for testing).
To make it reachable from your phone:
- Behind a Cloudflare Tunnel (outbound-only, no inbound port to open) —
bind the relay to
127.0.0.1:8080and letcloudflaredfront it, with TLS terminated at the Cloudflare edge. - On a plain LAN or VPS URL — point the app at that URL directly during pairing.
Either way, the app is told the relay’s URL once, at pairing time, and uses it from then on.
A self-hosted relay has no accounts, no Chime Cloud, and no managed push gateway attached — the app gets messages while it’s foregrounded (or via its normal reconnect/poll behavior), rather than a background push wakeup. That tradeoff is the whole point for a “zero third parties” or air-gapped setup; end-to-end encryption is identical either way.
Deploying the managed stack yourself
Section titled “Deploying the managed stack yourself”If you want to run your own copy of the exact production stack — Cloudflare
Workers + Durable Objects, the same topology api.chime.sh runs — the
relay/ and infra/ directories in the repo are the whole thing. Briefly,
because the full runbook belongs in the repo, not copied here and left to go
stale:
- No VM, no SSH, no inbound port, no tunnel to operate. The relay is a stateless Cloudflare Worker in front of Durable Objects; Cloudflare runs the compute.
- Two tools, two disjoint ownership boundaries.
wranglerdeploys the Worker script, the Durable Object classes, their bindings/migrations, and the push-gateway secrets. OpenTofu (infra/) owns the surrounding zone resources — the DNS custom domain that points your domain at the Worker, edge SSL/HSTS, a WAF ruleset, and an edge rate-limit ruleset. Tofu state is encrypted and stored in R2; secrets live in your OS keychain, never in files. - Ordering matters. The Worker has to be deployed with
wrangler deploybefore the firsttofu apply— the custom domain binds to an already-existing Worker by name.
The full first-time-setup runbook, token scopes, rotation procedures, and
troubleshooting table live in
infra/README.md
in the repo.