Quickstart
Install tunnelctl, log in, and put your first local service on a public URL.
This guide takes you from zero to a live public URL in a few minutes.
Prerequisites
- A tunnelctl account on your organization's identity provider (SSO).
- A local service listening on some port (e.g. a dev server on
8080).
1. Install
tunnelctl is a single self-contained binary. Install it from your platform's package manager, or run it straight from the container image.
# Register the dnf repository (Rocky / Fedora / RHEL):
dnf config-manager addrepo --from-repofile="https://git.piblade.net/api/packages/tunnelctl/rpm.repo"
# Install (signed by the repo key, no manual import):
dnf install tunnelctl# Trust the repo signing key:
sudo curl https://git.piblade.net/api/packages/tunnelctl/debian/repository.key -o /etc/apt/keyrings/forgejo-tunnelctl.asc
# Add the apt source:
echo "deb [signed-by=/etc/apt/keyrings/forgejo-tunnelctl.asc] https://git.piblade.net/api/packages/tunnelctl/debian stable main" | sudo tee /etc/apt/sources.list.d/forgejo.list
# Refresh + install the pinned version:
sudo apt update
sudo apt install tunnelctl=0.10.4-1# Register the zypper repository (openSUSE / SLES):
zypper addrepo https://git.piblade.net/api/packages/tunnelctl/rpm.repo
zypper install tunnelctl# Trust the repo signing key:
curl -JO https://git.piblade.net/api/packages/tunnelctl/alpine/key
# Add the apk repository for your Alpine release (v3.20 shown):
echo "https://git.piblade.net/api/packages/tunnelctl/alpine/main/v3.20" | sudo tee -a /etc/apk/repositories
# Install the pinned version:
sudo apk add tunnelctl=0.10.4-r1# Add the tunnelctl Homebrew tap (one-time):
brew tap tunnelctl/tunnelctl https://git.piblade.net/tunnelctl/homebrew-tunnelctl.git
# Install the CLI:
brew install tunnelctlWindows packaging is on the roadmap. For now, run the container image or build from source.
Distroless multi-arch image (amd64 + arm64); the entrypoint is tunnelctl, so CLI
args go straight through:
podman run --rm oci.piblade.net/tunnelctl/tunnelctl-cli:latest --helpRunning an actual tunnel from a container needs a little network setup — see Running in a container.
2. Log in
tunnelctl loginBy default the CLI detects the right sign-in flow (--auth-flow=auto): on a desktop it
opens your browser to the identity provider; on a headless box (SSH, container, CI) it
switches to the device flow — a short code + URL you open on any device. You can also
force a flow explicitly:
tunnelctl login --auth-flow=device # headless: sign in from another deviceSee login & auth for all --auth-flow values.
Check who you are at any time:
tunnelctl whoami # show identity + token expiry
tunnelctl whoami --verify # also verify the tokens against the IdP and API3. Expose a local service
Pick a protocol. For a web app, that's an HTTP tunnel — you give it a slug, which becomes the public subdomain:
tunnelctl up http myapp 8080myapp is now served at https://myapp.intunnel.eu, forwarding to 127.0.0.1:8080.
The command runs in the foreground and streams logs — press Ctrl+C to shut the tunnel
down cleanly.
Target formats
The target can be a bare port (8080 → 127.0.0.1:8080), a host:port
(localhost:5173, [::1]:5173), or — for HTTP — a URL (http://localhost:3000). Omit
it to reuse the target you used last time.
TCP / UDP tunnels
Non-HTTP services (databases, game servers, DNS, …) use a TCP or UDP tunnel, addressed by a public port instead of a slug:
tunnelctl up tcp 27017 5432 # tcp.intunnel.eu:27017 → 127.0.0.1:5432 (e.g. Postgres)
tunnelctl up udp 5353 53 # udp.intunnel.eu:5353 → 127.0.0.1:53Ports come from a shared pool — tunnelctl ports pick tcp suggests a free one. See
ports and Tunnels & protocols.
Run it in the background
To keep the tunnel up after you close the terminal, detach it as a daemon:
tunnelctl up http myapp 8080 -dThe command returns immediately and the tunnel keeps running.
4. Inspect and stop
tunnelctl status # tunnels running on this host
tunnelctl status --all -v # all your tunnels (every host) + verbose columns
tunnelctl logs http myapp # view the daemon log for a tunnel
tunnelctl down http myapp # stop one tunnel (or: down tcp 27017)
tunnelctl down --all # stop every tunnel on this hostNext steps
- Browse the full CLI reference.
- Understand tunnels & protocols (HTTP slugs vs TCP/UDP ports).
- Learn how authentication works.
- Run tunnelctl from a container (Podman / Docker).