Subdomains
How JustTunnel routes a public URL to a tunnel — random vs reserved names, DNS rules, and per-tier behavior.
Every tunnel gets a public URL on <name>.justtunnel.dev. The <name> part is the subdomain — JustTunnel uses it as the routing key on every inbound request. Names come in three flavors: random per session, requested ad hoc, and reserved across sessions.
How it works
When a request arrives at the JustTunnel edge, the host header (acme-staging.justtunnel.dev) is parsed to extract the subdomain (acme-staging). The edge looks up the active tunnel for that subdomain and forwards the request over its WebSocket. No active tunnel means a 502 from the edge — see Tunnel anatomy for the request path.
The DNS side is wildcard: *.justtunnel.dev resolves to the edge regardless of subdomain. There's no per-tunnel DNS record to provision and no propagation delay — the moment your CLI hands the edge a subdomain, traffic to that hostname starts working.
Three name flavors
Random per session (default)
Run justtunnel <port> with no flag and the CLI gets a friendly two-word name like wandering-otter-42. The name lives only as long as the WebSocket — close the tunnel and the name is released for someone else.
justtunnel 3000
# https://wandering-otter-42.justtunnel.dev
Random names are the right choice for one-off testing where the URL never leaves your terminal.
Requested ad hoc
Pass --subdomain <name> (or -s) to ask the edge for a specific name for this session only. If nobody else has it open right now, the edge accepts. If somebody does — including a paid user who has reserved the name — you get subdomain unavailable and the tunnel exits.
justtunnel 3000 --subdomain acme-staging
Free and Starter plans can request any unused name, but they cannot hold it across restarts. The next user who asks for acme-staging gets it. See Plans and limits for which tiers can hold names across sessions.
Reserved across sessions
Reserved subdomains are a Pro and Team plan feature. A reservation marks a name as belonging to your account so nobody else can claim it, even when no tunnel is active. The CLI invocation stays exactly the same — you reserve in the dashboard, then keep running justtunnel 3000 --subdomain acme-staging as before.
Server-side, reserved names are enforced at tunnel-create time (internal/plan/enforcer.go:103 rejects with RESERVED_SUBDOMAIN_NOT_ALLOWED for plans that lack AllowReservedSub). Walkthrough in Reserve a custom subdomain.
Naming rules
The edge validates every requested name against this regex (internal/subdomain/validation.go:8):
^[a-z0-9][a-z0-9-]{1,28}[a-z0-9]$
In English:
- 3 to 30 characters total
- lowercase letters, digits, and hyphens only
- must start and end with an alphanumeric (no leading or trailing hyphen)
- no underscores, dots, uppercase, or non-ASCII
Good: acme-staging, paul-webhooks, client-preview-2026, api-v3.
Rejected: Acme-Staging (uppercase), _internal (underscore + leading hyphen), -edge (leading hyphen), ab (too short), a * 40 (too long).
Worker tunnels follow a slightly different shape — names are <worker-name>--<team-slug> and the CLI pre-validates so the derived subdomain still fits the 63-character DNS label limit. See Worker tunnels.
Limits and guarantees
What's enforced today:
- Reservation requires Pro or Team. Free and Starter cannot reserve at all (
AllowReservedSub: false). Pro reserves up to 10 names; Team reserves up to 20 per team (not per seat). Frominternal/plan/limits.go. - Reservation is per-account (or per-team). Personal-context reservations belong to your user; team-context reservations belong to the team. Switching contexts does not move reservations across.
- Reservation does not survive plan downgrade. If billing lapses and your plan drops below Pro, the names stop being held — the next requester wins them. See Reserve a custom subdomain.
Best-effort, not guaranteed:
- Memorability of random names. The pool is large but finite; we don't guarantee a specific random name across runs.
- System-reserved names. Some names are blocked by the abuse layer (brand impersonation patterns in
internal/abuse/patterns/patterns.go). The error you get issubdomain unavailable— pick another name.
Related
- Reserve a custom subdomain — task-oriented walkthrough.
justtunnel [port]— the--subdomain/-sflag.- Tunnel anatomy — how subdomain routing fits into the request path.
- Worker tunnels — derived
<name>--<team-slug>subdomains. - Plans and limits — reservation caps per tier.