cmd / tun
tun tunnels local services to the public internet.
It is open source.
Why
I wanted a self-hosted tunnel like ngrok for a Slack Events API integration. It needs no vendor account and keeps data in our infrastructure.
Set up the server
Deploy the server to a host such as Render:
- Public git repository:
https://github.com/croaky/tun - Build command:
go build -o tund ./cmd/tund - Start command:
./tund - Env var:
TUN_TOKEN(shared secret) - Health check path:
/health
Render provides HTTPS. A scale-to-zero plan keeps the cost low for an occasional tunnel.
Server logs:
[croaky] tunnel connected
200 POST /slack/events 147.33ms
[croaky] tunnel disconnected
Set up the client
Install:
go install github.com/croaky/tun/cmd/tun@latest
Create a .env file in the directory where you run tun:
TUN_SERVER=wss://your-service.onrender.com/tunnel
TUN_LOCAL=http://localhost:3000
TUN_ALLOW="POST /slack/events GET /health"
TUN_TOKEN=...
TUN_ALLOW accepts space-separated METHOD /path pairs (exact match, no wildcards).
A request that matches no rule returns 403 Forbidden.
TUN_TOKEN authenticates the client to the server
with Authorization: Bearer <token>.
Run:
tun
Client logs:
[croaky] connected to wss://your-service.onrender.com/tunnel, forwarding to http://localhost:3000
POST /slack/events
The username comes from git config github.user, or $USER.
It shows who holds the tunnel when teammates share a server.
The client reconnects with exponential backoff from 500ms to 30s. Requests time out after 30 seconds. The server accepts one tunnel at a time. A new connection closes the previous one.