Fortschrittliche Frontend-Architektur & DX: Lokale Tunnels für schnellere Entwicklungszyklen nutzen
Erfahren Sie, wie Sie die Entwicklererfahrung mit localhost-Tunnels optimieren. Lernen Sie, visuelle Regression, Feature-Flags-Synchronisation und Micro-Frontends lokal zu testen.

Quick answer
Fortschrittliche lokale Tunnel-Pipelines für Frontend entwickeln: 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.
Frontend-Feedback-Schleifen verlangsamen sich, wenn bei jedem Check eine Deployment notwendig ist. Das Warten auf eine Vorschau-Umgebung oder eine CI-Pipeline nur um eine visuelle Änderung auf einem Telefon zu sehen oder ein Micro-Frontend gegen eine echte Shell zu testen, erhöht Reibung und Kosten.
Ein localhost-Tunnel ist eine Möglichkeit, diese Schleife zu verkürzen. Ein kleiner Agent auf Ihrer Maschine stellt eine ausgehende Verbindung zu einem Relay her, das Ihrer lokalen Server eine öffentliche HTTPS-URL gibt. Gängige Optionen sind ngrok, Cloudflare Tunnel (cloudflared) und localtunnel. Ihre Vor- und Nachteile unterscheiden sich erheblich und beeinflussen, welche Muster unten für Sie geeignet sind.
Dieser Artikel behandelt drei Muster und zeigt, wo der Tunnel hilft und wo nicht:
- Visuelle Regressionstests mit Playwright gegen einen getunnelten Entwicklungsserver
- Feature-Flags auf echten Geräten testen
- Übersteuerung eines Micro-Frontends in einer bereitgestellten Shell mit Shadow DOM-Isolation
Wahl eines Tunnels: Was die Dokumentation sagt (Oktober 2026)
Prüfen Sie diese Grenzen, bevor Sie einen Workflow um einen Tunnel herum entwerfen.
| Tool | Stabile URL | Bemerkenswerte Grenzen | Am besten geeignet für |
|---|---|---|---|
| ngrok (kostenfrei) | Zuweisbare Entwicklungsdomain (z.B. dein-name.ngrok-free.app); Name kann nicht gewählt werden |
Interstitial-Warnseite bei HTML-Browserverkehr; benutzerdefinierte oder reservierte Domains benötigen einen kostenpflichtigen Plan | Geräte-Tests, Webhooks, kurze Demos |
| Cloudflare Quick Tunnel | Nein: neuer trycloudflare.com-Hostname bei jedem Lauf |
Kein SLA, 200 gleichzeitige Requests pro Tunnel, keine Server-Sent Events | Schnelles Teilen einer einfachen HTTP-App |
| Cloudflare benannter Tunnel | Ja, auf eigener Domain | Erfordert Cloudflare-Konto und Domain-Setup | Längerfristige, stabile Endpunkte |
| localtunnel | Zufällige Subdomain | Paket inaktiv (neueste npm-Version ca. drei Jahre alt); öffentliche Instanz ist best-effort | Schnelle, risikoarme Experimente |
Cloudflare dokumentiert Quick Tunnels als nur für Tests geeignet, mit einer festen Begrenzung bei gleichzeitigen Requests und ohne SSE-Unterstützung. Wenn Ihre App Events über SSE streamt (z.B. ein Dev-Dashboard, eine KI-Chat-Oberfläche), wird ein Quick Tunnel diese unterbrechen. Verwenden Sie einen benannten Tunnel oder einen anderen Anbieter.
In ngrok’s kostenfreiem Plan wird eine Interstitial-Seite vor den HTML-Browserverkehr geschaltet, um Phishing zu verhindern. Nach Akzeptanz setzt sie ein Cookie, das 7 Tage gültig ist. Requests mit einem ngrok-skip-browser-warning-Header (beliebiger Wert) umgehen das, ebenso wie kostenpflichtige Pläne. Das ist später relevant: Skripte und Assets, die von einer Seite geladen werden, können stattdessen die Interstitial-HTML erhalten, anstatt der erwarteten Datei.
1. Visuelle Regressionstests gegen einen getunnelten Entwicklungsserver
Playwright bietet integrierte visuelle Vergleiche mit expect(page).toHaveScreenshot(). Der ältere Pfad toMatchSnapshot() funktioniert noch, aber die Playwright-Dokumentation empfiehlt toHaveScreenshot() für Screenshots.
Wann Sie einen Tunnel brauchen und wann nicht
Wenn Playwright auf derselben Maschine (oder CI-Runner) läuft wie Ihr Entwicklungsserver, kann es localhost direkt erreichen. Die webServer-Konfiguration von Playwright kann sogar den Server starten. Ein Tunnel ist dort unnötig.
Visuelle Dienste wie Percy und Chromatic benötigen ebenfalls keinen Zugriff auf Ihren Rechner. Ihre Playwright-Integrationen (@percy/playwright mit percy exec und @chromatic-com/playwright) erfassen Snapshots oder UI-Archive während Ihrer lokalen Tests und laden sie für Vergleich und Review hoch. Percy rendert diese Snapshots in seiner Cloud.
Ein Tunnel ist sinnvoll, wenn etwas Remote Ihr lokales Build laden muss. Beispiele sind eine gehostete Browser-Grid, eine echte Geräte-Cloud oder ein Kollege, der an einem WIP-Branch arbeitet. Das folgende Beispiel zeigt die Mechanik. Das gleiche Muster funktioniert, wenn der Remote-Browser statt eines lokalen einer ist.
Umsetzung: Playwright + das offizielle ngrok SDK
Das offizielle Node SDK ist @ngrok/ngrok. Es benötigt keine separate Binärdatei und stellt ngrok.forward() zum Starten eines Listeners bereit.
npm install --save-dev @playwright/test @ngrok/ngrok
npx playwright install
playwright.config.ts
import { defineConfig } from '@playwright/test';
const { PLAYWRIGHT_BASE_URL, TUNNEL_USER, TUNNEL_PASS } = process.env;
export default defineConfig({
testDir: './tests/visual',
use: {
baseURL: PLAYWRIGHT_BASE_URL ?? 'http://localhost:3000',
// Überspringt ngrok's kostenfreies Interstitial bei Requests vom Testbrowser
extraHTTPHeaders: { 'ngrok-skip-browser-warning': '1' },
// Beantwortet die Basic-Auth-Herausforderung, die im Tunnel konfiguriert ist
...(TUNNEL_USER && TUNNEL_PASS
? { httpCredentials: { username: TUNNEL_USER, password: TUNNEL_PASS } }
: {}),
},
expect: {
toHaveScreenshot: { maxDiffPixelRatio: 0.02 }, // bis zu 2% unterschiedliche Pixel zulassen
},
});
run-visual-tests.mjs
import ngrok from '@ngrok/ngrok';
import { spawnSync } from 'node:child_process';
const port = Number(process.env.PORT ?? 3000);
const { TUNNEL_USER, TUNNEL_PASS } = process.env;
const listener = await ngrok.forward({
addr: port,
authtoken_from_env: true, // liest NGROK_AUTHTOKEN
basic_auth: `${TUNNEL_USER}:${TUNNEL_PASS}`, // öffnet keinen öffentlichen Dev-Server
});
try {
console.log(`Tunnel läuft unter ${listener.url()}`);
const result = spawnSync('npx', ['playwright', 'test'], {
stdio: 'inherit',
env: { ...process.env, PLAYWRIGHT_BASE_URL: listener.url() },
});
process.exitCode = result.status ?? 1;
} finally {
await listener.close(); // Tunnel immer wieder schließen
}
tests/visual/dashboard.spec.ts
import { test, expect } from '@playwright/test';
test('Dashboard stimmt mit Basislinie überein', async ({ page }) => {
await page.goto('/dashboard');
// Warten auf sichtbares Element, nicht auf Netzwerk-Idle
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
await expect(page).toHaveScreenshot('dashboard.png', {
fullPage: true,
mask: [page.locator('.timestamp-badge')], // volatile Bereiche maskieren
});
});
Drei Änderungen im Vergleich zu üblichen Beispielen:
- Nicht auf
waitForLoadState('networkidle')verlassen. Die Playwright-API-Dokumentation hält diese Methode für Tests für ungeeignet und empfiehlt webbasierte Assertions wietoBeVisible(). - Volatile Inhalte maskieren statt sie mit einem injizierten Script zu verstecken.
toHaveScreenshot()bietet diemask-Option für Zeitstempel, Avatare und ähnliche Bereiche. Screenshot-Assertions deaktivieren auch standardmäßig Animationen und warten, bis zwei aufeinanderfolgende Aufnahmen übereinstimmen. - Baselines in einer konsistenten Umgebung erstellen. Schriftarten und Kantenglättung unterscheiden sich zwischen Betriebssystemen, daher sollten Baselines in derselben Umgebung (z.B. in einem fixierten Container-Image) erstellt und verglichen werden. Baselines sollten gezielt mit
npx playwright test --update-snapshotsaktualisiert werden.
Was ein Tunnel leistet und was nicht
- Vorteil: eine öffentliche HTTPS-URL für Tools, die Ihren Rechner nicht sehen können, ohne Deployment.
- Kein Vorteil: Es macht einen flüchtigen Test nicht deterministisch. Flakiness entsteht meist durch Animationen, Schriftarten und Live-Daten, die Maskierung und stabile Fixtures beheben.
- Kosten: ein Interstitial bei kostenfreiem Plan, Request-Limits und die Tatsache, dass Ihr Dev-Server für jeden mit der URL erreichbar ist.
2. Feature-Flags auf echten Geräten testen
Das Verhalten von Feature-Flags auf einem echten iPhone oder Android-Gerät unterscheidet sich von der Emulation am Desktop in Touch-Handling, Viewport-Quirks, WebView-Verhalten und Netzbedingungen. Ein Tunnel macht Ihren lokalen Build vom Telefon aus erreichbar, auch im Mobilfunknetz, ohne Deployment.
Was der Tunnel transportiert und was nicht
Hier ist Vorsicht geboten. Der Tunnel liefert HTML und JavaScript Ihrer App an das Telefon. Flag-Werte reisen auf einem separaten Pfad: Das Flag-SDK kommuniziert direkt vom Gerät in die Cloud des Anbieters, ohne Tunnel. Änderungen an Flags im Admin-Panel müssen nie durch den Tunnel laufen. Der Tunnel ist nur relevant, wenn Sie Flag-Daten durch Ihren eigenen Server proxyen.
Wie schnell die Seite reagiert, hängt vom SDK ab:
- LaunchDarklys JavaScript-Client-SDKs stellen eine erste Verbindung über einen Polling-Endpunkt her, und einige (z.B. das React Web SDK) öffnen standardmäßig eine Streaming-Verbindung. Sie abonnieren Änderungen mit Listenern wie
client.on('change:flag-key', …). - PostHogs JS-Bibliothek lädt Flags im Hintergrund bei jedem Seitenaufruf und cached die Werte. Die dokumentierte Methode zum Aktualisieren ist
posthog.reloadFeatureFlags(). MitonFeatureFlagswarten Sie, bis der erste Fetch abgeschlossen ist.
Beispiel: Reaktion auf LaunchDarkly-Flag-Änderungen
// useFlag.ts
import { useEffect, useState } from 'react';
import { initialize } from 'launchdarkly-js-client-sdk';
const client = initialize(import.meta.env.VITE_LD_CLIENT_ID, {
kind: 'user',
key: 'dev-device-01',
});
export function useFlag(key: string, fallback = false) {
const [value, setValue] = useState(fallback);
useEffect(() => {
let active = true;
const refresh = () => active && setValue(client.variation(key, fallback));
client.waitForInitialization(5).then(refresh).catch(() => {});
client.on(`change:${key}`, refresh);
return () => {
active = false;
client.off(`change:${key}`, refresh);
};
}, [key, fallback]);
return value;
}
export function Checkout() {
const newCheckout = useFlag('new-checkout-v2');
return newCheckout ? <ExpressCheckout /> : <LegacyCheckout />;
}
Verwenden Sie eine Client-ID aus einer Test- oder Entwicklungsumgebung, damit Flag-Umschaltungen nie echte Nutzer treffen.
Beispiel: PostHog mit explizitem Refresh
import posthog from 'posthog-js';
posthog.init(import.meta.env.VITE_POSTHOG_KEY, {
api_host: 'https://us.i.posthog.com', // für EU-Cloud `https://eu.i.posthog.com`
});
posthog.onFeatureFlags(() => {
console.log('new-checkout-v2:', posthog.getFeatureFlag('new-checkout-v2'));
});
// Nach Änderung eines Flags in der UI, Werte aktualisieren:
// (z.B. per Button, Intervall oder visibilitychange)
posthog.reloadFeatureFlags();
Das Entwickler-Server zum Telefon freigeben
ngrok http 3000
Auf dem kostenfreien Plan weist ngrok Ihrer Dev-Domain automatisch eine URL zu (Name kann nicht gewählt werden). Öffnen Sie die https://…ngrok-free.app-URL auf dem Telefon. Das Interstitial erscheint einmal; Akzeptieren setzt ein Cookie, das 7 Tage gültig ist.
Einige Dev-Server lehnen Requests mit einem unbekannten Host-Header ab. Vite hat server.allowedHosts, webpack-dev-server allowedHosts. Wenn die Seite von localhost lädt, aber nicht durch den Tunnel, prüfen Sie das zuerst.
Praktische Grenzen
- Ein Cloudflare Quick-Tunnel ist ungeeignet, wenn Ihre App SSE nutzt, da Quick Tunnels das nicht unterstützen.
- Hot Module Reload benötigt eine WebSocket-Verbindung zum Dev-Server. Wenn die Seite lädt, aber keine Live-Updates erfolgen, prüfen Sie Tunnel- und Server-Hosteinstellungen.
- Keine echten Nutzerdaten oder Produktions-Credentials hinter einem öffentlichen Tunnel verwenden.
3. Micro-Frontends: Überschreiben eines Remote in einer bereitgestellten Shell
Module Federation ermöglicht es, unabhängig entwickelte Anwendungen zur Laufzeit Code zu teilen. Webpack 5 enthält das ursprüngliche Plugin, und Module Federation 2.0 ergänzt eine bundler-unabhängige Laufzeit, Typhinweise für Remotes und Laufzeit-Plugins via @module-federation/enhanced, das Webpack und Rspack unterstützt. Die Laufzeit stellt registerRemotes und loadRemote bereit, um Remotes dynamisch hinzuzufügen.
Ein häufiges Entwicklungsproblem: Ihr Remote funktioniert eigenständig, aber bei Integration treten Style-Konflikte, Abhängigkeitsmismatches oder auth-abhängiges Verhalten erst auf, wenn es in die echte Shell eingebunden ist. Ein Workaround ist, die Shell deployed zu lassen, nur das Remote lokal hinter einem Tunnel laufen zu lassen und die Shell-Anfrage für das Remote-Entry-File auf die Tunnel-URL umzuleiten.
Warum ein Tunnel statt localhost
- Chrome hat Requests von öffentlichen Seiten zu lokalen Netzwerken und Loopback-Adressen durch eine Berechtigungsabfrage (Local Network Access, ab Chrome 142) eingeschränkt, später auch WebSocket-Verbindungen. Ein Tunnel gibt dem Remote eine öffentliche HTTPS-Quelle, sodass eine deployte HTTPS-Shell keine öffentliche-zu-Loopback-Anfrage macht.
- Eine HTTPS-Shell, die plain HTTP lädt, verursacht Mixed-Content-Probleme. Eine HTTPS-Tunnel-URL vermeidet das.
- Ein Kollege kann die Überschreibung laden, ohne im Netzwerk zu sein.
Schritt 1: Remote konfigurieren
// webpack.config.js (remote)
const { ModuleFederationPlugin } = require('@module-federation/enhanced/webpack');
module.exports = {
mode: 'development',
output: { publicPath: 'auto' }, // Chunk-Resolver relativ zum geladenen remoteEntry.js
devServer: {
port: 8081,
allowedHosts: ['.ngrok-free.app'], // Host-Header akzeptieren
headers: {
// Beschränkung auf die Shell, gegen die getestet wird, statt '*'
'Access-Control-Allow-Origin': 'https://app.example.com',
},
},
module: {
rules: [
// Scoped CSS als String importieren, um es ins Shadow DOM zu injizieren
{ test: /\.scoped\.css$/, type: 'asset/source' },
],
},
plugins: [
new ModuleFederationPlugin({
name: 'checkoutMFE',
filename: 'remoteEntry.js',
exposes: { './CheckoutWidget': './src/CheckoutWidget.tsx' },
shared: {
react: { singleton: true, requiredVersion: '^18.0.0' },
'react-dom': { singleton: true, requiredVersion: '^18.0.0' },
},
}),
],
};
Schritt 2: Styles mit Shadow DOM isolieren und Grenzen kennen
Shadow DOM verhindert, dass Selektoren der Host-Seite in Ihre Komponente eindringen, und umgekehrt. Es ist keine vollständige Isolierung:
- Vererbte Eigenschaften überschreiten die Grenze.
color,font-family,line-heightund ähnliche Eigenschaften, die außerhalb des Shadow DOM gesetzt sind, gelten auch innerhalb. - CSS-Variablen (Custom Properties) überschreiten die Grenze. Das ist nützlich für Theming, bedeutet aber, dass
--primarydes Hosts Ihre Komponente verändern kann. all: initialauf:hostsetzt vererbte Eigenschaften zurück, aber nicht Custom Properties. Diese explizit zurücksetzen, wenn nötig.
// src/CheckoutWidget.scoped.css
:host {
all: initial; /* Vererbte Eigenschaften vom Host stoppen */
display: block;
}
.checkout-container { font-family: system-ui, sans-serif; }
Da Shadow DOM Ihre CSS enthält, sehen Sie keine Host-Style-Konflikte mehr in dieser Komponente. Testen Sie Ihre Annahmen zu vererbten und Custom Properties im echten Shell, da dort Leakage noch passieren kann.
Schritt 3: Shell-Anfrage auf Ihren Tunnel umleiten
Starten Sie das Remote und den Tunnel:
npm start # remote auf :8081
ngrok http 8081 # notieren Sie die https://…ngrok-free.app URL
Dann verwenden Sie eine kleine Chrome-Erweiterung basierend auf declarativeNetRequest, die Requests blockiert oder umschreibt und eine Weiterleitung unterstützt. Sie benötigt die declarativeNetRequest-Berechtigung und host_permissions für die beteiligten Ursprünge.
manifest.json
{
"manifest_version": 3,
"name": "MFE Local Override",
"version": "0.1.0",
"permissions": ["declarativeNetRequest"],
"host_permissions": ["https://app.example.com/*", "https://*.ngrok-free.app/*"],
"declarative_net_request": {
"rule_resources": [
{ "id": "mfe_override", "enabled": true, "path": "rules.json" }
]
}
}
rules.json
[
{
"id": 1,
"priority": 1,
"action": {
"type": "redirect",
"redirect": { "url": "https://your-name.ngrok-free.app/remoteEntry.js" }
},
"condition": {
"urlFilter": "||app.example.com/assets/mfe/checkout/remoteEntry.js",
"resourceTypes": ["script"]
}
},
{
"id": 2,
"priority": 1,
"action": {
"type": "modifyHeaders",
"requestHeaders": [
{ "header": "ngrok-skip-browser-warning", "operation": "set", "value": "1" }
]
},
"condition": {
"requestDomains": ["your-name.ngrok-free.app"],
"resourceTypes": ["script", "xmlhttprequest"]
}
}
]
Request 2 behandelt das Interstitial bei kostenfreiem Plan. Ohne diese Regel kann der Browser die Warnseite-HTML erhalten, wo remoteEntry.js erwartet wird, und der Remote-Load scheitert. Nach Einrichtung prüfen Sie in den DevTools im Netzwerk-Tab, ob der Header bei Tunnel-Requests tatsächlich vorhanden ist. Wenn Ihr Remote andere Dateien per fetch lädt (z.B. eine Manifest-JSON), fügen Sie xmlhttprequest zu Regel 1 hinzu.
Solche statischen Regeln sind bei der Installation fest. Wenn sich der Tunnel-Hostname zwischen Sessions ändert (z.B. bei Cloudflare Quick Tunnel), verwenden Sie dynamische Regeln, die Browser-übergreifend bestehen bleiben.
Sicherheitshinweise für dieses Muster
- Das Override betrifft nur den Browser mit der Erweiterung. Nicht auf eine gemeinsame oder produktive Umgebung auf einem Entwickler-Laptop zeigen.
- Ihr Remote ist für jeden mit der Tunnel-URL erreichbar. Da Skript-Subresources keinen Login haben, ist eine IP-Whitelist (z.B. ngrok
restrict-ips) oft besser als Basic Auth. - Wenn die Shell und das Remote
singleton-Abhängigkeiten teilen, führen Versionsmismatches (z.B. unterschiedliche React-Major-Versionen) zu Laufzeitfehlern. Diese in Ihrer gemeinsamen Konfiguration beheben, nicht durch Lockerung des Tunnels.
Zusammenfassung
| Ziel | Wo ein Tunnel hilft | Wo nicht | Schlüssel-Tools |
|---|---|---|---|
| Visuelle Regression | Ein Remote-Browser, Geräte-Cloud oder Reviewer muss Ihr lokales Build laden | Lokale Playwright-, Percy- und Chromatic-Tests funktionieren bereits gegen localhost |
Playwright toHaveScreenshot(), @ngrok/ngrok, Percy, Chromatic |
| Feature-Flags auf Geräten | Das Telefon muss Ihre lokale App laden | Flag-Werte fließen Gerät-zu-Anbieter, nicht durch den Tunnel | LaunchDarkly, PostHog, ngrok |
| Micro-Frontend-Override | Eine deployte HTTPS-Shell braucht einen öffentlichen HTTPS-Remote | Shadow DOM blockiert keine vererbten oder Custom Properties | Module Federation 2.0, declarativeNetRequest, Shadow DOM |
Sicherheits-Checkliste für Tunnel-Workflows
- Authentifizieren oder einschränken Sie jeden Tunnel. ngrok unterstützt Basic Auth, OAuth und IP-Beschränkungen via Traffic Policy.
@ngrok/ngrokakzeptiert Optionen wiebasic_authundtraffic_policy. Cloudflare Quick Tunnels haben standardmäßig keine Authentifizierung,cloudflaredbietet--allowed-mailfür E-Mail-Verifizierung. - Tokens aus Quellcode fernhalten. Lesen Sie
NGROK_AUTHTOKEN(oder Cloudflare-Credentials) aus Umgebungsvariablen oder Secret-Manager, und rotieren Sie sie regelmäßig. - Kurzlebige Tunnel verwenden. Schließen Sie Listener in
finally-Blöcken oder Signal-Handlern, damit bei Absturz kein Dev-Server offen bleibt. - Nichts mit Produktionsdaten oder Credentials tunneln. Nutzen Sie Fixtures und Entwicklungsumgebungen.
- Prüfen Sie die Limits des kostenlosen Plans vor der Nutzung. Interstitials, Domain-Beschränkungen, Request-Limits und fehlende SSE-Unterstützung sind häufige Überraschungen.
Fazit
Ein Tunnel ist ein nützliches Werkzeug, wenn etwas Remote auf Ihren lokalen Build zugreifen muss. Das betrifft echte Geräte, Browser in der Cloud, deployte Shells und Reviewer. Es ist nicht notwendig, wenn alles bereits auf einer Maschine läuft, und beeinflusst nicht, wie Flag-SDKs oder Screenshot-Services kommunizieren. Wählen Sie das Muster passend zum Problem, prüfen Sie die aktuellen Limits Ihres Tunnels und sichern Sie den Endpunkt, bevor Sie die URL teilen.
Quellen
- ngrok JavaScript SDK (
@ngrok/ngrok) - ngrok Free Plan Limits und Interstitial
- ngrok Netzwerksicherheit und IP-Beschränkungen
- Cloudflare Quick Tunnels
- Playwright
SnapshotAssertions(mittoHaveScreenshot()) - Chromatic für Playwright
- Percy- und Playwright-Integration
- PostHog Web-Feature-Flags
- LaunchDarkly Client-side vs. Server-side SDKs
- LaunchDarkly: Abonnieren von Flag-Änderungen
- Module Federation Laufzeit-API
- Chrome
declarativeNetRequestAPI - Chrome Local Network Access
- Shadow DOM und vererbte Styles (Open Web Components)
- localtunnel Wartungsstatus (Snyk)
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.