THE FIELD GUIDE
TAILMUX DOCUMENTATION

Port forwarding & local URLs

Reach remote loopback services through localhost or a custom name.

tailmux forward personal/devbox 3000             # localhost:3000 → remote localhost:3000
tailmux forward personal/devbox 3000-3010        # inclusive range (up to 100 ports)
tailmux forward personal/devbox 8080:3000        # local:remote mapping
tailmux loopback setup personal/devbox            # configures devbox.test
tailmux loopback setup work/buildbox              # configures buildbox.test
tailmux forward personal/devbox 3000-3005 --name devbox.test
tailmux forward work/buildbox 3000-3005 --name buildbox.test
tailmux forwards                                # IDs, routes and status
tailmux forwards --json
tailmux unforward <id>

Without --name, forwarding carries arbitrary TCP unchanged over SSH to the remote machine's loopback interface. Using the same local and remote port preserves localhost URLs, including OAuth callbacks registered for localhost. Raw TCP listeners bind only to 127.0.0.1; they are not exposed on your LAN. SSH must allow local forwarding; no Tailmux installation or additional service is needed remotely.

With --name, Tailmux runs an HTTP reverse proxy on a dedicated loopback address for that canonical box. Configure it once before starting the forward:

tailmux loopback setup personal/devbox             # default: devbox.test
tailmux loopback setup work/buildbox --name workbox.test
tailmux loopback list

Tailmux assigns each box a stable address from 127.77.x.y, maps the chosen name in this computer's /etc/hosts, and binds that box's named routes to its address. devbox.test:3000 and workbox.test:3000 can therefore coexist even though they use the same port. .localhost is rejected: browsers resolve it internally to 127.0.0.1, so it cannot select a dedicated per-box address.

Setup needs administrator access because it changes the local loopback interface and /etc/hosts. It changes only this computer and installs nothing on the remote host. On macOS, setup installs a root-owned launchd job that restores the alias at boot using /sbin/ifconfig. Run setup once more to upgrade an older assignment. A process listening on wildcard 0.0.0.0:<port> may still conflict with the same port on a dedicated address.

Named forwards rewrite HTTP Location, Content-Location and Refresh redirects pointing directly to localhost, 127.0.0.1 or ::1 on ports in that forward group. JSON URL strings are also rewritten, covering common authentication responses, with a 2 MiB buffering limit. Loopback cookie domains are removed to make cookies host-only; Secure, HttpOnly and SameSite attributes are preserved. Requests use the upstream localhost Host header; matching Origin and Referer URLs are translated back. WebSocket upgrades and streaming responses use Go's reverse proxy. Use --no-rewrite to disable response, Origin and Referer rewriting.

This does not rewrite HTML/JavaScript, external URLs containing OAuth redirect_uri parameters, or HTTPS URLs. OAuth provider callback allowlists, HTTPS requirements and application origin validation may still require configuration. Unlike localhost, a .test HTTP origin is not automatically treated as a secure context; Secure cookies, service workers and OAuth flows may need HTTPS, a public URL, or application settings. For a strict localhost-only login flow, use the unnamed forward with the original port. Named mode serves HTTP; use raw TCP for end-to-end TLS or non-HTTP protocols. Two raw forwards cannot own the same local port. Unknown HTTP hostnames are rejected.

Saved forwards and reconnection

tailmux forward personal/devbox 3000 --name devbox.test --save web
tailmux forwards
tailmux forward --resume web
tailmux unforward web

Forwards run in the local daemon after the CLI exits. Every group is persisted automatically in the private TAILMUX_HOME/forwards.json file and restored when the daemon next starts. Use --save NAME to choose a friendly name; otherwise Tailmux generates one. This does not install a login/boot service. tailmux stop stops networking but retains saved definitions. unforward stops and forgets its group, using either its runtime ID or saved name.

After upgrading, run tailmux stop so the next networking command starts a daemon with isolated-loopback support. For a saved named forward created by an older version, configure its exact host/name with tailmux loopback setup, then use tailmux forward --resume NAME if it remains failed. Current macOS loopback setup restores aliases automatically at boot.

SSH failures enter reconnecting and retry up to eight times with capped backoff. Saved groups also retry when their initial restoration cannot reach the host. Exhausted retries remain visible as failed; check SSH access and your unlocked agent before using tailmux forward --resume NAME. Ports remain reserved for a group during reconnection so another application cannot silently take over its local address.

Port ranges are reserved together: a conflict rejects the new group without disturbing existing forwards. Each group uses one SSH connection and private temporary Unix sockets. SSH uses your existing configuration and agent in batch mode.

Inspect and select ports

tailmux ports personal/devbox
tailmux ports personal/devbox --forward
tailmux loopback setup lab/worker --name worker.test
tailmux forward lab/worker 3000 --name worker.test --json
tailmux forwards --json

The ports picker shows TCP listeners and visible process names. --forward selects one and forwards the same port locally. Use forward for ranges, custom port mappings and names.

JSON output contains each group's id, spec, state, optional error, and public connector state. Options follow the host and may appear before or after port arguments.

Public URLs with Cloudflare or ngrok

Tailmux can manage a provider connector alongside a single HTTP forward. Install the provider CLI locally and configure its account credentials first. A public forward uses an explicit HTTPS origin both for the provider and for redirect rewriting:

Public HTTPS hostname → provider connector → local HTTP proxy → SSH → remote localhost

The public provider options cannot publish a port range. They use HTTP to the remote service; they are not raw TCP publishing options. Managed public forwards remain on 127.0.0.1 because their provider connector supplies the public hostname; they do not require loopback setup.

Cloudflare: stable hostname

Use a locally managed named tunnel with a domain in your Cloudflare account. Follow Cloudflare's local tunnel setup to authenticate, create a tunnel and route a hostname:

cloudflared tunnel login
cloudflared tunnel create tailmux-preview
cloudflared tunnel route dns tailmux-preview preview.example.com

tailmux forward personal/devbox 13000:3000 \
  --cloudflare tailmux-preview \
  --url https://preview.example.com \
  --save preview

Tailmux writes a private connector configuration containing only the selected hostname and origin, plus a 404 catchall. Cloudflare credentials remain in the provider's normal credential directory. Existing unrelated connector ingress rules are not imported. Use the name or UUID of your locally managed tunnel; dashboard token-based tunnels are not configured automatically by this command.

The URL is stable because the hostname/DNS route remains configured. Tailmux does not register domains or create Cloudflare DNS records. See Cloudflare routing for the provider side.

ngrok: account domain

Install and authenticate ngrok, then select an HTTPS domain available in your account:

tailmux forward personal/devbox 13000:3000 \
  --ngrok \
  --url https://YOUR-ASSIGNED-DOMAIN.ngrok-free.app \
  --save preview

Replace the placeholder with your actual domain. ngrok's free plan provides an assigned development domain; custom domain availability depends on your account. See account limits and the agent CLI.

Public redirects

With a provider flag, Tailmux routes the public hostname and rewrites direct localhost redirect headers and bounded JSON URL strings to the explicit HTTPS origin. Matching incoming Origin/Referer URLs are translated back to the remote localhost origin. Loopback cookie domains are removed while their security attributes are retained. --no-rewrite disables those translations when the application already handles its public origin.

This does not rewrite HTML or JavaScript, nested OAuth callback parameters or provider callback registrations. Apps may still need public base URL, trusted proxy and allowed-origin settings. Named local forwards without a provider retain their local HTTP rewrite behavior.

Lifecycle and access

The daemon owns the provider process. unforward stops the connector and SSH tunnel; tailmux stop stops all local connectors. Saved public forwards restart when networking starts again, which republishes the selected service. Provider exits retry up to five times with capped backoff. public_state reports connector lifecycle, not a verified public HTTP health check. Errors point to private provider logs; credentials are not printed in status output.

A provider's hostname and DNS record remain until removed at that provider. Stopping Tailmux does not delete those external resources.

Publishing makes the selected service reachable beyond your tailnet. Configure provider access policies or app authentication if the preview should be private. Orca runtime/control ports should remain behind their private SSH tunnel.

The URL remains usable only while the app, Tailmux daemon, SSH connection and connector are running. A sleeping laptop interrupts it. For a URL independent of your laptop, run a provider connector directly on the remote box against http://127.0.0.1:3000; that separate route does not use Tailmux.

Temporary Cloudflare preview

Quick Tunnels remain a manual alternative:

tailmux forward personal/devbox 13000:3000
cloudflared tunnel --url http://127.0.0.1:13000

This prints a random temporary trycloudflare.com URL; it is not the managed stable-URL workflow above. The unnamed forward does not rewrite redirects to that random URL. Stop this separately launched connector with Ctrl+C. See Quick Tunnels.

macOS boot restoration

Loopback setup writes one root-owned /Library/LaunchDaemons/com.tailmux.loopback.<IP>.plist per address. At boot it runs Apple’s /sbin/ifconfig once to restore that alias; it does not launch Tailmux as root. The hostname remains in /etc/hosts. Existing users should rerun their usual loopback setup command once to install this upgrade. Forward definitions restore when Tailmux networking starts; this does not automatically start networking at boot.

On this page