tnnltnnl
Self-hostable · Built in Rust · Account-controlled

Your localhost,
on the internet.

Expose any local HTTP or TCP service to a public URL in one command — on your own domain, behind real authentication. No reverse proxies, no port forwarding, no fuss.

tnnl — zsh
$

Self-hostable · Built in Rust · Up in minutes

Install the CLI

One static binary, no dependencies. Works on macOS and Linux.

$curl -fsSL https://tnnl.uz/install.sh | sh
Homebrew · soonCargo · soonDocker · self-host

Everything you need to share localhost

One-command tunnels

Run "tnnl http 3000" and get a public HTTPS URL instantly. That’s the whole setup.

HTTP and raw TCP

Expose web apps over HTTP, or tunnel SSH, Postgres, Redis, and anything else over raw TCP — each on its own port.

Your name, or your domain

Get a friendly auto subdomain (flying-bird-4024.tnnl.uz), pick your own (my-app.tnnl.uz), or bring a custom domain like stiv.uz.

HTTPS by default

Every tunnel is served over TLS. Certificates are handled for you — visitors get a padlock, you do nothing.

Account-controlled access

Tunneling requires login. Sessions are managed, revocable, and tied to real user accounts — not anonymous links.

Self-hostable

Run the whole stack on your own VPS with Docker and Postgres. Your traffic, your domain, your rules.

Public subdomains use a wildcard certificate; custom domains get certs on demand.

From localhost to live in three steps

1

Log in

Authenticate once. tnnl stores a secure session token on your machine.

$ tnnl login
Email: you@example.com
Password: ••••••••
✓ Logged in
2

Start a tunnel

Point tnnl at any local port. HTTP or TCP.

$ tnnl http 3000
Tunnel ready:
https://flying-bird-
4024.tnnl.uz
3

Share the URL

Send the link to anyone. Requests stream straight to your machine in real time.

$ tnnl tcp 22
Tunnel ready:
tnnl.uz:2222
# ssh -p 2222 user@tnnl.uz

Under the hood: a single multiplexed connection (yamux) carries every request — fast, ordered, and efficient.

A CLI that gets out of your way

See all commands
tnnl loginSign in to your account
tnnl http <port>Expose a local HTTP server
tnnl tcp <port>Expose a raw TCP service (SSH, DB, …)
tnnl http <port> --subdomain my-appClaim a specific subdomain
tnnl http <port> --hostname stiv.uzServe on your own domain
tnnl logoutRevoke this session

Bring your own domain

Serve a tunnel on a domain you own — stiv.uz, app.yourcompany.com, anything. Point one DNS record at tnnl and you're live — the CLI tells you exactly which record to add and verifies it for you. HTTPS is automatic: the certificate is issued and renewed for you the first time your domain is visited. No cert setup, no renewals.

$ tnnl http 3000 --hostname stiv.uz
⚠ Add this DNS record: stiv.uz. A 203.0.113.10
Tunnel ready once DNS propagates → https://stiv.uz
✓ HTTPS certificate issued automatically

Run it yourself

tnnl is built to be self-hosted. Spin up the server and a Postgres database with one Docker Compose file, point a wildcard domain at it, and you have your own private tunneling service — with your own users, your own domain, and zero third-party dependency.

Single Rust binary + Postgres
Docker Compose included
Wildcard + custom-domain TLS
Invite-only user accounts
docker-compose.yml
$ docker compose up -d
✓ tnnl server listening on :443
✓ postgres ready
Point *.yourdomain at this host and go.

Built for control, not anonymity

Tunneling requires a real account, and the auth is hardened end to end — so you decide exactly who can put what online.

Read the security docs
Invite-only
No open sign-ups. A superadmin creates accounts; there’s no public registration.
Real sessions
Every device gets a revocable session token. See and kill them from your dashboard.
Encrypted in transit
Tunnels are served over TLS end to end.
Passwords done right
Argon2 hashing, forced password reset on first login.

Ship your localhost in one command.

Install the CLI, log in, and you're online.