How to Expose localhost to the Internet (HTTPS in One Command)
A practical guide to exposing a local port to the internet: how tunnels work, a one-command HTTPS setup with inrok, the SSH fallback, and the security basics to get right.
You're running something on localhost:3000 and someone who isn't you needs to reach it: a webhook from Stripe or GitHub, a client who wants to click through a work-in-progress, your phone testing a mobile layout, a friend joining your game server. localhost only exists on your machine — here's how to give it a real URL, safely.
Why you can't just share your IP
Two things stand between your laptop and the internet:
- NAT and firewalls — your router doesn't forward unsolicited traffic to your machine unless you configure port forwarding, and on many ISPs you can't.
- CGNAT — increasingly, your "public" IP is shared with hundreds of other customers (common on Jio, Airtel, T-Mobile Home Internet, Starlink, and most mobile connections). There is no port to forward; inbound connections are simply impossible.
A tunnel sidesteps both: a small client on your machine opens an outbound connection to a relay server with a real public address, and visitors reach you back through that connection. Outbound connections are allowed pretty much everywhere, so this works behind NAT, CGNAT, hotel Wi-Fi, and office networks.
The one-command version
With inrok (our service — free while in beta, no card needed):
curl -fsSL https://inrok.in/install.sh | bash
inrok login
inrok http 3000
That prints a public HTTPS URL pointed at your local port 3000. TLS is handled at the edge — your visitor sees a padlock, you change nothing in your app.
Want a URL that survives restarts? Name it:
inrok http 3000 --name demo
# → https://demo.share.inrok.in — yours across reboots and network drops
Raw TCP and UDP endpoints are coming soon. The free beta includes 100 GiB of bandwidth a month and 3 simultaneous tunnels; on Windows, use install.ps1 instead.
The zero-install version
If you can't (or don't want to) install anything, SSH can do it alone:
ssh -R 80:localhost:3000 localhost.run
This prints a temporary public URL proxied over SSH. The URL changes every session and bandwidth is best-effort, but for a five-minute demo it's unbeatable. Our comparison of tunneling options covers more alternatives, including self-hosted ones.
Security basics — read before you share
A tunnel makes your service public. Five rules of thumb:
- Expose the app, not the box. Tunnel a single port to the specific service you mean to share — never a remote-desktop or SSH port "just to have it".
- Auth must live in the app. If the dashboard you're sharing has no login, anyone with the URL has full access. Add auth (or at least basic auth in a reverse proxy) before tunneling.
- Treat the URL as semi-secret. Unguessable URLs are not access control, but don't post one in a public channel unless you mean the whole world.
- Watch what webhooks can do. A webhook endpoint that mutates state should verify signatures (Stripe, GitHub, and friends all sign their payloads).
- Tear it down when you're done.
inrok stop(or Ctrl-C) closes the tunnel. A demo tunnel left up for three weeks is an attack surface, not a convenience.
When a tunnel is the wrong tool
If you're deploying something for real users 24/7, a proper host (a VPS, a PaaS, or your homelab with real DNS) is the right home for it — tunnels shine for development, demos, webhooks, and personal self-hosted services. For that last category — say, streaming your Jellyfin library from home — a persistent tunnel is arguably the best tool, CGNAT or not.
Ready to try? Create a free account — the whole flow above takes about two minutes.