eleven / ocho Public

Clone
git clone https://amadan.net/eleven/ocho

Plain git — no account needed to clone.

Download

Download this file

🤖 lchat try — the one-command trial tunnel

lchat try is the zero-setup way to experience a real, self-run Eleven space: download the binary, run one command, get a public https://try-<slug>.11ch.at address serving a full instance from your own machine — through NAT, with no inbound ports, no DNS record, no certificate, and no root. Stop the command and the address retires; the space's data stays in ./lchat-try.db.

curl -LO https://github.com/elevenmessenger/releases/releases/download/server/lchat-linux-amd64
chmod +x lchat-linux-amd64
./lchat-linux-amd64 try

It prints two links: the space's address, and a one-time setup link that makes you its admin (the same conversational setup a hosted space gets).

How it works

Two halves, both in the single binary (internal/tunnel/):

  • The client (lchat try) starts a normal local instance (a subprocess running the ordinary single-instance path against lchat-try.db), then dials out to the gateway over one control WebSocket (wss://tunnel.11ch.at/api/tunnel/register). The gateway assigns try-<slug>.11ch.at and sends {"type":"ready","host":…}. For every backend connection the public side needs, the gateway sends {"type":"dial","id":…} and the client dials back one data WebSocket (/api/tunnel/conn/<id>), which both ends treat as a plain byte pipe (websocket.NetConn) spliced to the local instance's TCP port. Ordinary HTTP/1.1 flows through it — including WebSocket upgrades, which is what makes the chat itself work through the tunnel unmodified.
  • The gateway (lchat tunnel serve, unit lchat-tunnel.service) listens on /run/lchat/tunnel.sock behind the ordinary router. Each live tunnel is published as a plain registry route (kind=service, host=try-…, socket=/run/lchat/tunnel.sock), so the router needs no tunnel awareness at all: TLS comes from the existing *.11ch.at wildcard cert, and routing is the same host→socket lookup every instance uses. The router notices new routes via its registry watcher (a PRAGMA data_version poll every 2s), so the unprivileged gateway never needs rights to signal anything.

The E2EE story is unchanged: what crosses the tunnel is the same already-ciphertext traffic the router fronts for every instance. The gateway can see exactly what the router can see — nothing readable.

Why single-label slugs

try-x7k2m.11ch.at, not x7k2m.try.11ch.at: TLS wildcards match one label, and the fleet's wildcard cert is *.11ch.at. A nested scheme would need its own wildcard cert and DNS; the prefix gets the same effect for free.

Operations

  • Enable on a box: systemctl enable --now lchat-tunnel, then route its control host once: lchat add-service tunnel.11ch.at --socket /run/lchat/tunnel.sock. (Bootstrap installs the unit everywhere; it's inert until enabled.)
  • Config (/data/tunnel.env, optional): LCHAT_TUNNEL_HOST, LCHAT_TUNNEL_DOMAIN, LCHAT_TUNNEL_SOCKET, plus --max (default 50 concurrent tunnels).
  • Guardrails: 5 new tunnels per IP per hour, 50 concurrent tunnels, 32 concurrent connections per tunnel, 24-hour lifetime, dial-back timeout 15s. And the door check: before a hostname goes public — and every 10 minutes after — the gateway probes the tunnelled backend through the tunnel (GET /api/version) and refuses anything that isn't an Eleven instance, so the trial domain never lends its name (or its TLS) to arbitrary content. This is a trial surface, not free hosting — the limits say so politely.
  • Kill switch: lchat tunnel kill try-<slug>.11ch.at removes the route (the router stops serving it within seconds); systemctl restart lchat-tunnel additionally drops every live tunnel connection.
  • Cleanup is automatic: a tunnel's route is removed when its client disconnects; on gateway restart, leftover try-% rows pointing at its socket are swept. lchat instances will show live trials as service rows — transient by design.
  • Self-hosters can run their own gateway anywhere the router fronts a wildcard domain; lchat try --gateway https://tunnel.your.domain points the client at it.

Honest limits

  • A trial's address dies with the process (or at 24h). lchat try again mints a fresh address; the data in lchat-try.db persists, but members' saved links won't follow it. The printed copy says so — a keeper space should graduate to a real install (docs/self-hosting.md).
  • The gateway is a relay for one machine's trial, not a CDN: throughput is whatever the trial machine's uplink gives it.