# Tunnel — Overview

> Expose a local TCP/HTTP service at a public endpoint over QUIC — no inbound ports. Raw-TCP & HTTP tunnels, P2P, and remote desktop on one transport.

<img src="/images/diagrams/tunnel.png" alt="tunnel data flow" />

The **tunnel** modality turns ClutchCall's edge mesh into a self-hosted
reverse tunnel: expose `localhost:3000` (or any internal TCP/HTTP service) at a
public URL over QUIC, with **no inbound firewall ports opened**. The box-side
agent dials **out** over QUIC to the nearest edge PoP and parks streams; public
requests that land on the edge are multiplexed back over that connection to your
service. It is the same primitive that powers single-command public URLs, direct
peer-to-peer LAN/WAN links, and remote-desktop sessions.

> **NOTE:**
> The tunnel modality ships today as the **`clutchcall` CLI** plus a QUIC
> data-plane engine, not as a typed SDK class. This page documents the wire model
> and the CLI; a programmatic client is marked **Preview** where it appears.

## When to use it

  - **Public URL for localhost** — Demo a web app, take a webhook, share a dev server — one command, a public
    HTTPS URL, no router config or inbound port.
  - **Zero-trust ingress** — Reach an internal service (database, admin panel, SSH) from anywhere without
    punching a hole in the firewall — the box only ever dials out.
  - **Direct P2P links** — Two boxes connect directly — same LAN by discovery, or across NATs by hole
    punching — with the edge brokering candidates but never carrying bytes.
  - **Remote desktop** — A remote-desktop client rides the same raw-QUIC transport: the controlled box
    registers a slug and parks streams; the controller dials it by slug.

## Why QUIC, no inbound ports

The box-side agent is always the **QUIC client** — whoever dials is the client.
Because it dials *out*, there is no inbound hole to open and no static public IP
required on the box. NAT traversal is free: the connection is established from
behind the firewall, and the edge routes return traffic back over it.

- **One public connection ⇄ one QUIC stream.** Each tunneled connection rides its
  own QUIC stream, so there is **no head-of-line blocking across tunnels** — the
  classic pain of a single multiplexed TCP tunnel.
- **Survives network flaps.** QUIC connection migration / resume lets the box
  change networks (Wi-Fi → cellular) without dropping the public URL.
- **Multi-region by mesh.** A box connects to its nearest PoP; public traffic that
  lands on a *different* PoP is routed to the box's PoP over the edge↔edge mesh, so
  the URL is reachable from every region without the box re-homing.

## Wire model — the parked-stream pool

A QUIC server cannot open streams toward a client; only the client opens streams.
So the box pre-opens a pool of bidirectional streams and **parks** them. When a
public request arrives, the edge pops an idle parked stream, writes a small
metadata frame onto it, and splices the public socket to that stream.

  1. **Register**
The box dials the edge over QUIC (ALPN `clutchcall-engine`) and opens a **control
    stream**, sending a `reg` frame with its desired slug and a session token. The
    edge claims the slug and replies `reg_ok` with the public host.
  2. **Park a pool**
The box pre-opens `K` (≈16) bidi **work streams** and parks them idle. Each is
    surfaced to the edge with a one-shot park marker so the server sees it.
  3. **Public request arrives**
A request hits `https://<slug>.clutchcall.dev`. The edge strips the host to the
    slug, looks up the session, and pops an idle parked stream.
  4. **Splice**
The edge writes an `open` metadata frame (remote addr, host, scheme) onto the
    stream, then becomes a transparent byte relay between the public socket and the
    stream. The box reads the frame, dials `localhost:<port>`, and relays in both
    directions until either side closes.
  5. **Refill**
Whenever an idle stream is consumed, the box opens a replacement to keep `K`
    parked. The control stream also carries heartbeats and pool-low requests.

### Frame format

The control and metadata frames are length-prefixed JSON; the data path after the
metadata frame is raw bytes.

```
frame = [u32 BE length][payload]
```

| Frame | Direction | Payload (JSON) |
| --- | --- | --- |
| `reg` | box → edge | `{ "t":"reg", "v":1, "slug":"happy-otter"\|"", "token":"<session-jwt>", "proto":"tcp"\|"http"\|"quick" }` |
| `reg_ok` | edge → box | `{ "t":"reg_ok", "host":"happy-otter.clutchcall.dev", "slug":"happy-otter", "plan":"…" }` |
| `reg_err` | edge → box | `{ "t":"reg_err", "code":"slug_taken\|bad_token\|quota\|device_limit", "msg":"…" }` |
| `open` (META) | edge → box | `{ "t":"open", "id":"<conn-id>", "raddr":"<ip:port>", "host":"…", "scheme":"http\|tcp" }` |
| `pool_low` | edge → box | `{ "t":"pool_low", "want":8 }` |

An empty `slug` means "assign me a random memorable slug" — the least-friction
default. The session token is a short-lived JWT carrying the user id, device id
(for the device gate), and plan; the edge verifies it on `reg`.

## Tunnel types

<AccordionGroup>
  <Accordion title="HTTP / HTTPS tunnel" icon="globe">
    The headline type. The edge terminates public TLS, routes by `Host` header /
    SNI to the registered slug, and bridges each public connection onto a parked
    stream. WebSocket upgrade, SSE, and chunked transfer pass through cleanly —
    each public connection is its own stream. Wildcard TLS covers
    `*.clutchcall.dev`, so every slug gets automatic HTTPS.
  </Accordion>
  <Accordion title="Raw-TCP tunnel" icon="plug">
    A remote port maps straight to a local TCP service — SSH, Postgres, a game
    server. No HTTP parsing: the edge allocates (or routes) a public port and
    splices each accepted TCP connection onto a parked stream as an opaque byte
    pipe. Backpressure is honoured per stream (the read side pauses when the peer
    can't take more).
  </Accordion>
  <Accordion title="P2P direct (LAN + WAN)" icon="arrows-left-right">
    Two boxes link **directly**, with the edge out of the byte path. On the same
    subnet, discovery is mDNS (a `_clutchcall._udp.local` service) and the
    boxes dial over the LAN.
    Across NATs, each side STUN-gathers its reflexive candidate, publishes it to a
    rendezvous keyed by a shared pair-id, then both punch and the QUIC engine
    rebinds the same port. Endpoint-independent (cone) NATs work directly;
    symmetric NATs fall back to the relayed path.
  </Accordion>
  <Accordion title="Remote desktop" icon="display">
    A remote-desktop client (a fork of an open-source remote-desktop project) runs
    its transport over this same raw-QUIC relay. The controlled box registers its
    device id as a slug (`proto":"quick"`) and parks streams; the controller dials
    it by slug. The remote-desktop client's own framing and end-to-end encryption
    are reused unchanged on top — the edge is untrusted and only secures the hop.
  </Accordion>
</AccordionGroup>

## Control plane vs data plane

The CLI is the front and does two distinct things:

| Plane | Transport | What it carries |
| --- | --- | --- |
| **Control plane** | HTTPS + JSON | login (device-flow), status, devices, wallet, slug claim, P2P rendezvous. No bytes of your traffic. |
| **Data plane** | raw QUIC (ALPN `clutchcall-engine`) | the QUIC engine that dials the edge and forwards tunneled traffic. |

Sign-in is a provider **device flow** — the provider hosts the UI and the product
stores **no credentials**: only a short-lived session JWT plus a device id are
persisted locally (file mode `0600`). That one session token authorizes tunnels
and spend, and is presented to the data plane on `reg`.

## Lanes & QoS

The tunnel data path is **reliable and ordered** end to end — each tunneled TCP or
HTTP connection is a single QUIC stream, so bytes arrive in order with no loss.
There is no lossy datagram lane here (unlike voice or games): a tunnel is a
faithful byte pipe. Isolation between tunnels comes from stream multiplexing — one
slow or stalled connection cannot head-of-line-block another.

## Architecture

The edge PoP runs the ClutchCall engine in a **shard-per-core** reactor with an
**AF_XDP** kernel-bypass NIC fast path and **io_uring** for async I/O; cross-shard
hand-offs use **lock-free** rings. The public QUIC listener uses **SO_REUSEPORT**
so each shard owns an accept queue. The slug → session routing table is mutated at
runtime as boxes connect and disconnect, and shared across the edge mesh (Redis
membership) so any PoP can route a public request to the PoP that holds the box.

## Related

- [SDK methods](/modalities/tunnel/sdk-methods) — the `clutchcall` command surface and config
- [Cookbook](/modalities/tunnel/cookbook) — task-oriented snippets
- [Recipes](/modalities/tunnel/recipes) — end-to-end worked examples
