FeaturesGuidesBlogDocumentationFreeGet Started

Next.js Dev Server Through a Tunnel

Configure allowedDevOrigins for Next.js 15.2+ when accessing your dev server through a LocalToLink tunnel.

Why Next.js needs extra config with tunnels

Next.js dev server includes security checks that block requests from unexpected origins. When you access your app through a tunnel URL like https://k7m2x9p4q1.localtolink.com, the browser sends that hostname as the request origin — not localhost.

Starting with Next.js 15.2, the dev server validates origins and may block cross-origin requests or show errors when loading through a tunnel. You need to explicitly allow your tunnel domain.

This guide covers tunnel setup, allowedDevOrigins configuration, HMR over WebSocket, and a production-build fallback.

Prerequisites

Step 1: Start the tunnel

Terminal 1 — Next.js dev server:

npm run dev

Terminal 2 — LocalToLink:

npx localtolink --port 3000

Copy the public URL from the output, e.g. https://k7m2x9p4q1.localtolink.com.

Step 2: Configure allowedDevOrigins

Add your tunnel domain to next.config.js or next.config.ts:

/** @type {import('next').NextConfig} */
const nextConfig = {
  allowedDevOrigins: ["*.localtolink.com"],
};

export default nextConfig;

The wildcard covers all random subdomains LocalToLink assigns. You do not need to update this config when the subdomain changes.

Restart npm run dev after saving the config file. Next.js reads config at startup.

Step 3: Open through the tunnel URL

Navigate to the tunnel URL in your browser (not localhost:3000). On first visit, continue through any LocalToLink safety prompt if shown.

Your app should load with assets, API routes, and Fast Refresh working.

What allowedDevOrigins fixes

Without this setting, you may see:

The setting tells Next.js that requests from *.localtolink.com are trusted during development.

WebSocket / Fast Refresh (HMR)

Next.js Fast Refresh uses WebSockets for hot updates. LocalToLink supports WebSocket passthrough — no extra tunnel configuration needed.

Once allowedDevOrigins is set, HMR generally works through the tunnel. If hot reload fails:

  1. Check browser console for WebSocket errors
  2. Confirm you opened the app via the tunnel URL (not localhost)
  3. Try the production build fallback below

For mobile HMR testing, see Test Localhost on Your Phone.

Fallback: production build locally

If dev-server origin checks still cause issues, test through a production build. Production mode does not apply dev-only origin restrictions:

npm run build
npm run start
npx localtolink --port 3000

Trade-off: no Fast Refresh, but identical runtime behavior to deployed production.

Browser interstitial

When the visitor interstitial policy is enabled, browser access through the tunnel may show LocalToLink's one-time Opening a shared link page. Continue once per subdomain. Webhook and JSON API requests typically skip the page; only human browser navigations need the continue flow (or the localtolink-skip-browser-warning header in tests).

Environment variables and tunnel URLs

If your app uses NEXT_PUBLIC_* variables with hardcoded localhost URLs, update them for tunnel testing:

# .env.local — use relative paths when possible
NEXT_PUBLIC_API_URL=/api

Relative URLs work regardless of whether you access via localhost or tunnel.

Session notes

LimitImpact
2-hour sessionRestart tunnel for long dev sessions
Random subdomain*.localtolink.com wildcard covers all subdomains
Custom subdomainsNot available on the free tier yet
1 tunnel per IPStop other tunnels before starting

Troubleshooting

IssueFix
Cross-origin blockedAdd allowedDevOrigins; restart dev server
HMR not connectingOpen app via tunnel URL; check WebSocket in DevTools
Assets 404Confirm tunnel points to correct port (--port 3000)
Works on localhost, not tunnelExpected without allowedDevOrigins — add config
Interstitial on every navigationNew subdomain — click through once; cookie lasts 24h
API routes timeoutCheck handler logs; tunnel session may have expired

Testing OAuth through Next.js

Register the tunnel URL as your OAuth callback:

https://SUBDOMAIN.localtolink.com/api/auth/callback

See OAuth Callback on Localhost for provider-specific steps.

Middleware and tunnel origins

If you use Next.js middleware that checks request.nextUrl.hostname, ensure it accepts tunnel hostnames during development:

const host = request.nextUrl.hostname;
const isDev = process.env.NODE_ENV === "development";
const isTunnel = host.endsWith(".localtolink.com");
// Allow tunnel origins in dev

Hardcoded localhost checks in middleware can block requests when accessed through the tunnel URL.

FAQ

Does this work with Next.js App Router and Pages Router?
Yes. allowedDevOrigins applies to the dev server regardless of routing model.

Do I need this for Vercel preview deployments?
No. This is for local development through a tunnel only.

What about Next.js 14 and earlier?
Origin checks were less strict. Upgrade to 15.2+ or use the production build fallback.

See also Vite HMR Through a Tunnel for Vite-specific configuration and Expose Localhost to the Internet for tunnel basics.

Try it now

Start a tunnel from your project directory — no account required.

$ npx --yes localtolink@latest

See the full CLI reference for flags and exit codes.

LocalToLink CLI 1.0.1 — verified 2026-09-05