# uqtunnel — install, register, and tunnel a local port You are helping a user set up uqtunnel on their machine so they can expose a local port at a public HTTPS URL. The public service is at https://tunnel.tobu.fyi (server version 0.2.0). ## What uqtunnel is An ngrok-style HTTP tunneling tool. A small CLI on the user's machine opens a persistent HTTP/2 connection to https://tunnel.tobu.fyi; any request to https://.tunnel.tobu.fyi/ is relayed through that connection to a local port. Anyone can hit the public URL — no VPN, no port forwarding, no NAT tricks. ## What the user needs to give you - An API key that looks like `uqt_...` — required. They get one from an admin (the dashboard's Users page mints them). If they don't have one, tell them to ask an admin; do not attempt to mint one yourself. - A local port to expose (e.g. 5173 for Vite, 3000 for Next.js, 8080 for a typical backend). - Optionally a subdomain — must match /^[a-z0-9][a-z0-9-]{2,61}[a-z0-9]$/, so 4-63 chars, lowercase alphanumeric + hyphens, first/last must be alphanumeric. If they don't pick one, the server assigns one. Never echo the API key back after they give it to you. Save it via `uqtunnel login `, which writes ~/.uqtunnel/config.toml mode 600. ## Steps ### 1. Detect what's already there command -v uqtunnel && uqtunnel --version test -f ~/.uqtunnel/config.toml && grep '^api_key' ~/.uqtunnel/config.toml - If `uqtunnel` is installed and there's an api_key line, skip to step 4. - If `uqtunnel` is installed but no api_key, skip to step 3. - Otherwise, install (step 2). ### 2. Install the CLI Check the platform (both `uname -s` and `uname -m` matter): uname -sm The published binaries and their targets: - **Linux x86_64** → `uqtunnel-0.2.0-linux-x64` - **Linux aarch64** → `uqtunnel-0.2.0-linux-arm64` - **macOS Intel** → `uqtunnel-0.2.0-darwin-x64` (Darwin + x86_64) - **macOS Apple Silicon** → `uqtunnel-0.2.0-darwin-arm64` (Darwin + arm64) For all four, use the one-liner: curl -sSf https://tunnel.tobu.fyi/install.sh | sh The script auto-detects the OS + arch and installs to `~/.local/bin/uqtunnel` (or `$UQTUNNEL_BIN`). It does NOT need sudo. If `~/.local/bin` isn't on PATH, add it to the user's shell rc: export PATH="$HOME/.local/bin:$PATH" On macOS Gatekeeper may quarantine an unsigned binary the first time it's run (`"cannot verify developer"`). Clear it with: xattr -d com.apple.quarantine ~/.local/bin/uqtunnel **Windows / target we don't publish**: build from source. Needs Rust 1.85+ (https://rustup.rs) and access to the source repo. The repo lives at `git@uniqgit.dev:trinhhuyit/uq-tunnel.git` — this is an internal git server; if the user doesn't have an account there, they need to ask an admin. Clone and install: git clone git@uniqgit.dev:trinhhuyit/uq-tunnel.git && \ cd uq-tunnel && cargo install --path apps/cli Never `sudo` any of these steps. All install destinations are user-writable on purpose. ### 3. Save the API key uqtunnel login Writes the config file and prints "✓ saved to ~/.uqtunnel/config.toml". If a key was already saved, ask the user whether to overwrite before running this; don't silently clobber. ### 4. Sanity-check the local service is up Before you start the tunnel, confirm something is listening on the target port: ss -ltn 2>/dev/null | grep ":" || nc -z localhost If nothing is listening, tell the user to start their dev server first — the tunnel will register successfully but every request will 502. ### 5. Start the tunnel uqtunnel -p # server-assigned subdomain uqtunnel -p -s # pick your own Foreground. Wait for the CLI to print: ✓ Tunnel is ready! Your url is: https://.tunnel.tobu.fyi Give that URL to the user and stop. Do not close the CLI process — it needs to stay running for the tunnel to work. If the user wants it in the background: nohup uqtunnel -p -s > ~/.uqtunnel/.log 2>&1 & disown Flag that this dies with the shell unless they use screen/tmux. ### 6. Verify the tunnel curl -sSm 5 -o /dev/null -w '%{http_code}\n' https://.tunnel.tobu.fyi/ - 200 (or whatever the local service returns) → success. - 502 "bad tunnel gateway" → the CLI registered but the pool is dead. Restart the CLI. - 404 → someone else has the same subdomain, or the server has a stale row from a previous session. The user should either pick a different name or ask an admin to delete the stale row via `DELETE /api/tunnels/{id}`. ## Defaults baked in — the user should NOT set these The CLI defaults its --host to https://tunnel.tobu.fyi and uses the HTTP/2 carrier automatically. Do NOT tell the user to pass --host or --carrier unless they're pointing at a non-default server. ## What NOT to do - Do not mint or reveal API keys via any admin endpoint. - Do not run uqtunnel with sudo. - Do not tunnel ports on servers the user doesn't own — this skill is for the local machine. - Do not silently overwrite an existing ~/.uqtunnel/config.toml; ask first. - Do not close or restart other uqtunnel processes the user might have running. - Do not `git add` ~/.uqtunnel or paste its contents anywhere. ## Troubleshooting - **"tunnel error: registration failed: 400"** → subdomain regex violation. 4-63 chars, lowercase, alphanumeric + hyphens, first/last alphanumeric. - **"tunnel error: registration failed: 500"** → stale row in the DB with the same subdomain (usually from a previous kill without teardown, or a server restart while a tunnel was live). Ask an admin to reap it via the dashboard delete button or `DELETE /api/tunnels/{id}`. - **Public URL returns 502 "bad tunnel gateway"** → the pool is empty. Restart the CLI. If it keeps happening, the server may be running an old build without the take_socket fix (commit 03dc305); an admin needs to redeploy. - **Public URL returns 404** → either the subdomain doesn't exist, or the DB row is stale (agent died without cleanup). - **Vite HMR breaks / random reconnects** → we default to the HTTP/2 carrier which handles HMR fine. If someone forced --carrier tcp, drop it. ## Where to look for more - Install page (this is where https://tunnel.tobu.fyi/llm.txt is linked from): https://tunnel.tobu.fyi/install - Dashboard (admin-gated, for looking at traffic + reaping tunnels): https://tunnel.tobu.fyi/dashboard/ - API reference (Swagger): https://tunnel.tobu.fyi/docs - CLI version metadata (JSON): https://tunnel.tobu.fyi/api/cli/version That's the whole flow. Ask the user for missing values (API key, port, optional subdomain), run the steps, hand back the public URL.