You can expose your local dev server over a Cloudflare Tunnel when you need to share a preview, test a webhook, or access your app from another device.
This page covers tunnel support in Wrangler and the Cloudflare Vite plugin.
You can start a tunnel with Wrangler or the Cloudflare Vite plugin for the current session. This gives you either a random *.trycloudflare.com hostname via a Quick Tunnel, or a stable hostname via a named tunnel.
Wrangler
Run wrangler dev, then press [t] to start or close the tunnel. Wrangler will print the public tunnel URL or URLs for the current session.
To use a named tunnel, run:
npx wrangler dev --tunnel-name=my-tunnelyarn wrangler dev --tunnel-name=my-tunnelpnpm wrangler dev --tunnel-name=my-tunnelUse --tunnel if you want the tunnel to open automatically when Wrangler starts.
npx wrangler dev --tunnelyarn wrangler dev --tunnelpnpm wrangler dev --tunnelCloudflare Vite plugin
Run vite dev, then press t + Enter to start or close the tunnel. Add tunnel to the plugin config if you want to configure a named tunnel or have the tunnel open automatically when Vite starts.
To use a named tunnel with stable hostnames:
import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin";
export default defineConfig({
plugins: [
cloudflare({
tunnel: { name: "my-tunnel" },
}),
],
});import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin";
export default defineConfig({
plugins: [
cloudflare({
tunnel: { name: "my-tunnel" },
}),
],
});If you want the tunnel to open automatically when Vite starts, set tunnel.autoStart to true.
When using vite preview, Vite's preview host validation still applies:
- For Quick tunnel, add
.trycloudflare.comtopreview.allowedHosts. - For named tunnel, add the resolved hostnames or a matching domain suffix such as
.my-domain.comtopreview.allowedHosts.
For example:
import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin";
export default defineConfig({
preview: {
allowedHosts: [
// For Quick tunnels:
".trycloudflare.com",
// For named tunnels:
".my-domain.com",
],
},
plugins: [
cloudflare({
tunnel: { name: "my-tunnel" },
}),
],
});import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin";
export default defineConfig({
preview: {
allowedHosts: [
// For Quick tunnels:
".trycloudflare.com",
// For named tunnels:
".my-domain.com"
],
},
plugins: [
cloudflare({
tunnel: { name: "my-tunnel" },
}),
],
});The local development security considerations apply with or without a tunnel. A tunnel increases exposure by making your dev server remotely reachable. It does not add security isolation around the local workerd process.
Unless the tunnel is protected by access controls, anyone with its URL can reach your dev server. Review what your app exposes before starting a tunnel.
- Pay special attention to ungated preview or admin endpoints.
- Do not expose endpoints that accept and execute code supplied by users.
- Review any remote bindings connected to real resources.
- Review any code that proxies requests to private or internal services.
- If you are using the Cloudflare Vite plugin with
vite dev, HMR and module serving may expose source files, file paths, or project structure over the tunnel. If you only need to share a built preview, prefervite previewfor public sharing. This reduces source exposure but does not add runtime isolation. - Local dev-related routes, such as
/cdn-cgi/*, remain restricted and are not exposed over the tunnel. - If you need a stable hostname or stricter access control, use a named tunnel protected by Cloudflare Access. Access restricts who can reach the server but does not harden the local runtime.