Opening Tunnels
Basic usage
# Expose a local port (positional shorthand)
nullbore open 3000
# ✓ https://a7f3bc.tunnel.nullbore.com → localhost:3000
# Or with explicit flag
nullbore open --port 3000
This creates a tunnel with a random slug and a 1-hour default TTL.
Named tunnels
On Dev and Pro plans, users with a claimed account subdomain can choose their tunnel URL:
nullbore open --port 3000 --name myapp
# ✓ https://myapp.pj.nullbore.com → localhost:3000
Named tunnels live under your account subdomain (*.yourname.nullbore.com). Without a claimed subdomain, tunnels get random slugs on *.tunnel.nullbore.com.
Names must be 2-63 characters, lowercase alphanumeric and hyphens only.
TTL (time to live)
Every tunnel has a TTL — the maximum time it stays open. When it expires, the tunnel closes and the client exits cleanly (no reconnect).
nullbore open 3000 --ttl 30m # 30 minutes
nullbore open 3000 --ttl 4h # 4 hours
nullbore open 3000 --ttl 0 # persistent (Dev plan max)
TTL limits depend on your plan:
| Plan | Max TTL |
|---|---|
| Free | 2 hours |
| Dev | Persistent |
| Pro | Unlimited (persistent) |
Idle TTL mode
With --idle, the TTL becomes an inactivity timeout instead of a hard deadline. The tunnel stays alive as long as there's traffic, and only expires after the TTL period of silence.
# Stay alive while there's traffic, close after 30 min of silence
nullbore open 3000 --ttl 30m --idle
This is useful for:
- Dev servers you want up while you're working
- MCP servers that should be available while an agent session is active
- Demo environments that clean themselves up
Basic auth
Protect your tunnel with HTTP basic auth. Visitors are challenged with a 401 before any request reaches your local service:
nullbore open 3000 --auth admin:s3cret
# ✓ https://a7f3bc.tunnel.nullbore.com → localhost:3000 [auth protected]
The Authorization header is stripped before forwarding — your local service never sees it. Auth also works in config.toml for daemon tunnels:
[[tunnels]]
port = 3000
auth = "admin:s3cret"
Multiple tunnels
Open several tunnels at once:
# With the -p flag (PORT:NAME format)
nullbore open -p 3000:api -p 8080:web -p 5432:db
# ✓ https://api.pj.nullbore.com → localhost:3000
# ✓ https://web.pj.nullbore.com → localhost:8080
# ✓ https://db.pj.nullbore.com → localhost:5432
# Positional shorthand (random slugs)
nullbore open 3000 8080 5432
# ✓ https://a7f3bc.tunnel.nullbore.com → localhost:3000
# ✓ https://b2e91d.tunnel.nullbore.com → localhost:8080
# ✓ https://c4f7a0.tunnel.nullbore.com → localhost:5432
Named tunnels (the -p PORT:NAME form) require a Dev+ plan with a claimed account subdomain. Without one, names are silently ignored and you get random slugs.
Flags apply to all tunnels in the command:
nullbore open 3000 8080 --ttl 2h --auth demo:pass
Via the API
curl -X POST https://tunnel.nullbore.com/v1/tunnels \
-H "Authorization: Bearer nbk_your_key" \
-H "Content-Type: application/json" \
-d '{"local_port": 3000, "ttl": "30m", "name": "api", "auth_user": "admin", "auth_pass": "s3cret"}'
See API: Tunnels for full details.