Guides

Phone relay & remote

vmux relay speaks the community Cmux Remote HTTP and WebSocket protocol. Point that iPhone app at your Tailscale IP and the relay port (default 4399, configurable) and you can drive vmux workspaces and panes from your phone.

iPhone (Cmux Remote)  ── Tailscale ──►  vmux relay :port  ── Unix socket ──►  vmux daemon
                                         (default 4399)

This is a compatibility layer, not an official Manaflow product. Official cmux Mobile Connect is a different stack and will not work with it. Protocol drift in the App Store app may require relay updates.

The relay is on by default. On vmux attach, a managed relay starts if it is not already running (bind: Tailscale IP when available, otherwise localhost). Starting or stopping the relay does not change how attach, the CLI, or the daemon behave beyond that process.

The port is not fixed

The historical Cmux Remote default is 4399, and vmux uses that out of the box — but the port is not hard-wired.

HowExample
Config (managed relay / attach auto-start)vmux config set relay.port 4400
CLI overridevmux relay serve --listen 100.x.y.z:4400
relay.json listen"listen": "127.0.0.1:4400"

Whatever you choose, the phone app (and paste-page URLs) must use the same port.

The managed phone relay is machine-global, not per vmux --session. Session default and session dev share the same config port and the same process — a second attach sees "already running" and reuses it. That is intentional: the phone app points at one host:port.

Settings

In vmux attach, open ⚙ set and find the mobile relay section:

SettingMeaning
mobile relayon / off (default on)
relay bindauto (Tailscale if online, else localhost), tailscale, or local
relay portTCP port (default 4399)
relay localhostAllow device registration from 127.0.0.1, for dev
paste pageServe /paste for screenshot paste
phone-fit resizeLeased view-size overrides (relay.allow_view_resize)

Changing relay port / bind / toggles stays pending until you move to another row or close Settings — config is then saved once and the managed relay restarted once, no multi-second lag while cycling ports. There is deliberately no "all interfaces" option: the relay refuses to bind 0.0.0.0 or ::.

vmux config set relay.enabled true       # default
vmux config set relay.bind auto          # auto | tailscale | local
vmux config set relay.port 4399
vmux config set relay.allow_localhost false
vmux config set relay.allow_paste true
vmux config set relay.allow_view_resize false

Running it by hand

vmux relay serve
vmux relay serve --listen 127.0.0.1:4400
vmux relay serve --allow-localhost --listen 127.0.0.1:4399
vmux relay status
vmux relay devices list
vmux relay devices revoke <device_id>

Pairing a phone

  1. Install Cmux Remote, or another client that speaks the same wire protocol.
  2. Run Tailscale on the phone and on the host, on the same tailnet.
  3. On the host, run vmux relay serve (or attach with relay.enabled).
  4. In the app, set host to your tailscale ip -4 address and the relay port.
  5. Pair, list workspaces, open a surface.
PORT=4399
curl -s http://$(tailscale ip -4):${PORT}/v1/health
# {"ok":true,"version":"…","backend":"vmux",…}

Phone-fit pane sizing

Off by default — a phone glancing at a pane must not resize it under whoever is at the desk.

vmux config set relay.allow_view_resize true

Once enabled, the PTY runs at min(desktop layout, phone view) per axis — tmux's "smallest client wins", scoped to the one pane being viewed. The lease re-signs on every poll cycle and expires ~10s after the phone vanishes, so the pane always returns to its desktop size by itself. The desktop attach UI dims the pane's unused margin with a "sized by phone" note while an override is active.

Pasting screenshots over SSH

Claude Code's Ctrl+V image paste reads the clipboard of the machine it runs on. When you SSH into a box running vmux, your screenshot is on your laptop — vmux bridges that two ways.

The paste page — nothing to install. With the relay running, open http://<host>:<port>/paste in any browser on your tailnet and press Cmd+V/Ctrl+V (or drop an image file). The relay saves the image on the host and types its path into the active pane. Works from a phone too, photo picker included.

vmux send-image — for the terminal, pipes image bytes over SSH:

# macOS (brew install pngpaste)
pngpaste - | ssh yourbox vmux send-image -

# Linux: wl-paste --type image/png (Wayland) or
#        xclip -selection clipboard -t image/png -o (X11)
ssh yourbox vmux send-image - < ~/Desktop/Screen*.png

For both, --pane pane-2 / ?pane=pane-2 targets a specific pane and --enter / ?enter=1 submits immediately. Uploads land in ~/Downloads/vmux-remote/, capped at 16 MiB.

Turn the paste page off entirely (/paste and /v1/paste then 404):

vmux config set relay.allow_paste false