Privacy, all the way down

Your relay. Your server. Your rules.

Remoude’s default relay already sees only ciphertext. If that’s not enough, run the relay yourself — it’s a single zero-dependency file, and the encryption never depended on trusting it in the first place.

The trust boundary

A relay that cannot read what it carries

The whole design assumes the relay is untrusted. Every message body is sealed with ChaCha20-Poly1305 using a key derived from your pairing secret via HKDF-SHA256 — and that key never leaves your Mac and your phone.

So a fully compromised relay still can’t read a single request or forge an “Allow.” Self-hosting doesn’t add a security guarantee so much as shrink the one piece of metadata anyone else could ever see: that a pairing id and a device token are linked.

  • Sealed bodies — the AEAD key is on your devices only.
  • The topic id is a one-way HKDF of the secret — never the secret.
  • Zero dependencies, one file, Node ≥ 18 — auditable in an afternoon.
# derived from your secret S (HKDF)
topic id  remoude/v2/topic → relay sees
auth token remoude/v2/auth  → relay sees
enc key   remoude/v2/key   → relay never
 
# therefore, on the wire
body → 🔒 ciphertext
forge “allow” → impossible
What you have to trust

Two independent planes

Remoude splits into two hops you can host separately. Only one of them is unavoidably centralized — and even that one sees nothing but an opaque blob.

Message relay — fully yours

Carries questions, verdicts, and instructions, all sealed. No Apple key required. Self-host it and even the routing metadata stays on your own box.

Push wake-up — one hop

Only wakes your phone. An APNs key belongs to an Apple team, so the App Store build can only be woken by the author’s key — which sees a device token and an encrypted blob, nothing else.

Pick your tier

From “just works” to “fully independent”

1

Default

Both planes on the hosted relay. Simplest — and it still only ever sees ciphertext.

2

Privacy-max

Self-host the message relay. Only the wake-up push touches the author’s service, and it learns nothing but a token and a blob.

3

Fully independent

Build the app with your own bundle id and APNs key, then run both planes. Nothing of the author’s is in the path.

Run it

One file. No npm install.

The relay is built-ins only. Point the Mac installer at your host and the pairing QR carries the URL to the phone — no app rebuild.

your-server — relay
# relay-only (pub/sub, no pushes) — good for a quick look
node server.mjs

# turnkey on a fresh Ubuntu/Debian VPS: Node + Caddy + hardened systemd
scp -r backend your.p8 root@vps:/root/
ssh root@vps
cd backend && sudo bash deploy/setup-vps.sh   # prompts for domain + APNs

# then point your Mac at it — the QR hands the URL to the phone
REMOUDE_RELAY=https://your-relay bash mac/install.sh

TLS is required — the pairing QR embeds an https:// relay URL. Fly.io, Railway, and Render work too: point them at server.mjs and mount the .p8 as a secret.

Don’t take our word for it. Read the relay.

It’s one zero-dependency file. The trust boundary is right there in the source.