How it works
Port Zero runs a background daemon on your machine that scans running processes and
Docker containers for the PZ_TUNNEL environment variable (see Tunnels &
PZ_TUNNEL for the full syntax). What happens next depends on the
suffix.
Cloud tunnels: *.tunnel.portzero.cloud
Port Zero opens a WebSocket connection to edge.portzero.net — Port Zero’s edge, a
domain we own whose subdomains forward to programs on your local machine — and
registers the tunnel. Requests arriving from the internet are relayed through the edge
to your daemon, which forwards them to the real ephemeral port on your machine and
relays the response back. This requires portzero login; see Cloud
tunnels.
Local tunnels: *.portzero.local
For a name ending in .portzero.local, the daemon builds a small private network on
your machine, entirely in user space:
- Create a virtual network interface (a TUN device) on your machine, if it hasn’t already, and route a private address range into it.
- Assign a stable virtual IP to the process or container’s name, drawn from that private range. The same name always gets the same virtual IP for the life of the daemon, so DNS answers stay stable across restarts.
- Create a virtual DNS record for that virtual IP, from the name in
PZ_TUNNEL. A small embedded DNS server answers only for*.portzero.local, and a scoped OS resolver setting routes just that suffix to it — every other.locallookup (printers, AirDrop, a teammate’s machine) is untouched. - Forward the port named in
PZ_TUNNEL, on that virtual IP, to the real randomly-assigned port the process or container is actually listening on.
When a client connects to the virtual IP, the daemon completes the TCP handshake itself and proxies bytes to the real backend — no OS-level socket is opened on the client side, and no port is ever hand-assigned. Run a different branch in a separate worktree and it gets its own stable URL at the same time, with no conflict. This works for any TCP protocol, not just HTTP.
To serve https://*.portzero.local without browser warnings, Port Zero also installs a
local certificate authority into your OS and browser trust stores, scoped so it can
only sign certificates for *.portzero.local — see Security for what
that CA can and can’t do.
What this means day to day
- No port bookkeeping. Bind to port
0, let the OS pick, and Port Zero finds it. - Two projects, two names, zero collisions. Ports are OS-assigned per process; names are yours to choose. There’s no way for two running things to fight over the same port number.
- The URL is knowable before you deploy. Because the name comes from a template you control (see template variables), you can compute and share a tunnel’s URL before the process that will answer it has even started.
This creates its own tunnels natively on your machine and requires elevated privileges for the Local overlay specifically — see Platform privileges for exactly what’s needed and what happens if they’re missing.