Getting started
From nothing to your first service reachable at your own domain. About 20 minutes, most of it DNS propagation.
The big picture: you run a small server on a machine with a public address (a $5 VPS is plenty), and a tiny agent on the machine that has the service — your home server, a NAS, a Raspberry Pi. The agent dials out to the server; visitors come in through your domain.
1. What you need
- A domain you control — e.g.
example.com. This guide uses the dedicated sub-domaintunnels.example.com. - A public host for the server: any always-on Linux box with a public IP — VPS, cloud instance, a spare server in a datacenter.
- A machine with something to share — that is where the agent runs later. This guide assumes a web service on port
3000; any port works.
You do not need: port forwarding on your home router, a static IP at home, or any programming. Why? Connections are always made from home outward, and routers happily allow that direction — even carrier-grade NAT, which rejects every incoming connection by design, cannot get in the way.
2. Point the domain at your server
In your DNS provider's panel create two records with the server's IP address (replace 203.0.113.10):
| Type | Name | Value |
|---|---|---|
| A | tunnels.example.com |
203.0.113.10 |
| A | *.tunnels.example.com |
203.0.113.10 |
The first makes the admin panel reachable; the second — the wildcard record — is what makes every tunnel work. Each tunnel is a subdomain like myapp.tunnels.example.com, and the wildcard points them all at your server in one go. Without it, new tunnels would need a new DNS record every time.
If your provider needs a CNAME instead, point both at the server's hostname.
3. Install the server
With Docker (recommended — the image includes everything):
# docker-compose.yml on the public host
services:
tunnel-me:
image: ghcr.io/reddec/tunnel-me
command: >-
serve
--domain tunnels.example.com
--public-url http://tunnels.example.com:8080
--db /data/tunnel.db
--auth basic
--auth.basic.username me
--auth.basic.password pick-a-long-random-one
ports:
- "8080:8080"
volumes:
- ./data:/data
restart: unless-stopped
docker compose up -d
Full flag reference: Server reference.
Protect the panel before going public. The server's default (
--auth static) performs no credential check at all. The compose file above already sets--auth basicwith a username and password — keep that in. All sign-in options live in Authentication.
The --public-url above is the address that works now. When you add HTTPS in the last step, change it to https://tunnels.example.com — it is baked into the connect commands the panel shows.
HTTPS comes later (recommended: a reverse proxy in front — see Reverse proxy). For now the panel works on http://tunnels.example.com:8080.
4. Create your first tunnel
Open http://tunnels.example.com:8080 and sign in with the credentials you set.
- Click New agent, enter a sub-domain — say,
myapp. The dialog shows the future address:myapp.tunnels.example.com. - Open the new tunnel and go to Tokens → New token. Give it a label like "home server".
- Copy the token now — it is displayed exactly once.
5. Connect from home
On the machine with your service (the one where port 3000 answers), paste the one-line command from the tunnel's Overview tab. It looks like this:
curl -fsSL http://tunnels.example.com:8080/boot/connect/<token> | sh -s -- 3000
It downloads the agent binary, installs it to ~/.local/bin, and starts sharing your local port 3000. The 3000 at the end is the upstream — the local service to expose. Share a different machine on your network with 192.168.1.50:8123, or a folder of files with ./my-site (all forms in the agent guide).
The terminal now shows the agent running and the address it is reachable at. Keep it running — for an always-on setup, run it under systemd (agent guide).
6. Verify
Open http://myapp.tunnels.example.com:8080 — you should see your service. Traffic now flows: browser → your server → through the tunnel → your home machine. Nothing about your home network is exposed except this one service.
7. Add HTTPS
Right now everything is plain HTTP on port 8080. The recommended finishing touch: put Caddy/nginx/traefik in front with a wildcard certificate, port 80/443, and done — https://myapp.tunnels.example.com. Walkthrough: Reverse proxy.
Where to next
- Choose who may visit each tunnel: Authentication
- More scenarios like this one — demos, Docker, Kubernetes, corporate SSO: Use cases
- A guided tour of every panel page: Admin panel
- All agent flags and recipes: Agent guide
- Something not working: Troubleshooting