Self-hosting a relay¶
Hive's reference relay is a small Rust (axum) service in the main repo at
crates/hive-relay/. No database — it forwards encrypted event envelopes
between the devices in a workspace and holds queued events in memory. You host
one relay that your peers point at.
Fastest path: see the ready-to-go recipes (Docker, Fly.io, Render) in
deploy/relay/ and the small-team deployment guide.
The shortest local smoke test:
# from the repo root
cargo run -p hive-relay # binds 0.0.0.0:8443
# or containerized:
docker build -f deploy/relay/Dockerfile -t hive-relay . && \
docker run -p 8443:8443 hive-relay
Health check: curl http://localhost:8443/v1/health → ok.
The rest of this page covers a from-scratch deploy on a VM you control.
You need:
- Linux (Ubuntu 22.04+ / Debian 12+) or macOS on a host reachable from your peers.
- A domain with TLS (Let's Encrypt via Caddy is easiest), or use a PaaS that terminates TLS for you.
- One TCP port open.
Step 1 — Build¶
The binary lands at target/release/hive-relay. It has no resource
dependencies — copy it anywhere.
Step 2 — Run¶
The bind address is chosen in this order:
$PORT(set by Render / Cloud Run / Railway / Heroku) →0.0.0.0:$PORT$HIVE_RELAY_ADDR(fullhost:port)- default
0.0.0.0:8443
Optional: gate the relay with access tokens¶
By default the relay is open — anyone with the URL + room may connect (this
is the normal self-host mode; a workspace key keeps traffic private regardless).
If you want to restrict who can connect at all (e.g. you're running a relay for
a paid group), set HIVE_RELAY_ACCESS_TOKENS to a comma-separated allowlist:
Now only requests bearing Authorization: Bearer <one-of-those> are admitted
(/v1/health stays open). Each peer pastes their token into Settings → Team
sync → Relay access token (or sets HIVE_RELAY_ACCESS_TOKEN). Unset/empty ⇒
open, as before. This is a coarse on/off gate, not per-member roles — see the
managed-service plan in the repo for the finer-grained direction.
Step 3 — TLS termination¶
The relay speaks plain HTTP; put TLS in front. A two-line Caddyfile:
Caddy fetches and rotates a Let's Encrypt cert automatically. Nginx + Certbot works too. (PaaS hosts like Fly.io / Render terminate TLS for you — no proxy needed there.)
Step 4 — Run as a service (Linux / systemd)¶
/etc/systemd/system/hive-relay.service:
[Unit]
Description=Hive Relay
After=network-online.target
[Service]
ExecStart=/usr/local/bin/hive-relay
Environment=HIVE_RELAY_ADDR=0.0.0.0:8443
Restart=always
User=hive
Group=hive
[Install]
WantedBy=multi-user.target
Step 5 — Point Hive at it¶
In every peer's app: Settings → Team sync — set the Relay URL
(https://relay.example.com), a shared Room id, and (strongly recommended) a
shared Workspace key, then Save. If you gated the relay with
HIVE_RELAY_ACCESS_TOKENS (above), also paste each peer's Relay access token;
leave it blank for an open relay. Changes apply within a few seconds, no restart.
Devices on the same relay URL + room converge.
Environment variables (
HIVE_RELAY_URL/HIVE_WORKSPACE/HIVE_WORKSPACE_KEY/HIVE_RELAY_ACCESS_TOKEN) still work as first-launch seeds, but the in-app settings are the source of truth after that.
Step 6 — Verify¶
Create a chat on one device; within a few seconds it appears on the others (transcript, agents, proposals, reactions, and skills all flow through the same path).
Security¶
By default the relay is open — anyone with the URL + room id can join that room. Three things control access:
- Set a workspace key. With it, every envelope is sealed with
ChaCha20-Poly1305 before it leaves the device; the relay only ever stores
ciphertext. Settings shows
🔒 encryptedwhen it's on. This is what keeps your data private even on an open relay. - Use an unguessable room id. To revoke read access, rotate the key and/or room.
- Optionally gate connections with
HIVE_RELAY_ACCESS_TOKENS(see above) if you want to restrict who can reach the relay at all.
The access-token gate controls connection, not per-member roles. Workspace membership/removal is enforced client-side today (removal re-keys so an ejected member can't read new traffic); server-enforced membership is on the roadmap for managed/paid relays.
Operations¶
- Single instance, in-memory. Run one machine; don't scale out. A restart drops anything peers haven't pulled yet (durable storage is a tracked follow-up).
- Memory grows with
(workspaces × devices × queued events)— tiny for a small team. CPU is negligible.
Where the source lives¶
crates/hive-relay/ (the axum service + routes). It depends only on
hive-core types + a small async/HTTP stack, so lifting it into a standalone
repo is a mechanical move when that fits your workflow.