A service listening on localhost — a Vite dev server on localhost:5173, an API on localhost:3000 — is only reachable from the computer that runs it. To open it from your phone you have three options: connect over the same Wi-Fi using your computer's LAN address, expose the port through a tunnel such as ngrok, or use a remote access tool like CLIAnywhere, which opens localhost and LAN pages through its existing connection to your PC. The right choice depends on where your phone is and whether the page may be exposed publicly.
Short Answer
On the same Wi-Fi, the quickest route is the LAN IP: make the server listen on all interfaces, look up your computer's 192.168.x.x address, and open http://192.168.x.x:5173 in the phone's browser. Away from that network the LAN IP stops working, so you either run a tunnel — which hands out a public URL to your dev server — or use CLIAnywhere, whose phone clients can open localhost and LAN pages on your PC from any network without exposing the port to the internet.
Why This Is Difficult
localhost (127.0.0.1) is a loopback address: the operating system loops traffic straight back to the machine itself. A request to localhost:5173 from your phone asks for port 5173 on the phone, not on your computer. The name simply does not cross devices.
The obvious fix is the computer's LAN address — but most dev servers only bind to loopback by default, so even a request to the right IP is refused until you change the bind address. And the LAN address only works while the phone is on the same network. Leave the house, switch to cellular, or sit in an office with client isolation enabled on the Wi-Fi, and the address becomes unreachable.
Finally, your computer has no public address of its own: it sits behind NAT, and many home connections are behind carrier-grade NAT on top. There is no inbound path from the internet to localhost unless you deliberately create one — which is exactly what tunnels and remote access tools do, each with different trade-offs.
Common Solutions
Option 1: Same Wi-Fi, LAN IP
Make the server listen on the network instead of loopback — Vite: npm run dev -- --host, Next.js: next dev -H 0.0.0.0, plain Node: listen on 0.0.0.0. Then find the computer's LAN IP with ipconfig (Windows) or ip a / ifconfig (macOS, Linux), and open http://192.168.1.42:5173 in the phone's browser.
This is the standard approach and costs nothing. Its limits: it only works while the phone is on the same network; the first connection usually triggers a firewall prompt on the computer; and on many guest, hotel or office Wi-Fi networks, client isolation blocks phone-to-PC traffic entirely.
Best for: quick mobile testing at your own deskOption 2: A Tunnel (ngrok, cloudflared)
Tunnels give your local port a public URL. With ngrok: ngrok http 5173 prints a URL like https://a1b2.ngrok.app that anyone can open — including your phone from any network. Cloudflare's cloudflared does the same and is popular for longer-lived tunnels.
The trade-off is exposure: the URL is a public entrance to a dev server that was written assuming only you would reach it. Free tiers rotate URLs between runs, an extra process has to keep running, and some networks you visit will block tunnel traffic. Tunnels also cover a single host and port, so a second service means a second tunnel.
Best for: sharing a local server with other peopleOption 3: CLIAnywhere
CLIAnywhere takes a different route: instead of making your port public, the phone talks through the connection it already has to your PC's daemon. The localhost and LAN web access feature lets you open pages served on localhost — or on any device in your PC's local network, such as a router page or NAS panel — from the iOS, Android or web client.
Nothing is bound to 0.0.0.0, no port is forwarded, and no public URL exists. It works identically on your own Wi-Fi and on cellular across the country, and the same app gives you the terminal session of the PC running the dev server, which is usually where the logs are.
Using CLIAnywhere
Install the Client and the Daemon
Install the mobile app — Android on Google Play, iOS on the App Store (see the download page), or use the Web App in any browser. On the PC that runs your dev servers, install the open-source daemon from GitHub Releases — the full, tabbed build instructions are in the setup guide.
Link the App to Your PC
Create an access key in the app and link it to the daemon — paste the key into the daemon, or scan the daemon's QR code with the app. The key is used only for the local SPAKE2 key exchange and never leaves your devices. Your PC then appears in the app's device list.
Open the Local Page
Start your dev server on the PC exactly as you always do — npm run dev binding to localhost:5173 is fine, no --host flag needed. On the phone, open the web access view from the PC's session, enter the local URL (http://localhost:5173, http://localhost:3000, or a LAN address like http://192.168.1.1), and the page loads on your phone. Hot reload keeps working, because the phone reaches the dev server through your PC.
| Localhost web access from phone | Yes |
|---|---|
| LAN web app access (router, NAS, other devices) | Yes |
| Works from any network (not just same Wi-Fi) | Yes |
| Dev server must bind to 0.0.0.0 | No — localhost binding is fine |
| Windows / macOS / Linux host | Yes |
| iOS / Android / Web client | Yes — see the download page |
| Terminal session for the same PC | Yes, persistent across disconnects |
| Port forwarding / public URL required | No |
| Encryption | SPAKE2 key exchange + AES-256-GCM, P2P (DTLS) with encrypted relay (WSS) fallback |
| Open-source daemon | Yes — github.com/CLIAnywhere/clianywhere_daemon |
Example: A React App on Vite, localhost:5173
You are building a React app with Vite. At your desk, npm run dev starts the dev server on localhost:5173 and you work as usual. The layout needs a real-phone check — not the browser's device emulator.
You pick up your phone, open CLIAnywhere, tap your PC, and open the web access view. You enter http://localhost:5173; the app loads full-screen on the phone. You edit a component on the PC, and the page hot-reloads on the phone as if the server were local — because from the phone's point of view, it is.
The same flow covers the rest of the stack: the Node API on localhost:3000 that the React app calls, a Django runserver on localhost:8000, and — because LAN addresses work too — the router management page at 192.168.1.1 and your NAS panel, all reachable from the phone without opening any of them to the internet. None of it required a --host flag, a firewall exception, or a tunnel URL.
Security
Exposing a dev server is the step that usually goes wrong: tunnels create a public URL, and dev servers are not written to face the internet. CLIAnywhere keeps the port private — the phone reaches localhost through an end-to-end encrypted connection (SPAKE2 key exchange, AES-256-GCM), peer-to-peer over DTLS where possible, and the relay only sees ciphertext. See how CLIAnywhere handles security for details.