# Recipes

> End-to-end tunnel walkthroughs: ship a public demo URL, a private cross-NAT database link, and a remote-desktop session over raw QUIC.

These longer worked examples combine several `tunnel` commands into
a realistic scenario.

## Recipe 1 — Ship a public demo URL with a stable subdomain

Take a local web app from `localhost:3000` to a shareable HTTPS URL. With a
reserved subdomain, the URL survives restarts and Wi-Fi changes.

  1. **Save an API key once**
```sh
    tunnel config add-authtoken rtk_…   # the key from Tunnel · API keys
    ```
    The key is the only credential on the machine. A tunnel needs no sign-in.
  2. **Reserve your subdomain**
```sh
    tunnel domains add acme     # → https://acme.rnp.sh
    ```
    The domain belongs to your organization. A key can reach only the domains
    of its organization, or the domains that it is bound to.
  3. **Expose the app**
```sh
    tunnel http 3000 --url acme.rnp.sh     # → https://acme.rnp.sh
    ```
    The CLI dials the nearest edge PoP over QUIC. It registers the slug and
    parks a pool of streams. The edge splices public requests to
    `acme.firstbyte.fast` back over those streams to `localhost:3000`.
  4. **Run named tunnels for extra services**
```sh
    tunnel domains add acme-api
    tunnel http 8080 --url acme-api.rnp.sh   # → https://acme-api.rnp.sh
    ```
    Each service gets its own URL and its own stream pool. There is no
    head-of-line blocking between them.
  5. **Verify it from anywhere**
A stranger on the internet loads `https://acme.firstbyte.fast`. WebSocket
    upgrade, SSE, and large uploads all pass through. If your laptop hops from
    Wi-Fi to cellular, QUIC migration keeps the URL live without a reconnect.

> **NOTE:**
> The URL is reachable from every region. When traffic lands on a far PoP, the
> edge mesh routes it to the PoP that your box is connected to.

---

## Recipe 2 — A private cross-NAT database link

Reach a Postgres instance on a home server from your laptop on a different
network. There are **no inbound ports**. The edge **never carries your bytes**.

  1. **Configure a STUN reflector on both boxes**
```sh
    export TUNNEL_STUN=stun.firstbyte.fast:3478
    ```
    Each side gathers its server-reflexive candidate (public `ip:port`) so the
    two can punch toward each other.
  2. **Share the database from the home server**
```sh
    home$ tunnel p2p share pglink --port 5432
    ```
    `pglink` is a shared pair-id. Both peers agree on it out of band. The CLI
    binds a local UDP port and gathers candidates with STUN. It publishes its
    candidates to the rendezvous, then waits for the peer.
  3. **Connect from the laptop**
```sh
    laptop$ tunnel p2p connect pglink --listen 5432
    ```
    The laptop publishes its own candidates under the same pair-id. The control
    plane brokers the exchange. Both sides then punch. The QUIC engine rebinds
    the same local port to form a **direct** link.
  4. **Use the link**
```sh
    laptop$ psql -h localhost -p 5432
    ```
    Each `psql` connection becomes its own QUIC stream over the direct link.
    The pair-id gates the tunnel end to end. The edge only saw the candidate
    exchange. It never saw query bytes.

> **WARNING:**
> On a symmetric NAT, the direct punch can fail. The flow then falls back to the
> relayed path, so the link still forms. In that case, the edge forwards bytes
> for that session.

**Why no inbound port is ever opened**

Both peers are QUIC **clients** that dial outward. The peer that dials is the
client. The home server never accepts an unsolicited inbound connection. Thus
there is no firewall hole to punch and no static public IP to maintain.

---

## Recipe 3 — Remote desktop over the raw-QUIC relay

Control a headless box from a laptop with
[**QuickDesk**](/modalities/quickdesk/overview). Its transport rides the same
tunnel relay. Both legs are QUIC. End-to-end encryption is QuickDesk's own.

  1. **Point both clients at the relay**
In QuickDesk's network settings, set the relay endpoint:
    ```text
    Relay server = relay.firstbyte.fast:4443
    ```
    This replaces QuickDesk's own rendezvous/relay with the FirstByte tunnel
    relay (ALPN `clutchcall-engine`).
  2. **The controlled box registers**
On start, the controlled box dials the relay. It registers its **device id
    as a slug** with `"proto":"quick"`. It then pre-opens and parks bidi work
    streams. This is exactly the parked-stream pool that the HTTP/TCP tunnels
    use.
  3. **The controller dials by slug**
The controller enters the box's device id. The relay looks up the slug and
    pops a parked stream. It writes an `open` metadata frame. It then splices
    the controller's QUIC stream to the box's parked stream.
  4. **Session runs end to end encrypted**
QuickDesk's signed key exchange and message framing ride unchanged on top
    of the QUIC byte pipe. The relay is **untrusted**. QUIC TLS only secures
    the hop to the PoP. Confidentiality and peer auth stay in QuickDesk's own
    crypto.

> **NOTE:**
> QuickDesk speaks the tunnel wire protocol directly. This path needs no extra
> CLI. The HTTP/TCP/P2P tunnels and the QuickDesk session all share one
> transport, one slug namespace, and one parked-stream model. See the
> [QuickDesk docs](/modalities/quickdesk/overview) for clients and self-hosting.

---

## Recipe 4 — Self-hosted control plane + edge

Run the whole stack against your own infrastructure for a zero-trust ingress to
internal services.

  1. **Point the CLI at your control plane**
```sh
    export TUNNEL_API=https://api.internal.example.com
    export TUNNEL_POP=edge.internal.example.com:4443
    tunnel config add-authtoken rtk_…
    ```
  2. **Expose an internal admin panel**
```sh
    tunnel domains add admin.internal.example.com
    tunnel http 9000 --url admin.internal.example.com   # → https://admin.internal.example.com
    ```
    The box on the internal network dials out to your edge. Nobody opens an
    inbound port to the admin host.
  3. **Gate access at the edge**
Front the public URL with your SSO/OIDC at the edge. Then only
    authenticated users reach the internal service. This is the zero-trust
    ingress pattern. The box-side agent stays a pure byte pipe. Policy lives at
    the PoP.

## Related

- [Tunnel overview](/modalities/tunnel/details) — wire model & architecture
- [SDK & CLI](/modalities/tunnel/sdk-methods) — full command surface
- [Cookbook](/modalities/tunnel/cookbook) — short task snippets
