Get Moshi
preview

Browser preview

Open any HTTP server running on your host in the in-app browser, forwarded over SSH. No public tunnel, no port-juggling.

updated 1 week ago26 min readpage 25 / 32

When an agent spins up a dev server — next dev, vite, a Python runserver, a Storybook — you usually want to look at it. Browser preview turns any HTTP server moshi-hook can see on the host into a single tap from the terminal, without exposing the port to the internet.

What it is

moshi-hook watches local TCP listeners on the host and asks each one whether it speaks HTTP. The Moshi app reaches them through a per-session SSH local-forward, so the in-app browser loads the server over an authenticated, host-bound tunnel. Nothing leaves the host except encrypted SSH traffic on the same connection you're already using for the terminal.

This avoids the usual workarounds: no ngrok, no cloudflared, no public ingress, no manual -L flags.

Requirements

  • moshi-hook installed and running on the host. See Hooks.
  • An SSH-capable session to the host. Mosh sessions are fine — they bootstrap over SSH and the same channel is reused for the forward.
  • A Pro subscription — browser preview and the diff viewer together form the host gateway, which is gated on Pro.

Auto-detection

moshi-hook periodically probes local listeners and remembers which ones respond with an HTTP header. Each detected server carries:

  • A name (process command, e.g. node, python, vite).
  • The PID and port.
  • The bind address (so a server on 127.0.0.1 is distinguished from one on 0.0.0.0).

When at least one server is detected, the terminal title shows an indigo button on the right. Tap it to open the picker.

muted dot
No HTTP servers detected on the host, or the SSH forward channel is not active yet.
indigo dot
One or more HTTP servers detected — tap to pick one.

If the button is missing entirely, browser preview is turned off in Settings → Hooks. Turn "Use preview" back on to bring it back.

Open a server

Tap the indigo button. If a single server is running, the picker still opens so you can confirm it before forwarding. Each row shows:

  • The server name and the PID.
  • The host:port the server is listening on.
  • A short label when moshi-hook recognizes the framework (e.g. "vite", "next", "storybook").

Pick one and Moshi opens it in the in-app browser. The page is a regular browser view — links, refresh, devtools-style scroll all work as you'd expect.

Same-port vs random local port

When you open a server, Moshi tries to bind the matching port locally first (e.g. host :5173 → local :5173), so the URL in the address bar mirrors what you would type on a desktop. If that port is already in use on the device, it falls back to a random free local port and the URL shifts to that one. Either way, only 127.0.0.1 on the device is involved — nothing is reachable from your LAN.

Privacy

  • The forward exists only for the active terminal session. Closing the session tears the tunnel down.
  • The forward binds locally on the device, not on the host's public interfaces. Other machines on your network or the internet cannot reach the server through Moshi.
  • moshi-hook discovery never publishes the server list to Moshi's backend. The picker reads it through the same authenticated host gateway used by the diff viewer.

Troubleshooting

  • Button is hidden. Turn on Settings → Hooks → Use preview, then return to the terminal.
  • Button is muted with "no servers detected". moshi-hook has not yet found an HTTP listener. Start your dev server (bun dev, vite, etc.) and retry — the next discovery sweep picks it up within a few seconds.
  • "Preview unavailable" with "no session". The SSH bootstrap for the current session has not finished. Wait a moment or reconnect.
  • Wrong server opens. If two processes share a port across interfaces (e.g. one on 127.0.0.1 and another on 0.0.0.0), pick the one with the bind address you want from the sheet.
  • Forward fails on the matching local port. Another app on your device is using that port. Moshi falls back to a random port and reports the new URL — there is nothing to do besides note the address.