Blog
How localhost tunnels work
Your laptop already has a web server running on it. Nobody else can open it not because the server is broken, but because the internet is built so a stranger can't dial into your machine uninvited, and a tunnel is a deliberate way around that.
A laptop on home Wi-Fi or behind a company firewall has no address the internet can dial into: NAT and default-deny firewall rules mean connections your machine starts are allowed out, but nothing unsolicited gets in. A tunnel flips the direction. Your machine opens an outbound connection to a relay it trusts, and the relay forwards inbound requests back down that same connection to your local server. ssh -R does this with a single flag. Hosted services like ngrok and Cloudflare Tunnel run the identical trick at larger scale, adding a public hostname and terminating TLS at their own edge before relaying traffic to your machine.
Why a laptop can't just be reached from the internet
Most machines, including every laptop on home Wi-Fi, a coffee shop network, or behind a company firewall, sit behind NAT, the router technique that lets many devices share one public IP address. The router keeps a table of which outbound connection belongs to which device and routes replies back accordingly, but nothing maps an unsolicited inbound connection to your laptop specifically, because none was requested.
Firewalls add a second, deliberate wall on top of that. The default posture on almost every home router and every reasonable company network is to allow outbound connections and refuse inbound ones nobody asked for. Both mechanisms exist on purpose, your laptop should not be independently reachable by anyone who finds its address, and together they mean a dev server on localhost:3000 is invisible to anything outside your own network.
The idea behind a reverse tunnel
An ordinary connection is your machine asking a server for something. A reverse tunnel inverts that: your machine makes the first move, opening an outbound connection to a relay you trust and leaving it open. Because the connection is outbound, it passes through NAT and the firewall the same way any ordinary web request does, with nothing to configure on either box.
The relay now has a live channel back to your machine. When someone makes a request to an address the relay owns, instead of answering it directly, the relay forwards that request down the open connection, your machine answers it, and the response travels back the same way. Nothing had to be opened on your side; the hole in the wall is the connection you made yourself.
ssh -R: the original version of this trick
SSH has done this since long before "tunnel" was a product category. The -R flag on the ssh client requests remote port forwarding: per OpenSSH's own manual, it specifies that connections to a given TCP port on the remote, server, host are to be forwarded to the local side. Run ssh -R 8080:localhost:3000 [email protected] and a connection to port 8080 on yourserver.example gets routed, through the SSH connection you opened outbound, to port 3000 on your laptop.
Whether anyone besides that server can actually reach port 8080 is a separate decision the server owner makes. OpenSSH defaults to binding a forwarded remote port to the loopback interface only, controlled by GatewayPorts in sshd_config, which the manual describes as specifying whether remote hosts are allowed to connect to ports forwarded for the client. Left at its default of no, your forwarded port answers only the server itself; someone has to deliberately set GatewayPorts yes, or clientspecified, before the rest of the internet can reach it too.
How ngrok and Cloudflare Tunnel do the same thing at scale
Hosted tunnel services automate this exact pattern and add a stable public hostname on top. ngrok describes its own mechanism plainly: its agent makes an outbound connection out to ngrok's cloud edge, and instead of the internet pushing traffic to your machine, you maintain a connection to that edge and ngrok pushes inbound requests back through it.
Cloudflare Tunnel works the same way from a different vendor. Its cloudflared daemon initiates an outbound connection through your firewall from your machine to Cloudflare's network, and once that connection exists, traffic flows in both directions over it, which is why Cloudflare's own guidance is to block all inbound traffic at your firewall and rely on the outbound tunnel alone. Neither service does anything SSH doesn't already do; they do it with a managed relay, a stable hostname, and no server of your own to run.
Where TLS actually terminates
For both ngrok and Cloudflare Tunnel, the HTTPS certificate a visitor's browser checks belongs to the vendor's edge, not to your laptop. The encrypted connection from the browser ends at that edge; from there to your machine, the request travels over the tunnel connection you already opened.
That is the same model a CDN uses and isn't a flaw specific to tunnels, but it does mean the vendor's edge is a point that sees your traffic unencrypted before relaying it onward, which is worth knowing if what you're tunneling is sensitive rather than a page you're happy to show anyone.
The question that actually decides whether a tunnel is safe: who can open the URL
A hostname being reachable from anywhere is not the same as its contents being open to anyone, and this is the detail that gets skipped. By default, a free ngrok URL is public: ngrok's own pricing page lists an interstitial page on HTTP and HTTPS endpoints for the free tier, a warning screen shown to visitors before your app loads, precisely because the address itself carries no access control. Paid tiers can add OAuth, basic auth, or IP restrictions in front of an endpoint through ngrok's traffic policy system, but none of that is on by default.
Cloudflare Tunnel is the same shape underneath. A tunnel's public hostname resolves like any other DNS name, and restricting who can open it is a separate step: adding a Cloudflare Access policy, which Cloudflare's own docs describe as deny by default once configured, determining who can reach your application. Until you add one, the hostname is exactly as open as the URL you hand out.
Neither kind of gate, an interstitial page or an Access policy, changes what a general tunnel is for: letting anything with the address in, including another machine. That is a feature rather than a flaw when the thing dialing in is a webhook from Stripe or GitHub, which cannot sign in to anything and needs exactly that kind of open door.
How this works in Forkbench
Forkbench's version of this is called Live Link, and it answers a narrower question than a general tunnel does: not "how do I let anything reach my machine" but "how do I let one person look at what's running on it." Point Live Link at the port your dev server is on and Forkbench hands back an HTTPS address on its own hostname, the same reverse-tunnel mechanism described above, your machine making the outbound connection and every response traveling back the same way.
The access control isn't optional or bolted on afterward. Every visitor has to be signed in to Forkbench and be an active member of the Thread the link came from, checked before the request ever reaches your machine. Every plan includes it, free too; the plan sets how many links you can have open at once and how long each one lives. Inviting someone to look costs nothing, since participating in someone else's Thread is free.
The honest limit, stated the same way a webhook limit gets stated for any tunnel: a machine cannot sign in, so a Live Link cannot receive a webhook from Stripe or GitHub, and that is by design rather than an oversight. For that you still want a general tunnel like ngrok or Cloudflare Tunnel. Live Link is for showing a running app to a named person, not for wiring up a machine caller, and it isn't trying to be the other kind of tool.
Related: How Live Link works, and what each plan gets, Show someone a dev server without deploying it, Forkbench as an ngrok alternative
Frequently asked
Why can't someone just connect to my laptop's IP address directly?
Because your laptop almost certainly doesn't have one the internet can use. Home routers and most company networks put devices behind NAT, sharing one public address among many machines, and firewalls default to allowing outbound connections while refusing unsolicited inbound ones. Both exist on purpose, so nothing reaches
localhost:3000on your machine unless you open a path yourself, which is what a tunnel does.What does ssh -R actually do?
It asks the SSH server you're connecting to, to forward connections made to a port on itself back down the tunnel to a port on your machine. Per OpenSSH's manual,
-Rspecifies that connections to the given TCP port on the remote host are to be forwarded to the local side. Whether anyone besides that server can reach the forwarded port depends on itsGatewayPortssetting, which defaults to no.Is an ngrok URL public?
By default, yes: anyone with the address can open it, which is why ngrok's free tier shows visitors an interstitial warning page before your app loads, since the hostname itself carries no login requirement. Paid plans can add OAuth, basic auth, or IP restrictions in front of an endpoint, but that protection has to be configured; it is not the default state of a tunnel.
Can a webhook use a localhost tunnel?
A general tunnel like ngrok or Cloudflare Tunnel, yes, that's exactly what they're for: anything with the URL, including a machine, can reach the service behind it. A membership-gated link like Forkbench's Live Link cannot, because every visitor has to sign in, and a webhook from Stripe or GitHub has no way to do that, so webhook testing needs a general tunnel instead.
Does Cloudflare Tunnel expose my home server's real IP address?
No, that's most of the point.
cloudflaredmakes an outbound-only connection from your machine to Cloudflare's network, and Cloudflare's own guidance is to block inbound traffic at your firewall entirely and rely on that connection alone, so there's no port on your router pointing at your server for anyone to find or scan in the first place.
Keep reading
Sources
- OpenSSH ssh(1) manual: the -R remote port forwarding flag
- OpenSSH sshd_config(5) manual: the GatewayPorts directive
- ngrok: how the agent's outbound connection to ngrok's network works
- ngrok pricing: the free-tier interstitial page and plan limits
- Cloudflare Tunnel: how cloudflared's outbound connection works
- Cloudflare Access: policies that decide who can reach an application