Use the CLI to expose local services and the dashboard to monitor and manage them.
The CLI discovers local processes and maintains the tunnel connection.
This installs devenv (dispatcher) and port-zero (the actual binary). You can also run port zero <cmd>.
From source: clone port-zero and run cargo install --path client/crates/cli (or just install).
Opens your browser to complete login via the dashboard. Stores credentials in ~/.devenv/auth.json.
Headless: port zero login --interactive --email you@example.com
Go to app.portzero.cloud and sign in with email (magic code) or GitHub.
The dashboard shows all your active tunnels and account settings.
Set PORT_ZERO on the process (or its parent; children inherit it). The daemon scans running processes for this variable.
How port detection works: The daemon finds the process (or child process via inherited env) that has PORT_ZERO and is listening on TCP port(s). It reads the listening sockets directly from the OS (via /proc or lsof). By default it forwards the lowest-numbered port bound to all interfaces (0.0.0.0). If the process listens on multiple ports, the chosen one becomes the tunnel target; use care or explicit strategies if you need a specific one.
Avoiding port conflicts entirely: Let the OS assign an ephemeral port by starting your server with PORT=0 (or equivalent for your runtime, e.g. server.listen(0) in Node). The kernel guarantees a free port. The daemon will discover whichever port your process actually bound. This is a major advantage of Port Zero—no more fighting over fixed ports like 3000 or 8080 across projects or team members.
The daemon scans every 2 s for processes with `PORT_ZERO`, opens a persistent WebSocket to the edge, and registers the discovered route+port. TLS is automatic.
Use these in PORT_ZERO for automatic unique names. All tunnels must end with USERNAME.tunnel.portzero.cloud (the label immediately before .tunnel must be your account username):
| Variable | Meaning |
|---|---|
{service} | Executable / process name |
{project} | Git directory name |
{branch} | Current git branch |
{worktree} | Worktree or branch |
{user} | OS user |
{machine} | Hostname |
{uid} | Short account ID (guarantees uniqueness) |
{username} | Your account username (recommended for the namespace segment). Falls back to {uid} then {user}. |
PORT_ZERO={project}-{branch}-{username}.tunnel.portzero.cloud npm run dev Example: myapp-main-alice.tunnel.portzero.cloud
Open app.portzero.cloud after logging in.
Quick stats, active environment count, and install reminder. Lists your running services at a glance.
Live list of routes with status, public URL, local port, request count, bytes transferred, and last-seen time. Auto-refreshes.
Your tunnels always live at predictable *.USERNAME.tunnel.portzero.cloud addresses. No custom domains.
Update display name, view account ID, manage billing and plan, see usage, and sign out everywhere.
Routes you start via the CLI appear automatically in the dashboard (and vice versa — the account is shared).
port zero login or dashboard).PORT_ZERO=... prefix (or export it for a shell session).port zero status or the Tunnels page to inspect.| Command | Description |
|---|---|
port zero start | Start discovery daemon + tunnel connection (background) |
port zero stop | Stop the daemon |
port zero restart | Restart the daemon |
port zero status | Show running state, routes, connection health |
| Command | Description |
|---|---|
port zero login [--interactive] [--email E] | Authenticate (browser by default) |
port zero logout | Remove local credentials |
port zero whoami | Print current user, plan |
PORT_ZERO | The only documented variable. Set on your process (or inherited by child) to tag it for discovery. Value is the desired public hostname, which must end with .<your-username>.tunnel.portzero.cloud. Supports the template variables listed above. |
port zero loginPORT_ZERO is set on the actual listening process (or inherited by it from parent), then restart the service and wait for the next scan (~2s). The daemon detects processes by scanning their environment.status. The daemon discovers the exact TCP port(s) the tagged process (or its child) is listening on.port zero stop first.
See the full docs in the repo under docs/ for self-hosting and advanced details.