> ## Documentation Index
> Fetch the complete documentation index at: https://rustunnel.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# rustunnel CLI Client Guide — every flag, command, and config option

> Complete reference for the rustunnel CLI client: installation, authentication, HTTP/TCP/UDP/P2P tunnel commands, live terminal UI, local request inspector, region selection, config file format, and troubleshooting. The companion to the Quickstart and Self-Hosting guides.

This is the complete reference for the rustunnel CLI — every flag, command, and config option, including the live [terminal UI](#terminal-ui) and [request inspector](#request-inspector) shipping in 0.8.3. New to rustunnel? Start with the [Quickstart](/docs/quickstart) for a three-step walkthrough, or the [self-hosting guide](/docs/guides/self-hosting) if you want to run your own server.

## Installation

### From source (recommended)

Requires [Rust](https://rustup.rs/) 1.75 or later.

```bash theme={null}
git clone https://github.com/joaoh82/rustunnel
cd rustunnel
cargo build --release -p rustunnel-client
sudo install -Dm755 target/release/rustunnel /usr/local/bin/rustunnel
```

Or use the Makefile shortcut:

```bash theme={null}
make deploy-client
```

### Verify

```bash theme={null}
rustunnel --version
```

***

## Quick Start

```bash theme={null}
# 1. Get an auth token
#    → Sign up at https://rustunnel.com, then go to Dashboard → API Keys → Create token

# 2. Create a config file interactively
rustunnel setup
# → prompts for region and auth token, writes ~/.rustunnel/config.yml

# 3. Expose a local web server running on port 3000
rustunnel http 3000

# 4. Expose a raw TCP service (e.g. SSH on port 22)
rustunnel tcp 22
```

After connecting, the terminal displays the public URL:

```text theme={null}
╭────────────────────────────────────────────────────────────╮
│                         rustunnel                          │
├────────────────────────────────────────────────────────────┤
│  HTTP [myapp] → localhost:3000                             │
│   https://myapp.tunnel.example.com                        │
╰────────────────────────────────────────────────────────────╯

  ✓ Tunnels active. Press Ctrl-C to quit.
```

***

## Configuration File

The client reads `~/.rustunnel/config.yml` automatically. CLI flags always override file values.

### Full example

```yaml theme={null}
# Tunnel server address (required — choose a region)
server: eu.edge.rustunnel.com:4040

# Authentication token (required)
auth_token: rt_live_abc123...

# Skip TLS certificate verification — local dev ONLY, never use in production
insecure: false

# Region preference: auto (probe & pick nearest), or eu / us / ap.
# Omit for self-hosted / single-server setups.
region: auto

# Named tunnel definitions used by `rustunnel start`
tunnels:
  web:
    proto: http
    local_port: 3000
    local_host: localhost       # optional, defaults to localhost
    subdomain: myapp            # optional, requests a specific subdomain

  api:
    proto: http
    local_port: 8080
    subdomain: myapi

  database:
    proto: tcp
    local_port: 5432
```

### Field reference

| Field                       | Type    | Default       | Description                                                            |
| --------------------------- | ------- | ------------- | ---------------------------------------------------------------------- |
| `server`                    | string  | —             | Tunnel server host:port (e.g. `eu.edge.rustunnel.com:4040`)            |
| `auth_token`                | string  | —             | Authentication token issued by the server                              |
| `insecure`                  | bool    | `false`       | Skip TLS certificate verification (dev only)                           |
| `region`                    | string  | omit          | `auto` (probe nearest), `eu`, `us`, `ap`. Omit for self-hosted setups. |
| `tunnels`                   | map     | `{}`          | Named tunnel definitions (used by `rustunnel start`)                   |
| `tunnels.<name>.proto`      | string  | —             | `http` or `tcp`                                                        |
| `tunnels.<name>.local_port` | integer | —             | Local port to forward                                                  |
| `tunnels.<name>.local_host` | string  | `localhost`   | Local hostname to connect to                                           |
| `tunnels.<name>.subdomain`  | string  | auto-assigned | Requested HTTP subdomain                                               |

***

## Commands

### `setup` — Interactive config wizard

Create (or overwrite) `~/.rustunnel/config.yml` through a guided prompt sequence.

```bash theme={null}
rustunnel setup
```

**Prompts:**

| Prompt         | Default           | Description                                                |
| -------------- | ----------------- | ---------------------------------------------------------- |
| Region         | `auto`            | `auto` (probe nearest), `eu`, `us`, `ap`, or `self-hosted` |
| Auth token     | *(blank)*         | Token issued by the server; leave empty to fill in later   |
| Server address | *(auto-resolved)* | Only prompted when `self-hosted` is selected               |

**Region behavior:**

| Choice             | Server resolution                                |
| ------------------ | ------------------------------------------------ |
| `eu` / `us` / `ap` | Auto-set to `<region>.edge.rustunnel.com:4040`   |
| `auto`             | Probes all regions, picks the nearest by latency |
| `self-hosted`      | Prompts for your server address                  |

**Behaviour:**

* Creates `~/.rustunnel/` if the directory doesn't exist.
* If a config file already exists it is overwritten — a backup is not kept, so copy the old file first if you want to preserve it.
* Writes a commented `tunnels:` block with HTTP and TCP examples so you can see the structure right away.
* Prints `Created:` or `Updated:` with the full path when done.

**Example session (auto region):**

```text theme={null}
rustunnel setup — create ~/.rustunnel/config.yml

Region [auto / eu / us / ap / self-hosted] (default: auto):
  Selecting nearest region… eu 12ms · us 143ms · ap 311ms · → eu (Helsinki, FI) 12ms
  Server set to: eu.edge.rustunnel.com:4040

Auth token (leave blank to skip): rt_live_abc123xyz

Created: /Users/alice/.rustunnel/config.yml
Run `rustunnel start` to connect using this config.
```

**Example session (self-hosted):**

```text theme={null}
rustunnel setup — create ~/.rustunnel/config.yml

Region [auto / eu / us / ap / self-hosted] (default: auto): self-hosted

Tunnel server address: tunnel.internal.corp:4040

Auth token (leave blank to skip): my-token

Created: /Users/alice/.rustunnel/config.yml
Run `rustunnel start` to connect using this config.
```

**Generated file (managed):**

```yaml theme={null}
# rustunnel configuration
# Documentation: https://github.com/joaoh82/rustunnel

server: eu.edge.rustunnel.com:4040
auth_token: rt_live_abc123xyz
region: auto

# tunnels:
#   web:
#     proto: http
#     local_port: 3000
#   api:
#     proto: http
#     local_port: 8080
#     subdomain: myapi
#   database:
#     proto: tcp
#     local_port: 5432
```

**Generated file (self-hosted):**

```yaml theme={null}
# rustunnel configuration
# Documentation: https://github.com/joaoh82/rustunnel

server: tunnel.internal.corp:4040
auth_token: my-token
# region: not applicable (self-hosted)

# tunnels:
#   ...
```

After running `setup`, uncomment and fill in the `tunnels:` section then run `rustunnel start`, or use `rustunnel http <port>` / `rustunnel tcp <port>` directly.

***

### `http` — HTTP tunnel

Expose a local HTTP/HTTPS service through the tunnel server.

```bash theme={null}
rustunnel http <port> [options]
```

**Arguments:**

| Argument | Description                             |
| -------- | --------------------------------------- |
| `<port>` | Local TCP port to forward (e.g. `3000`) |

**Options:**

| Flag                   | Default       | Description                                                                      |
| ---------------------- | ------------- | -------------------------------------------------------------------------------- |
| `--subdomain <name>`   | auto-assigned | Request a specific subdomain (e.g. `myapp` → `myapp.eu.edge.rustunnel.com`)      |
| `--server <host:port>` | from config   | Override the server address (bypasses region selection)                          |
| `--token <token>`      | from config   | Override the auth token                                                          |
| `--local-host <host>`  | `localhost`   | Local hostname to forward to                                                     |
| `--region <id>`        | from config   | Region to connect to: `eu`, `us`, `ap`, or `auto`. Ignored if `--server` is set. |
| `--no-reconnect`       | off           | Exit instead of reconnecting on failure                                          |
| `--insecure`           | off           | Skip TLS verification (dev only)                                                 |

**Examples:**

```bash theme={null}
# Expose port 3000 — auto-selects the nearest region
rustunnel http 3000

# Connect to a specific region
rustunnel http 3000 --region eu

# Request a specific subdomain
rustunnel http 3000 --subdomain myapp

# Forward to a non-localhost service
rustunnel http 8080 --local-host 192.168.1.10

# One-shot connection (exit on disconnect instead of reconnecting)
rustunnel http 3000 --no-reconnect

# Use an explicit server address (bypasses region selection)
rustunnel http 3000 --server tunnel.example.com:9000 --token rt_live_abc123
```

***

### `tcp` — TCP tunnel

Expose any raw TCP service (database, SSH, game server, etc.).

```bash theme={null}
rustunnel tcp <port> [options]
```

**Arguments:**

| Argument | Description               |
| -------- | ------------------------- |
| `<port>` | Local TCP port to forward |

**Options:** Same as `http` except `--subdomain` has no effect for TCP tunnels. `--region` still works.

**Examples:**

```bash theme={null}
# Expose a local PostgreSQL instance
rustunnel tcp 5432

# Expose SSH on a non-standard port
rustunnel tcp 2222 --local-host 10.0.0.5
```

The server assigns a random public port from its configured TCP port range. The public address is displayed in the startup box.

***

### `start` — Multi-tunnel mode

Start all tunnels defined in a config file simultaneously.

```bash theme={null}
rustunnel start [--config <path>]
```

**Options:**

| Flag                  | Default                   | Description           |
| --------------------- | ------------------------- | --------------------- |
| `-c, --config <path>` | `~/.rustunnel/config.yml` | Path to a config file |

**Example:**

```bash theme={null}
# Use default config file
rustunnel start

# Use a custom config file
rustunnel start --config /etc/rustunnel/production.yml
```

`start` always reconnects automatically (equivalent to running each tunnel without `--no-reconnect`). At least one tunnel must be defined in the config file or the command exits with an error.

***

### Multiple backends (load balancing)

When `start` is given two or more tunnels with the same `(group, group_key)`, the server treats them as one logical pool — inbound traffic is dispatched to a healthy member at random. This is the path for running a hot-spare backend, scaling out a service horizontally behind a single subdomain, or doing zero-downtime rollouts.

Add the load-balancing fields to each pool member's tunnel definition:

```yaml theme={null}
server: tunnel.example.com:4040
auth_token: "your-token"

tunnels:
  a:
    proto: http
    local_port: 3000
    subdomain: pool
    group: web
    group_key: shared-secret-for-this-pool
    health_check:
      type: tcp
      # Optional: when this group goes 0/N healthy, the server POSTs a
      # group_zero_healthy alert to this URL. Per-tenant — independent
      # of any operator-side webhook configured on the edge.
      alert_webhook: "https://hooks.slack.com/services/my-team/..."
```

Run a second client (on the same or a different host) with `local_port: 3001`, the same `subdomain`, and the same `(group, group_key)`. Both clients register as members of the same pool; public connections to `pool.tunnel.example.com` are dispatched at random across them.

<Note>
  Load balancing requires `[load_balancing] enabled = true` in the server's `server.toml`. When the flag is `false` (the default), the client's `group` / `group_key` / `health_check` fields are accepted but ignored — both clients try to register as solo tunnels and the second one fails with `subdomain '...' is already in use`.
</Note>

#### Quick smoke test

End-to-end validation with two backends sharing one subdomain.

<Steps>
  <Step title="Build the client from source">
    ```bash theme={null}
    git clone https://github.com/joaoh82/rustunnel
    cd rustunnel
    cargo build --release -p rustunnel-client
    ```
  </Step>

  <Step title="Drop a config that opts into a group">
    ```bash theme={null}
    cat > /tmp/lb-test.yml <<'EOF'
    server: tunnel.example.com:4040
    auth_token: "your-token"

    tunnels:
      a:
        proto: http
        local_port: 3000
        subdomain: lbtest
        group: web
        group_key: shared-secret-for-lb-test
        health_check:
          type: tcp
    EOF
    ```
  </Step>

  <Step title="Start backend A and client A">
    ```bash theme={null}
    # Terminal 1 — backend A
    python3 -m http.server 3000

    # Terminal 2 — client A
    ./target/release/rustunnel start --config /tmp/lb-test.yml
    ```
  </Step>

  <Step title="Start backend B and client B">
    Use a second config file that's identical except for `local_port: 3001`.

    ```bash theme={null}
    # Terminal 3 — backend B
    python3 -m http.server 3001

    # Terminal 4 — client B
    ./target/release/rustunnel start --config /tmp/lb-test-b.yml
    ```
  </Step>

  <Step title="Hammer the public URL">
    ```bash theme={null}
    for i in $(seq 1 50); do
      curl -fsS https://lbtest.tunnel.example.com/ -o /dev/null -w "%{http_code}\n"
    done
    ```

    Both backends should see roughly half of the requests.
  </Step>

  <Step title="Validate failover">
    Kill one of the local backends (Ctrl-C on its `python3` process). The probe loop on that client marks it unhealthy after `max_failed × interval_secs` seconds; subsequent requests all land on the survivor. Restart the backend — the probe re-registers it as healthy and dispatch distributes again.
  </Step>
</Steps>

For the full reference (config field meanings, behaviour rules, observability series, limitations) see [Load Balancing & Health Checks](/docs/reference/load-balancing).

***

### `token create` — API token management

Create a new API token via the server's dashboard REST API. Requires admin credentials.

```bash theme={null}
rustunnel token create --name <label> [options]
```

**Options:**

| Flag                    | Default          | Description                                   |
| ----------------------- | ---------------- | --------------------------------------------- |
| `--name <label>`        | —                | Human-readable label for the token (required) |
| `--server <host:port>`  | `localhost:4040` | Dashboard server address                      |
| `--admin-token <token>` | —                | Admin token for authentication                |

**Example:**

```bash theme={null}
rustunnel token create \
  --name "production-server" \
  --server tunnel.example.com:4040 \
  --admin-token admin_secret_here
```

**Output:**

```text theme={null}
Token created:
  id:    f47ac10b-58cc-4372-a567-0e02b2c3d479
  token: rt_live_abc123xyz...
  label: production-server
```

<Warning>Copy the `token` value — it is shown only once. Add it to your config file as `auth_token`.</Warning>

***

## Flags Reference

| Flag                    | Commands                                 | Description                                                                |
| ----------------------- | ---------------------------------------- | -------------------------------------------------------------------------- |
| `--server <host:port>`  | http, tcp                                | Tunnel server address (bypasses region selection)                          |
| `--token <token>`       | http, tcp                                | Auth token (overrides config; also read from `RUSTUNNEL_TOKEN`)            |
| `--subdomain <name>`    | http                                     | Requested HTTP subdomain                                                   |
| `--local-host <host>`   | http, tcp                                | Local hostname (default: `localhost`)                                      |
| `--region <id>`         | http, tcp                                | Region: `eu`, `us`, `ap`, or `auto`. Ignored if `--server` is set.         |
| `--no-reconnect`        | http, tcp                                | Exit on failure instead of reconnecting                                    |
| `--insecure`            | http, tcp                                | Skip TLS certificate verification                                          |
| `--json`                | http, tcp, udp, p2p, start, token create | Emit machine-readable NDJSON events on stdout instead of human output      |
| `--no-tui`              | http, tcp, udp, p2p, start               | Disable the full-screen terminal UI; print one line per request instead    |
| `--inspect-port <port>` | http, tcp, udp, p2p, start               | Port for the local web inspector (default `4040`; `0` picks any free port) |
| `--no-inspect`          | http, tcp, udp, p2p, start               | Disable the local web inspector                                            |
| `-c, --config <path>`   | start                                    | Config file path                                                           |
| `--name <label>`        | token create                             | Token label (required)                                                     |
| `--admin-token <token>` | token create                             | Admin token for dashboard API                                              |
| `--version`             | all                                      | Print version and exit                                                     |
| `--help`                | all                                      | Print help and exit                                                        |

`setup` takes no flags — all input is collected interactively.

***

## Region Selection

rustunnel can connect to multiple edge servers in different geographic regions. The region selection logic follows this priority order:

1. **`--server <host:port>`** — explicit server address always wins; region logic is skipped entirely.
2. **`--region <id>`** — connect directly to the named region without probing.
3. **`region: auto`** (config file or `--region auto`) — probe all regions in parallel and pick the nearest.
4. **No region preference** — use `server:` from config as-is (backward compatible with self-hosted setups).

### Available regions (hosted service)

| Region ID | Location      | Server                       |
| --------- | ------------- | ---------------------------- |
| `eu`      | Helsinki, FI  | `eu.edge.rustunnel.com:4040` |
| `us`      | Hillsboro, OR | `us.edge.rustunnel.com:4040` |
| `ap`      | Singapore     | `ap.edge.rustunnel.com:4040` |

### Auto-select output

When `region: auto` is active, the client probes all regions by TCP connect time and prints:

```text theme={null}
  Selecting nearest region… eu 12ms · us 143ms · ap 311ms → eu (Helsinki, FI) 12ms
```

Unreachable regions time out after 3 seconds and are assigned a 10-second penalty so they never win the selection.

### Region list refresh

The region list is cached at `~/.rustunnel/regions.json` for 24 hours. On expiry the client fetches a fresh list from `GET https://<host>:8443/api/regions`; if that fails it falls back to the hardcoded list compiled into the binary.

***

## Reconnection Behavior

By default, `rustunnel` reconnects automatically when the connection drops. The retry delay follows an **exponential backoff** schedule:

| Attempt | Delay        |
| ------- | ------------ |
| 1       | \~1 s        |
| 2       | \~2 s        |
| 3       | \~4 s        |
| 4       | \~8 s        |
| …       | …            |
| n≥6     | \~60 s (max) |

Each delay has ±20% random jitter to prevent thundering-herd reconnects when a server restarts.

```text theme={null}
  Reconnecting in 2.3s (attempt 2)…
  Reconnecting in 5.1s (attempt 3)…
```

### Fatal errors (no reconnect)

The following errors cause an immediate exit — retrying would not help:

* **Auth failed** — invalid or revoked token. Fix: create a new token at [rustunnel.com](https://rustunnel.com) (Dashboard → API Keys) and update your config.
* **Config error** — missing required fields. Fix: check your `~/.rustunnel/config.yml`.

### Disabling reconnect

Use `--no-reconnect` for scripting, CI, or when you want manual control:

```bash theme={null}
rustunnel http 3000 --no-reconnect || echo "Tunnel exited"
```

***

## Terminal Output

When stdout is a terminal, the client takes over the screen with a live UI.
Otherwise — piped output, CI, `--no-tui`, or `--json` — it falls back to the
line-based output described further down.

### Terminal UI

<Frame caption="Live terminal UI — session status, tunnels, traffic counters, and a scrolling request log">
  <img src="https://mintcdn.com/rustunnel/bN59zjGRazkGXAPU/images/cli-tui-dark.png?fit=max&auto=format&n=bN59zjGRazkGXAPU&q=85&s=17ac3303e8a4836dda8977cabf7c0e92" alt="rustunnel full-screen terminal UI showing session status, tunnel health, traffic counters, and request log" width="1280" height="720" data-path="images/cli-tui-dark.png" />
</Frame>

```text theme={null}
┌ rustunnel ───────────────────────────────────────────────────────────────────┐
│Session  ● online                    Server   eu.edge.rustunnel.com:4040      │
│Uptime   00:12:43                    Region   eu · 57ms                       │
│Version  0.8.3                       Inspect  http://127.0.0.1:4040           │
└──────────────────────────────────────────────────────────────────────────────┘
┌ Tunnels ─────────────────────────────────────────────────────────────────────┐
│HTTP   web    http://bb176fb6.eu.edge.rustunnel.com  → localhost:3000  ● healthy│
└──────────────────────────────────────────────────────────────────────────────┘
┌ Traffic ─────────────────────────────────────────────────────────────────────┐
│Conns    2 open · 27 total    Requests 1204                        req/s       │
│Traffic  ↑ 1.2 MB  ↓ 830.0 kB    Latency  p50 6ms · p90 41ms      ▁▂▃▅▂▁▃▂    │
└──────────────────────────────────────────────────────────────────────────────┘
┌ Requests ────────────────────────────────────────────────────────────────────┐
│23:21:54 GET     /style.css                    200   3 ms    95.99.57.76:51224│
│23:21:53 POST    /api/items                    201  18 ms    95.99.57.76:51223│
│23:21:53 GET     /missing                      404   2 ms    95.99.57.76:51222│
└──────────────────────────────────────────────────────────────────────────────┘
q quit  ↑↓ scroll  f pause  c clear  l logs
```

* **Session** — connection state, uptime, client version, edge server, region and live control-plane latency (measured from the keepalive round-trip), and the local inspector URL.
* **Tunnels** — one row per tunnel with its public URL, local target, and health when a `health_check` is configured.
* **Traffic** — open/total connections, bytes each way, p50/p90 request duration, and a requests-per-second sparkline.
* **Requests** — live log of every HTTP request: time, method, path, status, duration, and the public client address. Replayed requests are marked `↻`.

Keys:

| Key                  | Action                                   |
| -------------------- | ---------------------------------------- |
| `q`, `Esc`, `Ctrl-C` | Quit (closes the tunnel)                 |
| `↑` `↓` / `k` `j`    | Scroll the request log                   |
| `PgUp` / `PgDn`      | Scroll by page                           |
| `g` / `G`            | Jump to newest / oldest                  |
| `f`                  | Pause or resume following new requests   |
| `c`                  | Clear the captured requests              |
| `l`                  | Toggle the log pane (client diagnostics) |

Only HTTP tunnels produce request rows. TCP and UDP tunnels are opaque byte streams, so they show connection and traffic counters only.

### Line mode

With `--no-tui`, a non-terminal stdout, or `--json`, output stays line-based.

While establishing the connection a spinner is shown:

```text theme={null}
⠙ Connecting to tunnel server…
⠹ Authenticating…
⠼ Registering tunnels…
```

Once all tunnels are registered, a bordered box appears:

```text theme={null}
╭────────────────────────────────────────────────────────────╮
│                         rustunnel                          │
├────────────────────────────────────────────────────────────┤
│   HTTP [myapp] → localhost:3000                            │
│   https://myapp.tunnel.example.com                        │
│   TCP  [ssh]   → localhost:22                             │
│   tcp://tunnel.example.com:34521                          │
╰────────────────────────────────────────────────────────────╯

  ✓ Tunnels active. Press Ctrl-C to quit.

  Inspect http://127.0.0.1:4040
```

Color coding:

* Protocol label — **bold yellow**
* Tunnel name — dim
* Public URL — **bold green**
* Border — cyan

Requests then stream one per line as they arrive:

```text theme={null}
23:21:54    GET /style.css                     200 3ms
23:21:53   POST /api/items                     201 18ms
23:21:53    GET /missing                       404 2ms
```

### JSON output (`--json`)

With `--json`, the spinner and startup box are suppressed and stdout instead carries NDJSON — one JSON event object per line — for scripts and AI agents:

```json theme={null}
{"event":"tunnel_ready","protocol":"http","public_url":"https://myapp.tunnel.example.com","local_port":3000,"local_host":"localhost","tunnel_id":"6f9a…","name":"myapp"}
```

Events: `inspector_ready` (`url`; emitted once at startup when the request inspector is enabled), `tunnel_ready` (includes `public_addr` host:port for tcp/udp), `reconnecting` (`attempt`, `reason`, `delay_secs`), `reconnected`, `error` (`code`, `message`, `hint`; exit code 1 follows), and `token_created` (for `token create --json`). Diagnostics still go to stderr.

A `--json` session that also runs the inspector emits it first, so a script can pick the port up before any traffic arrives:

```json theme={null}
{"event":"inspector_ready","url":"http://127.0.0.1:4040"}
{"event":"tunnel_ready","protocol":"http","public_url":"https://myapp.tunnel.example.com","local_port":3000,"local_host":"localhost"}
```

### Graceful shutdown

Press `Ctrl-C` to cleanly close the tunnel and exit. The control WebSocket is closed before the process exits. In the terminal UI, `q` and `Esc` do the same.

***

## Request Inspector

Every tunnel session also starts a small web inspector on loopback, printed at startup and shown in the terminal UI:

```text theme={null}
Inspect http://127.0.0.1:4040
```

Open it to browse everything that flowed through the tunnel. See the dedicated [Request Inspector](/docs/guides/request-inspector) guide for the full walkthrough.

<Frame caption="Local request inspector at http://127.0.0.1:4040 — request list and detail with Replay">
  <img src="https://mintcdn.com/rustunnel/bN59zjGRazkGXAPU/images/request-inspector-detail-dark.png?fit=max&auto=format&n=bN59zjGRazkGXAPU&q=85&s=7c806c4ed1402701ee45c0276dfac5a5" alt="rustunnel local web request inspector showing request list, detail tabs, and Replay button" width="1400" height="860" data-path="images/request-inspector-detail-dark.png" />
</Frame>

* **Request list** — live-updating, with method, path, status, and duration. Filter by method, path, or status.
* **Detail view** — Summary (bodies), Headers (full request and response headers), and Raw (the reconstructed HTTP messages).
* **Replay** — re-issue any captured request against your local service without the original caller doing anything. Handy for webhooks: trigger once, then iterate against the same payload. Replayed requests appear in the list marked `replay`.

### Scope and limits

* Captures **HTTP tunnels only**. TCP and UDP tunnels are raw byte streams; they contribute connection and traffic counters but no request entries.
* Keeps the **last 500 requests in memory**, per process. Nothing is written to disk and nothing survives a restart.
* Bodies are captured up to **64 KB each**; larger ones are marked truncated (the reported size is still exact). A truncated request body cannot be replayed byte-for-byte.
* WebSocket and other upgraded connections are recorded as their handshake (`101`); the frames afterwards are not parsed.

### Configuration

| Flag                    | Effect                                                                                                           |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `--inspect-port <port>` | Bind a specific port (default `4040`). If it is taken, the next free port is used and the real URL is displayed. |
| `--no-inspect`          | Disable the inspector entirely.                                                                                  |

Because the port can shift when the preferred one is taken, always read the actual URL rather than assuming `4040` — from the terminal UI header, the line under the startup box, or the `inspector_ready` event in `--json` mode.

The inspector binds `127.0.0.1` only and has no authentication, so treat it as local-only — captured payloads may contain credentials, tokens, and personal data. Use `--no-inspect` on shared or multi-user machines.

***

## Environment Variables

| Variable          | Description                                                                                                                                                                                                                                                              |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `RUST_LOG`        | Log level filter (e.g. `debug`, `info`, `warn`, `rustunnel=debug`). Default: `warn`.                                                                                                                                                                                     |
| `RUSTUNNEL_TOKEN` | Auth token for the `http`, `tcp`, `udp`, and `p2p` commands, used when `--token` is not passed (takes precedence over the config file; empty values are ignored). `start` reads tokens from the config file only, and `token create` authenticates with `--admin-token`. |

**Examples:**

```bash theme={null}
# Enable debug logging for all crates
RUST_LOG=debug rustunnel http 3000

# Enable debug only for rustunnel internals
RUST_LOG=rustunnel=debug rustunnel http 3000

# Quiet mode (errors only)
RUST_LOG=error rustunnel http 3000
```

<Note>Log output goes to **stderr**. Normal tunnel output (terminal UI / line mode, reconnect messages) goes to **stdout**.</Note>

***

## Error Reference

| Error                                                   | Cause                                            | Fix                                                                                                                                         |
| ------------------------------------------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `config error: server address is required`              | No `--server` flag and no config file            | Add `server:` to `~/.rustunnel/config.yml` or pass `--server`                                                                               |
| `auth failed: <message>`                                | Token invalid or revoked                         | Create a new token at [rustunnel.com](https://rustunnel.com) (Dashboard → API Keys) or with `rustunnel token create` for self-hosted setups |
| `tunnel error: <message>`                               | Subdomain already in use or server limit reached | Use a different `--subdomain` or wait                                                                                                       |
| `connection error: control WS: …`                       | Can't reach the server                           | Check network, firewall, and server address                                                                                                 |
| `connection error: heartbeat timeout`                   | Server stopped responding to pings               | Transient — reconnect loop will retry                                                                                                       |
| `connection error: timeout waiting for server response` | Auth/registration timed out (10 s)               | Check server health; may be overloaded                                                                                                      |
| `no tunnels defined in config file`                     | `rustunnel start` with an empty `tunnels:` map   | Add at least one tunnel to the config                                                                                                       |

***

## Troubleshooting

### Tunnel connects but requests don't arrive

* Verify your local service is running and listening: `curl http://localhost:<port>`
* Check `--local-host` if forwarding to a non-localhost address

### Certificate verification failed

If your server uses a self-signed certificate (common for local/staging environments), use `--insecure`:

```bash theme={null}
rustunnel http 3000 --insecure
```

<Warning>**Never use `--insecure` in production** — it disables all TLS certificate checks.</Warning>

### Subdomain already taken

The server returns `tunnel error: subdomain already in use`. Either:

* Omit `--subdomain` to get an auto-assigned subdomain, or
* Choose a different name: `--subdomain myapp-dev`

### Debugging connection issues

Enable verbose logging to see full protocol traces:

```bash theme={null}
RUST_LOG=debug rustunnel http 3000 2>&1 | tee rustunnel.log
```

Key log messages to look for:

| Message                                  | Meaning                                    |
| ---------------------------------------- | ------------------------------------------ |
| `authenticated session_id=...`           | Auth succeeded                             |
| `tunnel registered public_url=...`       | Tunnel is active                           |
| `data WebSocket connected`               | Data plane is ready                        |
| `new connection from server conn_id=...` | Incoming proxied request                   |
| `yamux data conn error`                  | Data-plane transport error                 |
| `heartbeat timeout`                      | Server stopped responding — will reconnect |

### Multiple tunnels on the same server

Use `rustunnel start` with a config file to open all tunnels over a single control connection:

```yaml theme={null}
server: tunnel.example.com:9000
auth_token: rt_live_abc123

tunnels:
  frontend:
    proto: http
    local_port: 3000
    subdomain: app
  backend:
    proto: http
    local_port: 8080
    subdomain: api
  metrics:
    proto: tcp
    local_port: 9090
```

```bash theme={null}
rustunnel start
```

***

## Related pages

<CardGroup cols={2}>
  <Card title="Quickstart" icon="rocket" href="/docs/quickstart">
    Expose your first local port in three steps with the hosted service.
  </Card>

  <Card title="Request Inspector" icon="magnifying-glass" href="/docs/guides/request-inspector">
    Browse and replay HTTP traffic on localhost:4040 while a tunnel is live.
  </Card>

  <Card title="Self-Hosting Guide" icon="server" href="/docs/guides/self-hosting">
    Run your own rustunnel server with systemd, TLS, and PostgreSQL.
  </Card>

  <Card title="Load Balancing & Health Checks" icon="route" href="/docs/reference/load-balancing">
    Pool multiple backends behind one subdomain with automatic failover.
  </Card>
</CardGroup>
