// blog

← all posts

Exposing localhost in 2026 — the 5-minute guide

·5 min read·networking · developer-tools · guide

The "expose localhost" problem hasn't changed in a decade — you have a server on 127.0.0.1:3000 and something on the internet (a webhook provider, a mobile app, a stakeholder review) needs to reach it. What's changed is which option is easiest in 2026.

Option 1: a tunnel service (90% of cases)

The default. Run one command, get a public HTTPS URL. The agent on your laptop dials a long-lived TLS connection to the service; incoming requests travel it.

Picks:

  • lrok — reserved subdomain on the free plan, $9/mo flat for unlimited. Real Let's Encrypt certs, no interstitial warning, request inspector. (install)
  • ngrok — the original. Free tier is restrictive; paid plans are tiered.
  • Loophole — serious tunnel platform with multi-region edges; reserved subdomains are paid-only.
  • Expose — tight Laravel/artisan integration; the natural pick if your stack is PHP.
  • Cloudflare Tunnel — free, requires a domain on Cloudflare DNS. Setup is heavier; once configured, very stable.
  • localtunnel — free, no signup. URL rotates; not for webhooks.
  • bore — open-source Rust reverse-tunnel you self-host; no hosted service, but zero infrastructure cost if you already have a VPS.

Use a tunnel when you need: webhook testing, OAuth callbacks during dev, mobile-app real-device testing, sharing a preview with someone non-technical.

Option 2: port-forward + dynamic DNS (the dinosaur option)

Forward a port on your home router, register a dyndns hostname. You'll spend a Saturday on it; you'll get something that works only on your home network.

Use this when: you specifically need an L4 path with no L7 proxy in between, you're already running a server with public IP, and the dynamic DNS update lag is acceptable.

This isn't the path for "I want to test a Stripe webhook in 30 seconds."

Option 3: deploy to a preview environment

Vercel, Netlify, Render, Fly all have preview deploys triggered by a PR. Push the branch; you get a public URL.

Use this when: the iteration loop is slow enough that build time doesn't bother you, the testing is for stakeholders rather than yourself, and you don't need a server-side handler hitting your local DB.

It's the wrong tool for "I'm iterating on a webhook handler at 3-second cycle time."

Option 4: ssh -R reverse tunnel

If you have any server with a public IP and sshd running, you can:

$ ssh -R 8080:localhost:3000 user@your-server.com -N

Now your-server.com:8080 forwards to your laptop's :3000. Useful for one-off debugging where you already have ssh access. Pain points: the ssh server has to allow GatewayPorts, you're terminating TLS yourself if you need it, and there's no inspector.

What I'd pick in 2026

For most webhook / OAuth / mobile-testing work: a tunnel service. Specifically lrok if you want a reserved free-plan subdomain that survives restarts; Cloudflare Tunnel if you already live in Cloudflare and have a domain there; ngrok if you've already got a Pro subscription.

For preview deploys: keep them for PR review and prod-parity testing, not for the inner dev loop.

For ssh -R: it's a great trick to know but rarely the cleanest path.

The 30-second start with lrok

$ curl -fsSL https://lrok.io/install.sh | sh
$ lrok login
$ lrok http 3000
  Forwarding https://violet-mole.lrok.io  →  http://127.0.0.1:3000

That's it. Walkthroughs for specific stacks: Next.js, Django, Rails, Go, + 15 more.

// try it yourself

lrok is a hosted reverse-tunnel: one command, public HTTPS URL, reserved subdomain on the free plan. $9/mo flat for unlimited.