Like ngrok, except the tunnel never leaves your tailnet.
Live demo. Click Run to load the real app and use it right here, or open it full-screen.
Localhost Mirror exposes a port running on your machine to your other devices, and only your other devices. It rides on Tailscale, so a dev server on your laptop becomes reachable from your phone, tablet, or another Mac, but never from the public internet. Run `lm expose 3000` and you get a private URL the rest of your tailnet can open.
It ships as two halves that share one background daemon: a terminal CLI for people who live in the shell, and a native macOS menu-bar app that scans every port your machine is listening on, recognizes what is running there (Next.js, Vite, Postgres, Ollama, and dozens more), names the owning project, and exposes any of them from the menu bar. A single-file dashboard, optional per-tunnel tokens, health checks, and a daemon that puts itself to sleep round it out.
Sharing a local dev server usually means a public tunnel that hands a URL to the entire internet and often wants an account. Localhost Mirror keeps the one-command convenience but scopes access to devices you already own, so the QR-code-on-your-phone workflow never exposes a half-built app to strangers.
lmcliTerminal CLI (the `lm` bin) whose expose, list, stop, status, dashboard, and shutdown commands drive the daemon over its localhost management API on 127.0.0.1:19099.
LocalhostMirrorappSwiftUI macOS menu-bar app (a MenuBarExtra, LSUIElement) that lists every listening port and lets you expose, stop, copy the tailnet URL, or kill any of them, polling the daemon every three seconds.
daemonserviceBackground service running a localhost-only management API on :19099 plus a tailnet-facing proxy and dashboard server on :19100, auto-starting on the first expose and shutting itself down 60 seconds after the last tunnel closes unless run with --persistent.
apilibraryRequest router that maps an lm_tunnel cookie or a /name path to a per-port http-proxy instance (one cached per target port), forwards WebSocket upgrades, gates optional per-tunnel nanoid tokens, and serves the tunnel CRUD REST API.
PortScannerlibrarySwift scan engine that lists TCP listeners with lsof every three seconds, reads per-process CPU, RAM, and zombie state from ps, finds the owning project by walking up for package.json, Cargo.toml, go.mod, or .git, and raises alerts for CPU over 80 percent, RAM over 500MB, or a process that died.
CommonPortslibraryLookup table that labels and colors a detected port from 87 known dev ports (Next.js, Vite, Postgres, Redis, Ollama, and more) plus 28 process-name heuristics.
dashboardappSingle-file dark web dashboard (index.html served at /lm/) that the daemon serves over the tailnet to list, expose, and stop tunnels from the browser.