Einen Vite-Dev-Server zu tunneln funktioniert gut – außer bei zwei Dingen, die dich beim ersten Mal stolpern lassen. Die Seite lädt, aber HMR nicht. Oder die Seite lädt gar nicht, weil Vite deinen Tunnel-Hostnamen ablehnt. Beides sind Config-Einzeiler, sobald du weißt, wo du suchen musst.
Problem 1: „Blocked request. This host is not allowed.“
Vite 5+ hat standardmäßig einen Host-Check-Schutz eingeführt. Wenn du deine Tunnel-URL öffnest und Blocked request. This host is not allowed siehst, lehnt dieser Check deinen *.portpreview.dev-Hostnamen ab.
Fix in vite.config.ts:
export default defineConfig({
server: {
host: true, // listen on 0.0.0.0
allowedHosts: ['.portpreview.dev'], // accept any subdomain
},
});
Der führende Punkt macht daraus eine Suffix-Übereinstimmung. Du kannst dort deinen spezifischen Tunnel-Hostnamen eintragen, wenn du strikt sein willst, aber für die tägliche Entwicklung ist das Suffix bequem – Tunnel-Session-URLs rotieren.
Problem 2: HMR lädt, stirbt dann still
HMR läuft über WebSocket. Wenn Vite unter localhost:5173 ausliefert, dein Browser aber von https://abc123.portpreview.dev lädt, versucht der HMR-Client, sich mit der URL zu verbinden, die der Server ihm genannt hat – der lokalen. Der Tunnel leitet das nicht weiter, also schlägt der WebSocket fehl und HMR stoppt still.
Korrigiere die HMR-Config:
export default defineConfig({
server: {
host: true,
allowedHosts: ['.portpreview.dev'],
hmr: {
clientPort: 443, // browser connects on 443 (HTTPS)
protocol: 'wss', // secure WebSocket through the tunnel
},
},
});
Jetzt verbindet sich der HMR-Client mit wss://abc123.portpreview.dev (Port 443), der Tunnel leitet das Upgrade weiter, und Änderungen propagieren wie erwartet. Wenn du nur statischen Reload brauchst und HMR über den Tunnel egal ist, kannst du das überspringen – aber du wirst viel cmd-R drücken.
Warum man Vite überhaupt tunneln will
Drei echte Gründe:
- Mobile-Tests. Öffne die URL auf einem Handy, sieh denselben Build mit HMR. Besser als Screen-Sharing oder Emulatoren pro Gerät. Siehe Mobile-Tests mit einem Tunnel für das ganze Muster.
- Work-in-Progress teilen. Schick einem Designer oder PM einen Link, sie sehen deinen Branch live. Kein Deploy-Schritt.
- OAuth- und Webhook-Flows, die HTTPS brauchen. Vite-ausgelieferte Frontends, die mit Stripe-redirect-only, Auth0 o. Ä. sprechen. mkcert vs. Tunnel behandelt die Wahl.
SvelteKit, Astro, SolidStart nutzen alle Vite
Die obigen Configs gelten für jedes Framework, das Vite als Dev-Server ausliefert. SvelteKits vite.config.js hat dieselbe Form. Astro hat seine eigene astro.config.mjs mit einem vite-Unterobjekt – setze dieselben server-Optionen dorthin. SolidStart, Nuxt 3 (via Vite) und Qwik City: dasselbe Muster.
Production-Builds sind eine andere Geschichte
Alles oben ist Dev-Server-Config. Wenn du vite preview ausführst oder ein gebautes Bundle ausliefert, spielt nichts davon eine Rolle, weil es kein HMR und keine Host-Check-Middleware gibt. Der Tunnel leitet dann nur noch statische Dateien weiter.
Ein paar kleinere Dinge
- Strict-Host-CORS. Wenn dein Frontend eine API auf einem anderen Origin anspricht (anderer localhost-Port oder ein separater API-Tunnel), setze CORS auf der API-Seite. Vite proxyt standardmäßig nicht, sofern du es nicht über
server.proxyanweist. - WebSocket-lastige Apps. Vite-HMR ist ein WebSocket. Wenn deine App einen anderen WebSocket für Spielstand, Chat oder Live-Daten nutzt, ist der separat und muss in deinem Client-Code ebenfalls auf die Tunnel-URL konfiguriert werden.
- Tunnel-URL in Env-Dateien. Wir setzen die aktive Tunnel-URL in
.env.localalsVITE_PUBLIC_URL, wenn das Frontend seine eigene öffentliche Adresse kennen muss.import.meta.env.VITE_PUBLIC_URLliest sie im Client.
Schritt für Schritt
- Füge den
server.host-,allowedHosts- undhmr-Block zu deiner Vite-Config hinzu. - Starte den Dev-Server neu.
- Führe
npx portpreview 5173aus (oder den Port, den Vite nutzt). - Öffne die HTTPS-URL im Browser oder auf einem Handy.
- Bearbeite eine Komponente. Bestätige, dass HMR die Seite ohne vollständigen Reload aktualisiert.
Wenn HMR nicht aktualisiert, öffne die Browser-Konsole – Vite loggt den WebSocket-Verbindungsversuch, und du siehst die versuchte URL. Das zeigt dir, ob die hmr.clientPort/protocol-Änderung gegriffen hat.
Tritt der PortPreview-Warteliste bei für Tunnel, die WebSocket-Upgrades standardmäßig erhalten.