Self-hosting the relay
Apex Relay forwards opaque, end-to-end encrypted payloads between your paired devices. It is content-blind by construction: it cannot read your vault or credentials, only route ciphertext. You can use the managed instance or run your own — both modes are content-blind, and self-hosting means you don’t have to trust anyone’s routing but your own.
Topology
Section titled “Topology”Apex Relay is designed to run behind a TLS-terminating reverse proxy (NGINX, Caddy, Traefik, or a cloud load balancer) that forwards to the local process.
Internet clients ├─ HTTPS requests ─┐ └─ WSS connections ─┴─> TLS-terminating reverse proxy (public) └─ HTTP/WS on a private network ─> Apex Relay (PORT=3000)Required production settings
Section titled “Required production settings”Set these environment variables in production:
NODE_ENV=productionCORS_ORIGINS— explicit HTTPS origins, comma-separatedREQUIRE_TLS_IN_PRODUCTION=trueTRUST_PROXY_HEADERS=trueSTRICT_CORS_ORIGINS=true
If NODE_ENV=production and REQUIRE_TLS_IN_PRODUCTION=true, startup fails unless TRUST_PROXY_HEADERS=true — a guard against accidentally serving without TLS in front.
Reverse-proxy headers
Section titled “Reverse-proxy headers”Configure your proxy to pass:
X-Forwarded-Proto: httpsX-Forwarded-For: <client-ip>X-Forwarded-Host: <public-hostname>Host: <public-hostname>
For WebSocket upgrades, also forward:
Upgrade: websocketConnection: upgrade
Container defaults
Section titled “Container defaults”The image runs with:
NODE_ENV=productionPORT=3000DATA_DIR=/data
It exposes port 3000 and reports liveness at GET /api/health.
Point your devices at it
Section titled “Point your devices at it”In the Apex app, set the relay endpoint to your instance’s public HTTPS/WSS URL. Pairing and vault contents are unaffected — your vault still never leaves the phone; the relay only routes the encrypted messages between your devices.
Verify
Section titled “Verify”curl -fsS https://relay.example.com/api/healthA healthy instance returns a success response. If it fails, check that your proxy terminates TLS, forwards the headers above, and that TRUST_PROXY_HEADERS=true is set.