# Cookbook

> Short copy-pasteable tunnel tasks: expose localhost, reserve a subdomain, tunnel SSH/Postgres, P2P links, share webhooks, and remote desktop.

Task-oriented snippets for the `tunnel` CLI. Each snippet does one
thing.

> **NOTE:**
> Env vars below use the `TUNNEL_` prefix. The CLI also reads the old `RNP_`
> name of each variable.

## Expose a local web app at a public URL

This is the headline move. Save an API key one time. Then one command gives
you a public HTTPS URL with no inbound port.

```sh
tunnel config add-authtoken rtk_…   # the key from Tunnel · API keys
tunnel http 3000                    # → https://acme.rnp.sh
```

## Reserve a stable subdomain

Add the subdomain one time. Then give it to `http` with `--url`.

```sh
tunnel domains add alice                 # reserves https://alice.rnp.sh
tunnel http 3000 --url alice.rnp.sh      # → https://alice.rnp.sh
```

## Use your own hostname

Add the hostname on the **Domains** page of the Tunnel console, or with
`tunnel domains add`. Create the DNS record that it shows. Then:

```sh
tunnel http 3000 --url tunnel.example.com   # → https://tunnel.example.com
```

## Run more than one tunnel

Give each service its own domain, so each service gets its own URL.

```sh
tunnel http 3000 --url alice-web.rnp.sh    # → https://alice-web.rnp.sh
tunnel http 8080 --url alice-api.rnp.sh    # → https://alice-api.rnp.sh
```

## Receive a webhook on your laptop

Point the provider's webhook at your public URL. Deliveries reach `localhost`
without a deployed server.

```sh
tunnel http 4000      # set the webhook URL to the printed https URL
```

> **TIP:**
> Streaming and chunked responses (SSE, long-poll) pass through unchanged. Each
> public connection is its own QUIC stream, so one slow request never blocks
> others.

## Tunnel a raw-TCP service (SSH, Postgres)

The raw-TCP type maps a remote endpoint to a local port with no HTTP parsing.
It is a good fit for SSH or a database. Use the P2P direct form for a private
link. Use the public form for an internet-reachable port.

```sh
# Private service through the edge, reached by name:
home$   tunnel tcp 5432 --url db
laptop$ tunnel connect db --listen 127.0.0.1:5432

# Direct, private link between two of your machines:
home$   tunnel p2p share db --port 5432
laptop$ tunnel p2p connect db --listen 5432
laptop$ psql -h localhost -p 5432    # rides the QUIC tunnel
```

## Point a remote shell at a box behind NAT

Use the same P2P flow for SSH. The box only dials out. No inbound rule is
necessary.

```sh
box$    tunnel p2p share shell --port 22
client$ tunnel p2p connect shell --listen 8022
client$ ssh -p 8022 localhost
```

## Connect two boxes on the same LAN

On one subnet, discovery is automatic. The edge stays fully out of the path.

```sh
A$ tunnel p2p share lanlink --port 3000
B$ tunnel p2p connect lanlink --listen 3000
# Bytes flow A ⇄ B directly over the LAN — stop the edge and it still works.
```

## Punch through NATs with STUN

Across networks, set a STUN reflector so each side gathers its public candidate
before punching.

```sh
export TUNNEL_STUN=stun.firstbyte.fast:3478
A$ tunnel p2p share wan --port 8000
B$ tunnel p2p connect wan --listen 8000
```

> **NOTE:**
> Cone NATs punch directly. Symmetric NATs fall back to the relayed path
> automatically.

## Pick a region / specific edge PoP

Override the edge that the data plane dials, for example to test a region or a
self-hosted PoP.

```sh
export TUNNEL_POP=edge-sg.firstbyte.fast:4443
tunnel http 3000
```

## Point at a self-hosted control plane

To run against your own control plane, override the API base.

```sh
export TUNNEL_API=https://api.internal.example.com
tunnel config add-authtoken rtk_…
```

## Check the key, hosts, and egress

See the organization, the key, its hosts, and the egress for this month. This
command uses the key. It does not need a sign-in.

```sh
tunnel status
```

## Revoke the key of an old machine

Use one key for each machine. Then one revoke removes one machine.

```sh
tunnel keys                # find the id
tunnel keys revoke <id>
```

## Use a custom engine binary

If the QUIC data-plane engine is not next to the CLI, point at it explicitly.

```sh
export TUNNEL_ENGINE_BIN=/opt/tunnel/tunnel-engine
tunnel http 3000
```

## Enable remote desktop over the QUIC relay

[**QuickDesk**](/modalities/quickdesk/overview) uses this relay for transport
instead of its own rendezvous/relay. Point it at the relay in its network
settings:

```text
# In QuickDesk's network settings, set:
Relay server = relay.firstbyte.fast:4443
```

The controlled box registers its device id as a slug and parks streams. The
controller dials it by slug. QuickDesk's own end-to-end encryption is
unchanged. See the [QuickDesk docs](/modalities/quickdesk/overview) for the
full product.

## Run as a long-lived background tunnel

`http` runs in the foreground until you interrupt it. `tunnel service install`
runs the named tunnels of the config file at login (Linux and macOS). You can
also use your own process manager.

```sh
# systemd user unit, supervisord, or simply:
nohup tunnel http 3000 --url alice-api.rnp.sh >/var/log/tunnel.log 2>&1 &
```

## Related

- [SDK & CLI](/modalities/tunnel/sdk-methods) — full command surface
- [Recipes](/modalities/tunnel/recipes) — end-to-end worked examples
