DOCS · 60 SECONDS TO LIVE

Install. Sign in. Tunnel.

Three commands and your localhost has a public URL. Everything else is on the dashboard — tokens, custom domains, edge auth, request inspector, audit log.

1 Quickstart

Install

One line. Detects OS + arch, drops the binary into ~/.local/bin (or /usr/local/bin as root).

curl -fsSL https://login.21tunnel.com/install.sh | sh

Windows PowerShell: iwr https://login.21tunnel.com/install.ps1 -UseBasicParsing | iex

Sign in

Opens a browser, you click Authorize, the agent saves a 90-day token to ~/.config/mytunnel/credentials. From here on, no flags needed.

mytunnel login

Tunnel

Forward any local port. The URL is yours — same one across agent restarts.

mytunnel http 3000
 Tunnel active: https://kind-otter-7f.21tunnel.com → 127.0.0.1:3000

Want a specific name? mytunnel http 3000 --subdomain ci-runner

2 CLI reference

The eight commands you'll actually use.

mytunnel http <port> HTTP tunnel; sticky random URL across restarts.
mytunnel http <port> --subdomain <name> Claim a specific subdomain. First-come per org.
mytunnel tcp <port> Opaque TCP tunnel. Use for databases, raw protocols.
mytunnel ssh [port=22] SSH-tunnel sugar. Prints a copy-pasteable ssh -p N user@host.
mytunnel login Browser-redirect auth. Saves a 90-day per-machine token.
mytunnel start Run every tunnel declared in mytunnel.toml.
mytunnel list List your active tunnels (queries the dashboard).
mytunnel logout Revoke + clear local credentials.

mytunnel.toml — multi-tunnel orchestration

Drop a mytunnel.toml beside your project; mytunnel start runs everything in parallel. Search order: --tunnels-config FILE, ./mytunnel.toml, ~/.config/mytunnel/tunnels.toml.

# mytunnel.toml — every tunnel runs in its own yamux session.
[[tunnels]]
kind = "http"
port = 3000
subdomain = "api"
headers = { "X-Forwarded-Host" = "api.acme.com" }

[[tunnels]]
kind = "http"
port = 5173
subdomain = "web"

[[tunnels]]
kind = "tcp"
port = 5432

Global flags

-H KEY=VALUEInject a request header on every forwarded HTTP request.
--no-stickyForce a fresh random subdomain instead of the saved one.
--token-file PATHUse a token file (override the saved credentials).
--token-env VARRead the token bytes from an env var (CI-friendly).
--verboseLog at DEBUG. Useful when filing bugs.

3 Dashboard concepts

Five capabilities the CLI doesn't surface — they live on the dashboard at login.21tunnel.com.

Tokens

One credential per machine. Mint with a label (ci-runner, dev-laptop), rotate when keys leak, revoke from any browser. mytunnel login mints one for you automatically; the dashboard is for the cases where you need more control.

Custom domains

Bring app.acme.com. The dashboard hands you a TXT record; add it at your DNS, click Verify, then bind the domain to one of your tunnels. Real ACME-style proof — not a string field.

Reserved subdomains

Claim myco-prod org-wide so nobody else can take it, even between tunnels. Pro and above.

Edge auth Pro

Gate any tunnel behind Google sign-in before traffic reaches your localhost. Optional email allowlist (alice@acme.com) or domain allowlist (acme.com). Toggle from the tunnel row's globe icon.

Inspector

Every inbound request streams to the dashboard over a WebSocket. Click any request to inspect headers + body. Retention scales with plan — 7 days on Hobby, 30 on Pro, 90 on Team, 365 on Enterprise. Replay is wired in code but gated server-side until per-tunnel allowlists ship.

4 REST API

For when you want to wire 21tunnel into a deploy script, CI runner, or your own dashboard.

The full OpenAPI 3.1 spec lives at login.21tunnel.com/api/openapi.yaml. Browse it interactively:

Open API reference

Auth

Three patterns, pick the one that fits the caller:

Authorization: Bearer <jwt> User session. Get one from POST /auth/login or after Google OAuth. 15-minute TTL; refresh via POST /auth/refresh.
Cookie: qnt_refresh=… HttpOnly refresh cookie set by /auth/login. Browser sends it automatically; servers should not.
Authorization: Bearer <admin> Static admin token. Service-to-service / ops only. Configured server-side, never browser-visible.

Common operations

A selection of the most-used endpoints. The full surface (~60 routes) lives in the OpenAPI spec.

POST /auth/signupCreate an account. Returns pending_email_verification.
POST /auth/verify-email-otpVerify the 6-digit signup OTP (10-min TTL, 5-attempt cap).
POST /tunnelsCreate a tunnel row + reserved subdomain.
GET /tunnelsList your tunnels with stats + auth state.
POST /tokensMint a capability token (CLI agent credential).
POST /tokens/masterMint a mtk_master_ key for AI-agent delegation.
POST /projectsCreate a project namespace (subdomain suffix isolation).
POST /projects/:slug/tokensMint a project-scoped child token via a master key.
POST /domainsAdd a custom domain; returns TXT challenge.
POST /domains/:id/verifyVerify the TXT record was added.
PUT /tunnels/:id/edge-authEnable Google sign-in gate on a tunnel.
GET /inspectorRecent inbound requests (replay coming).
GET /me/eventsYour audit log — every action you've taken.

All requests use JSON. Errors return { "error": "code", "message": "…" } with stable machine codes (quota_exceeded, upgrade_required, etc.) — branch on error, not English.