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.