FAQ
Why doesn’t Port Zero use real mDNS (Bonjour/Avahi .local names) instead of its own portzero.local domain?
It’s tempting: mDNS already gives you .local names, and in principle a single machine
could bind a separate .local IP alias per service, all on the same port, so
foo.local:80 and bar.local:80 reach different processes without port conflicts. We
looked at it and decided against it, for a few reasons:
- Address ownership. Port Zero’s virtual IPs live in a private range inside its own virtual network interface (see How it works) — a space Port Zero fully owns, so collisions are impossible. Real mDNS reachable from the LAN needs addresses aliased onto the physical interface, out of whatever subnet that network happens to be using. That’s a different subnet every time you change networks, and a real risk of colliding with another device’s address or the DHCP pool.
- Security boundary. Today, a process opened with
PZ_TUNNELis reachable only from the machine running it. Real mDNS + LAN-facing aliases would make local dev services — often unauthenticated — reachable by anyone else on the same Wi-Fi or office network. That’s a meaningful expansion of attack surface for a feature most people only need on one machine. - Reliability. Port Zero’s scoped-domain DNS approach works identically offline, on a VPN, or on networks that filter multicast — common on corporate Wi-Fi and especially hotel/coffee-shop networks with client isolation. Real mDNS is unreliable in exactly those situations.
- Protocol complexity. Port Zero’s embedded DNS server is authoritative for its own domain, so it never has to worry about record conflicts. Real mDNS requires implementing probing, announcing, and conflict tie-breaking against any other Bonjour/Avahi responders already on the network.
If you actually need a process to be reachable beyond the local machine — from another device, a teammate, or the internet — that’s what Cloud tunnels are for, and they’re simpler than making mDNS do this job.
Doesn’t .local belong to mDNS? Does Port Zero break Bonjour/AirPrint/Avahi?
No. Port Zero claims only the portzero.local subtree, not .local itself, using a
scoped resolver entry that sends queries for portzero.local and its subdomains (and
nothing else) to Port Zero’s embedded DNS server. Every other .local name —
printer.local, my-mac.local, your teammate’s AirDrop — still goes to
mDNSResponder/Avahi exactly as before. Port Zero never answers, probes, or announces on
multicast at all.
RFC 6762 does reserve .local for mDNS, so the honest description is: Port Zero carves
one name (portzero.local) out of that space on your machine only. The only
theoretical conflict is a real mDNS device on your network that advertises the hostname
portzero — in that case your machine’s scoped resolver entry claims the name instead
of that device. Nothing else on the network is affected, because the override is local
resolver configuration, not network traffic.
Two platform quirks are worth knowing (both handled by portzero setup):
- macOS intercepts all
.locallookups with its own resolver before other resolvers are consulted, which is why a scoped resolver entry is part of setup. - Linux desktops commonly claim two-label
.localnames via an mDNS nsswitch entry; see Platform privileges for the elevated-privilege setup this requires. Subdomain Local tunnel names likemyapp.portzero.localhave three labels and aren’t claimed by that entry, so they resolve normally.
Remote and cloud coding-agent sessions
Setting up a Local tunnel inside a remote/browser coding session
It works, with one extra step beyond a normal machine: add a hosts entry by hand instead of relying on automatic OS-level DNS, because these sandboxes commonly don’t run the services Linux resolver integration depends on (see Troubleshooting for why).
- Install Port Zero the same way you would anywhere else — see Getting started.
- Start the daemon as root, since the overlay needs elevated privileges:
Leave it running in the background for the rest of the session — for example, launch it from a session-startup hook so it’s already up before you start working.sudo -E portzero start --foreground - Tag your dev process or container with
PZ_TUNNELas usual, e.g.PZ_TUNNEL=myapp.portzero.local:80 npm start— see Tunnels & PZ_TUNNEL. - Check it actually worked:
If the hosts pin check warns, add the entry it suggests.portzero doctor
Exposing a public Cloud tunnel from a remote session
This is Cloud tunnels, not the Local overlay above — and it’s actually simpler in a sandbox: no root, no elevated privileges, no hosts pin. The cloud connector runs fully unprivileged and only needs outbound HTTPS; it’s the Local overlay that needs elevated networking privileges.
- Check the environment’s network policy allows outbound HTTPS to
app.portzero.net(the API) andedge.portzero.net(the tunnel connection). If either is blocked, Cloud tunnels can’t work from that environment —portzero doctorwill show the cloud connection as failed rather than hanging. - Run
portzero login. It prints a URL — open it on any device (your phone, your own laptop) and sign in there; the CLI polls in the background and picks up the completed login automatically.portzero login --interactive(an emailed one-time code typed at the prompt) also works, and needs no network callback of any kind. - Persist the login across sessions, since each session is often a fresh
container: save
~/.portzero/auth.jsonas a secret in your environment, then write it back out at the start of every session. The token doesn’t expire on its own; revoke it from the dashboard orportzero logoutif it’s ever compromised. - Start the daemon (no
sudoneeded for cloud-only use):portzero start - Tag your process with a cloud domain instead of
.portzero.local:
(bind to port 0 as usual.)PZ_TUNNEL=myapp.<username>.tunnel.portzero.cloud:80 npm start - Get the public URL:
orportzero url myapp.<username>.tunnel.portzero.cloudportzero wait <domain> --healthyto block until it’s actually serving.portzero doctorreports cloud connection state either way.