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:

  1. Create a virtual network interface (a TUN device) on your machine, if it hasn’t already, and route a private address range into it.
  2. 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.
  3. 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 .local lookup (printers, AirDrop, a teammate’s machine) is untouched.
  4. 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.