eleven / messenger Public
π€ Relay mode β self-hosting with zero routing
lchat relay is the permanent sibling of lchat try (issue #738, Phase 1): your instance runs on your own machine, dials out, and keeps a stable public hostname β no port forward, no domain, no DNS, no certificate, no root. Ships dormant: it only works against a gateway that offers a relay domain, and the fleet gateway doesn't yet.
lchat relay # run a space from ./lchat-relay.db, keep it relayed
lchat relay --local 127.0.0.1:1747 # relay an instance you already runWhat makes a relay different from a trial
| | lchat try | lchat relay | |---|---|---| | Hostname | random, dies with the process | claimed by your keypair, permanent | | Lifetime | 24 hours max | unlimited | | Disconnect | address retires | address sleeps (503) for a grace window, then retires; reconnect revives it | | Reconnect | new address | same address, automatic (backoff β€ ~32s) | | Admission | 5/IP/hour | same for new claims; reconnects are never rate-limited |
Everything else is identical: the door probe (only Eleven instances), the per-tunnel connection cap, the re-probe every 10 minutes, and the E2EE posture β the relay carries the same ciphertext any Eleven server carries.
The identity
On first run the client writes an Ed25519 seed to <db>.relay-id (or lchat-relay.id with --local, or --identity <path>). The file is the hostname: claiming works by signing a gateway nonce, so whoever holds the key holds the name. Back it up; lose it and the name is gone (the gateway operator can free an orphaned claim by deleting its row in the claims db).
Wire shape (internal/tunnel): hello carries mode:"relay"; the gateway answers challenge{nonce}; the client sends claim{pubkey,sig}. A hello without mode is a trial and follows the original flow byte-for-byte, so old clients are unaffected.
Gateway operations
lchat tunnel serve --relay-domain <domain> [--claims /data/tunnel-claims.db] [--max-relays 200] [--claim-idle-days 45]- Use a dedicated domain, not the trial/instance domain β relayed content shares its reputation. It needs a wildcard A record and a wildcard cert (same DNS-01 setup 11ch.at uses).
- Claims persist in the gateway's own sqlite (
relay_claims: host, pubkey, timestamps). Routes are the ordinary registryservicerows; on gateway restart staler-%rows are swept and reappear as clients reconnect (within ~32s). - Grace window: 15 minutes by default. A sleeping relay answers 503 with an honest "this space's machine is offline" message.
lchat tunnel kill r-β¦.<domain>withdraws the route; the claim stays, so the same keypair gets the same hostname back on reconnect. Add--forgetto also delete the claim β the hostname returns to the pool and the keypair starts fresh. That's the kick for a test or abusive relay.- Abandoned claims free themselves: an hourly janitor deletes claims whose owner hasn't connected for
--claim-idle-days(default 45). Currently-connected relays are never swept, however old their claim.
Honest limits (put these on any page that sells it)
- Your space's uptime is your machine's uptime. Lid closes, space naps.
- Throughput is your home uplink, relayed twice through the gateway box.
- TLS terminates at the gateway (hosted-grade transport trust; content is E2EE regardless). Phase 2 β SNI passthrough, where your machine holds its own certificate and the relay sees only opaque bytes β is designed in #738 and is the reason relay routes stay a distinct concept.
Not in Phase 1 (see #738)
Memorable/chosen slugs, bring-your-own-domain (CNAME), SNI passthrough, relay plans/billing, and gateway sharding.