Why Hot Reload Breaks Over a Tunnel — and What Actually Fixes It

Quick answer
The End of CLI Tunnels: Browser-Native Localhost Sharing : localhost tunnel answer
A localhost tunnel gives your local app a public HTTPS URL without opening router ports, which is useful for demos, QA, mobile testing, and provider callbacks.
How do I expose localhost without opening ports?
Use a reverse HTTPS tunnel. Your machine connects outbound to the tunnel service, and the public URL forwards requests back to your local app.
When should I use a localhost tunnel?
Use one for webhook testing, OAuth callbacks, client demos, QA previews, mobile device checks, and short-lived development reviews.
Vite and Next.js don’t refresh your browser tab when you save a file. They push the changed module over a persistent WebSocket connection and patch it into the running page. It’s fast, and it’s also the reason sharing a local dev server with a client, a phone, or a webhook provider is more fragile than it looks.
Most general-purpose tunnels handle plain HTTP requests fine and mishandle the WebSocket upgrade handshake that HMR depends on. This piece looks at why that happens, what a tunnel actually needs to do differently, and where two current tools — one open-source, one bundled into a broader AI-agent dev tool — fit into the picture.
Why the failure is specifically a WebSocket problem
A WebSocket starts life as an ordinary HTTP request carrying Upgrade: websocket and Connection: Upgrade headers. The server (or anything proxying for it) is supposed to recognize that handshake and switch the connection from request/response into a raw, long-lived, bidirectional byte stream. A tunnel that doesn’t explicitly account for this can strip those headers, or time the connection out because it looks like a request that’s been hanging too long.
Two concrete places this shows up:
Vite. When a reverse proxy (or tunnel) in front of Vite doesn’t proxy WebSocket traffic correctly, the Vite client falls back to connecting its HMR socket directly to the dev server, bypassing the proxy — and logs a console warning to that effect. Vite’s own docs note this fallback error can usually be ignored on a normal local network, because the direct connection still succeeds. The catch: over a public tunnel, “direct” isn’t reachable from outside your machine, so the fallback fails too, and HMR breaks. Vite documents fixes for this: configuring the reverse proxy to pass WebSocket traffic through, or setting server.ws (clientPort, port) so the client and server agree on how to reach the socket.
Next.js. Since version 12, Next.js runs Fast Refresh over a WebSocket at /_next/webpack-hmr instead of the older server-sent-events mechanism. A misconfigured proxy sitting between the browser and the dev server is a common cause of “WebSocket is closed before the connection is established” errors reported against custom Next.js server setups — the fix is making sure whatever sits in front of the dev server passes WebSocket upgrades through untouched.
Neither of these is unique to any one tunnel vendor; they’re properties of how Vite and Next.js implement HMR, and any tool sitting in the middle has to actively handle them.
What a “framework-aware” tunnel needs to get right
- Recognize the upgrade handshake and switch to raw TCP passthrough instead of treating the connection as a stalled HTTP request.
- Keep the connection alive with periodic ping/pong frames, since idle long-lived connections are exactly what intermediate firewalls and load balancers tend to kill.
- Not mangle Host/Origin headers, since dev servers increasingly do their own origin checks for security reasons, and a tunnel that rewrites these incorrectly can get requests rejected by the dev server itself before they ever reach your code.
Two tools actually doing this today
OutRay — open-source, self-hostable
OutRay is a real, actively maintained open-source project (AGPL-3.0, ~1k GitHub stars as of writing) positioned as an ngrok alternative. It supports HTTP, TCP, and UDP tunnels from a CLI (outray http 3000, outray tcp 5432), custom domains, a dashboard with traffic analytics, and framework integrations.
Its Express integration is clearly documented as an actual npm middleware package (@outray/express) — you import it, wrap your app, and it prints a tunnel URL alongside your normal server log line. OutRay’s docs also list Next.js, Vite, and NestJS plugins, though I couldn’t independently verify the specific claim (repeated in some marketing copy) that the Next.js plugin edits next.config.ts for you with literally no CLI step — treat that particular detail as unconfirmed until you’ve tried it yourself. The core value proposition that is well-documented: it’s open source, so you can inspect or self-host the whole stack rather than trusting a third party with your traffic.
AgentsRoom — a tunnel bundled inside a bigger tool, not a standalone product
The original draft framed this as a dedicated “browser-native” tunnel product. That’s a mischaracterization worth correcting: AgentsRoom is a native desktop app (Mac/Linux/Windows) for orchestrating multiple AI coding agents — Claude Code, Codex, Antigravity CLI, and others — with a task board, per-project terminals, an in-app browser-automation QA agent, and an iOS/Android companion app. The localhost tunnel is one feature among several, not the product itself, and nothing about it runs “in the browser” — it’s a native-app feature you start from a desktop dashboard or the mobile app.
What the tunnel feature does, per AgentsRoom’s own documentation: it scans your open local ports, lets you pick a custom subdomain, and proxies HTTP/WebSocket traffic to your Next.js, Vite, Expo Metro, or other dev server with a claimed sub-2-second startup. It ships a 25-second heartbeat with up to five automatic reconnect attempts, and shows a styled offline page to visitors when the tunnel is stopped rather than a raw connection error. The mobile app can start a tunnel remotely so you can preview a site from your phone without touching the machine running it.
Two things worth knowing before treating it as a general tunnel solution: it’s built by a single independent developer (per its App Store listing), not a company with a dedicated networking product, and its own pricing page caps the free tier at three projects — so “zero cost” only holds if your usage stays under that ceiling.
Where ngrok actually stands, since it’s the usual comparison point
The bandwidth-throttling and “ephemeral URL” criticisms leveled at ngrok in tunnel-comparison content are generally fair: ngrok’s current published pricing limits the free tier to 1 GB of data transfer and 20,000 HTTP requests per month, capped at three online endpoints, with one auto-assigned (non-custom) domain and an interstitial browser warning page on free HTTP endpoints (that page can be bypassed with a request header, without upgrading).
One claim that circulates constantly in this genre of article, though, doesn’t hold up: ngrok’s free tier does not enforce a hard session timeout. Ngrok’s own documentation states explicitly that free-tier endpoints have no timeout and can run indefinitely as a background service — the real constraints are the monthly data/request caps above, not a forced disconnect after some fixed number of hours. If you see the “2-hour free session” claim elsewhere, it’s worth checking the source against ngrok’s own docs before repeating it.
Practical takeaway
If you’re already on Vite or Next.js and seeing the WebSocket fallback warning, it’s worth trying the config-level fix first — server.ws in Vite, or making sure whatever proxy sits in front of your Next.js dev server passes Upgrade headers through — before reaching for a new tool. If you need a public HTTPS URL regularly for webhook development or mobile QA, a tunnel that’s explicitly built to handle WebSocket upgrades saves that config work. And if you’re choosing between options, it’s worth distinguishing genuinely open-source, self-hostable tools like OutRay from a tunnel that’s a convenience feature bundled inside a much larger (and, in AgentsRoom’s case, single-developer) product — the trust and maintenance model is different in each case.
Changelog
Rewritten from a submitted draft and fact-checked against primary sources on July 28, 2026.
- Removed SEO scaffolding: cut the repeated keyword phrases (“Next.js tunnel no CLI,” “zero deploy preview,” “zero-context-switching”) used purely for search-engine targeting, and restructured around the actual technical claims.
- Corrected AgentsRoom’s framing: original draft called it a “browser-native localhost sharing” tool; it is a native desktop app for multi-agent AI coding orchestration with a bundled tunnel feature, not a dedicated tunnel product and not something that runs in-browser. Noted it’s built by a single independent developer and that its free tier is capped at 3 projects, not unconditionally free. Source: agentsroom.dev feature and pricing pages, and its App Store listing.
- Softened an unverified OutRay claim: could not confirm the specific claim that OutRay’s Next.js plugin automatically edits
next.config.tswith zero CLI involvement. Confirmed instead, via OutRay’s own npm package page, that its Express integration is a standard middleware import — used that as the verified reference point and flagged the Next.js-specific mechanic as unconfirmed. Source: npmjs.com/package/@outray/express, outray.dev docs. - Corrected the Vite WebSocket fallback explanation: the original draft implied the “Direct websocket connection fallback” message is always a hard failure. Vite’s own docs note the fallback error can typically be ignored on a local network since the direct connection still succeeds; it only becomes a real failure when the client can’t reach the dev server directly, as is the case over a tunnel. Source: vite.dev/config/server-options.
- Confirmed the Next.js HMR detail: Next.js has used a WebSocket connection at
/_next/webpack-hmrfor Fast Refresh since v12 (replacing an earlier SSE-based mechanism), and misconfigured proxies are a documented cause of HMR WebSocket failures. - Corrected ngrok’s free-tier limits and added a myth-check: verified current numbers directly against ngrok’s own pricing/limits documentation (1 GB/month, 20,000 requests/month, 3 online endpoints, one auto-assigned domain, bypassable interstitial page) and explicitly flagged the commonly repeated “2-hour free-tier session timeout” as false — ngrok’s docs state free endpoints have no timeout and can run as a background service indefinitely. Source: ngrok.com/docs/pricing-limits/free-plan-limits.
- General tone: rewrote promotional language into a neutral technical explainer; no factual claims were retained from the original draft without a check against a primary source (framework docs, vendor docs, or official pricing pages).
Related InstaTunnel pages
Continue from this article into the most relevant product guides and workflows.
Related Topics
Keep building with InstaTunnel
Read the docs for implementation details or compare plans before you ship.