Self-Hosting the Relay

The relay is a stateless WebSocket router. It validates connection metadata, emits join events, and forwards application frames unchanged. It does not create channels with a separate command, decrypt payloads, store messages, or require a WebSocket subprotocol header.

Build from source

bash
cd walletpair-relay
cargo build --release
./target/release/walletpair-relay

Connection

text
ws(s)://<relay-host>/v1?ch=<channel-id>&name=<name>&url=<url>&icon=<icon-url>&pubkey=<x25519-public-key>
FieldValidation
chExactly 64 lowercase hexadecimal characters.
name1–128 UTF-8 bytes; no control characters.
urlAbsolute http: or https: URL, at most 2048 UTF-8 bytes.
iconAbsolute https: URL, at most 2048 UTF-8 bytes.
pubkeyCanonical unpadded base64url, 32 decoded bytes, not all zero.

Join event and routing

After a client joins, the relay sends this JSON text frame to every active connection in that channel, including the new connection. A client waits for its own event before sending application frames.

json
{
  "type": "channel_joined",
  "ch": "<channel-id>",
  "name": "Example Wallet",
  "url": "https://wallet.example",
  "icon": "https://wallet.example/icon.png",
  "pubkey": "<base64url-x25519-public-key>"
}
  • Text and binary application frames are forwarded unchanged to every other active connection in the same channel.
  • The sender does not receive its own application frame.
  • There is no cross-channel forwarding and no replay for later joiners.

Deployment note

Each in-memory channel must remain on one relay instance. Use TLS for public traffic and configure load balancing for channel affinity if you run multiple instances.