{"slug":"lan-mode-hand-your-app-to-a-phone","url":"https://tako.sh/blog/lan-mode-hand-your-app-to-a-phone/","canonical":"https://tako.sh/blog/lan-mode-hand-your-app-to-a-phone/","title":"LAN Mode: Hand Your App to a Phone in Three Seconds","date":"2026-04-13T06:33","description":"Press l in tako dev and your app is reachable from any phone or tablet on your Wi-Fi as myapp.local — real HTTPS, no ngrok, no port forwarding.","author":null,"image":"98ba3963a720","imageAlt":null,"headings":[{"depth":2,"slug":"what-happens-when-you-press-l","text":"What happens when you press l"},{"depth":2,"slug":"why-not-ngrok","text":"Why not ngrok?"},{"depth":2,"slug":"how-it-works-under-the-hood","text":"How it works under the hood"},{"depth":2,"slug":"try-it","text":"Try it"}],"markdown":"You're building a responsive layout. You want to see how it looks on your actual phone, not Chrome's device emulator. The usual options are all bad: type your laptop's IP and a port number into your phone's browser, fight with self-signed cert warnings, or fire up an ngrok tunnel that broadcasts your half-built app to the public internet just so it can come back to a device three feet away.\n\nThere's a better way. Press `l` in [`tako dev`](/docs/development).\n\n## What happens when you press `l`\n\nTako detects your LAN IP, binds the dev proxy to `0.0.0.0:443`, and publishes an mDNS record for every registered `.test` route as a matching `.local` hostname. Your phone — already a fluent mDNS client thanks to Bonjour — resolves `myapp.local` and connects over real HTTPS.\n\nIt also prints a QR code in your terminal pointing at `http://<lan-ip>/ca.pem`. Scan it on your phone, install the Tako development CA as a configuration profile, and the green padlock shows up on every `.local` hostname you serve, forever. One setup, every project.\n\n```bash\n$ tako dev\n  ✓ dev daemon running\n  ✓ routes ready\n\n  https://myapp.test/\n\n  l LAN mode · r restart · b background · ctrl+c stop\n\n# press l\n\n  ✓ LAN mode enabled\n\n  https://myapp.local/   ← reachable from any device on your Wi-Fi\n\n  ▄▄▄▄▄▄▄ ▄ ▄▄ ▄ ▄▄▄▄▄▄▄\n  █ ███ █ █▀▀█▄ █ ███ █     scan to trust the dev CA\n  █▄▄▄▄▄█ ▄▀█ ▄ █▄▄▄▄▄█     http://192.168.1.42/ca.pem\n```\n\nPress `l` again to turn it off. mDNS records vanish, the proxy goes back to loopback-only, and your laptop is no longer announcing anything to the network.\n\n## Why not ngrok?\n\nNgrok and similar tunnels solve a different problem — making your laptop reachable from the public internet. For real-device testing on the same Wi-Fi network, that's the wrong tool. You don't need a public URL, a third-party relay, or a rotating subdomain that breaks every OAuth callback you configure. You need your phone, three feet away, to talk to your laptop directly.\n\n| Approach              | Setup                             | URL on the phone           | HTTPS               | Public exposure |\n| --------------------- | --------------------------------- | -------------------------- | ------------------- | --------------- |\n| IP + port             | Find IP, type it, allow firewall  | `http://192.168.1.42:3000` | No                  | LAN only        |\n| ngrok / Cloudflare    | Account, daemon, auth token       | `https://abcd.ngrok.app`   | Yes                 | Public internet |\n| `mkcert` + manual DNS | Edit `/etc/hosts` on every device | `https://myapp.test`       | If you trust the CA | LAN only        |\n| **Tako LAN mode**     | Press `l`                         | `https://myapp.local`      | Yes (one-tap CA)    | LAN only        |\n\n## How it works under the hood\n\n```d2\ndirection: right\n\nphone: Phone {shape: rectangle; style.fill: \"#9BC4B6\"}\nmdns: mDNS / Bonjour {shape: circle; style.fill: \"#FFF9F4\"; style.stroke: \"#2F2A44\"}\nproxy: Tako Dev Proxy {style.fill: \"#E88783\"}\napp: Your App {shape: hexagon; style.fill: \"#FFF9F4\"; style.stroke: \"#2F2A44\"}\n\nphone -> mdns: \"who has myapp.local?\"\nmdns -> phone: \"192.168.1.42\"\nphone -> proxy: \"GET https://myapp.local/\"\nproxy -> app: routed by Host header\n```\n\nWhen you toggle LAN mode, the dev server spawns one mDNS publisher per registered route — `dns-sd` on macOS, `avahi-publish-address` on Linux. Each publisher advertises one concrete hostname. The dev proxy starts listening on `0.0.0.0:443` and routes by `Host` header, the same way [the production Tako proxy](/blog/pingora-vs-caddy-vs-traefik) does.\n\nOne footnote: mDNS only knows how to advertise concrete records, so wildcard routes like `*.app.test` don't translate. Tako warns you about this and suggests adding an explicit subdomain. Everything else — subpaths, multiple apps, multiple terminals — just works.\n\n## Try it\n\nIf you've got `tako` installed, you already have LAN mode. Run `tako dev` in any project, press `l`, scan the QR code on your phone, and open `https://<your-app>.local` in mobile Safari. Your responsive breakpoints, your touch targets, your iOS-only Safari quirks — all live, all over real HTTPS, all in about three seconds.\n\nNew here? `brew install takoserver/tap/tako` and check out the [development docs](/docs/development) or the [CLI reference](/docs/cli) for everything `tako dev` can do beyond this one keystroke."}