Cloudflare.Tunnel reference
Configuration
Section titled “Configuration”Source:
packages/cloudflare/src/Tunnel/Configuration.ts
Routing configuration for a remotely-managed Cloudflare Tunnel.
Cloudflare exposes the cfd_tunnel configuration as a single PUT-style
document per tunnel — ingress rules in order, plus optional default
originRequest settings. This resource owns that document; it is the
declarative equivalent of editing a tunnel’s Public Hostname or Private
Hostname rules in the Zero Trust dashboard.
The catch-all rule (final ingress entry with no hostname) is appended
automatically — Cloudflare rejects PUTs whose last rule has a hostname,
and forgetting it is a common foot-gun. Override the auto-appended
service via ConfigurationProps.catchAllService.
Configuration: Routing a private hostname through a tunnel
Section titled “Configuration: Routing a private hostname through a tunnel”yield* Cloudflare.Tunnel.Configuration("AdminIngress", { tunnelId: tunnel.tunnelId, ingress: [ { hostname: "cluster-admin.microagi", service: "http://research-ui.admin.svc.cluster.local:80", }, ],});Configuration: Multiple hostnames + custom catch-all
Section titled “Configuration: Multiple hostnames + custom catch-all”yield* Cloudflare.Tunnel.Configuration("Ingress", { tunnelId: tunnel.tunnelId, ingress: [ { hostname: "ui.internal", service: "http://ui.app.svc.cluster.local:80" }, { hostname: "api.internal", service: "http://api.app.svc.cluster.local:8080" }, ], catchAllService: "http_status:503",});HostnameRoute
Section titled “HostnameRoute”Source:
packages/cloudflare/src/Tunnel/HostnameRoute.ts
A Cloudflare Zero Trust hostname route — routes traffic for a
private hostname through a cfd_tunnel, so WARP clients can reach
internal apps by name without publishing a public DNS record.
All fields (hostname, tunnel, comment) are mutable in place via PATCH.
HostnameRoute: Creating a hostname route
Section titled “HostnameRoute: Creating a hostname route”Route an internal hostname through a tunnel
const tunnel = yield* Cloudflare.Tunnel.Tunnel("MyTunnel");const route = yield* Cloudflare.Tunnel.HostnameRoute("AppRoute", { hostname: "app.internal.example.com", tunnelId: tunnel.tunnelId,});Add a comment
const route = yield* Cloudflare.Tunnel.HostnameRoute("AppRoute", { hostname: "app.internal.example.com", tunnelId: tunnel.tunnelId, comment: "Internal wiki behind the datacenter tunnel",});ReadTunnel
Section titled “ReadTunnel”Source:
packages/cloudflare/src/Tunnel/ReadTunnel.ts
Binding that lets a Worker read Cloudflare Tunnels at runtime.
Creates a scoped AccountApiToken with only the Cloudflare Tunnel Read permission and binds its outputs into the Worker (the token value as a
secret_text binding) so runtime code can authenticate.
ReadTunnel: Reading tunnels at runtime
Section titled “ReadTunnel: Reading tunnels at runtime”Bind the read client
Bind once in the Init phase; every method is available on the returned client.
const tunnels = yield* Cloudflare.Tunnel.ReadTunnel();List tunnels
const { result } = yield* tunnels.list({ isDeleted: false });Fetch a tunnel and its connector token
getToken returns the plaintext token used to run cloudflared.
const tunnel = yield* tunnels.get(tunnelId);const token = yield* tunnels.getToken(tunnelId);Read the ingress configuration
const { config } = yield* tunnels.getConfiguration(tunnelId);ReadTunnel: Runtime Layer
Section titled “ReadTunnel: Runtime Layer”Provide ReadTunnelBinding in the Worker’s runtime layer.
Effect.provide(Cloudflare.Tunnel.ReadTunnelBinding)ReadWriteTunnel
Section titled “ReadWriteTunnel”Source:
packages/cloudflare/src/Tunnel/ReadWriteTunnel.ts
Binding that lets a Worker perform the full Cloudflare Tunnel CRUD surface at runtime.
Creates a scoped AccountApiToken with both the Cloudflare Tunnel Read and Cloudflare Tunnel Write permissions and binds its outputs into
the Worker (the token value as a secret_text binding) so runtime code can
authenticate.
ReadWriteTunnel: Managing tunnels at runtime
Section titled “ReadWriteTunnel: Managing tunnels at runtime”// initconst tunnels = yield* Cloudflare.Tunnel.ReadWriteTunnel();
return { fetch: Effect.gen(function* () { const tunnel = yield* tunnels.create({ name: "on-demand-tunnel" }); yield* tunnels.putConfiguration(tunnel.id!, { ingress: [ { hostname: "app.example.com", service: "http://localhost:3000" }, { service: "http_status:404" }, ], }); const token = yield* tunnels.getToken(tunnel.id!); return HttpServerResponse.json({ id: tunnel.id, token }); }),};ReadWriteTunnel: Runtime Layer
Section titled “ReadWriteTunnel: Runtime Layer”Provide ReadWriteTunnelBinding in the Worker’s runtime layer.
Effect.provide(Cloudflare.Tunnel.ReadWriteTunnelBinding)Source:
packages/cloudflare/src/Tunnel/Route.ts
A Cloudflare Tunnel Route attaches a private CIDR to a cfd_tunnel so that
WARP clients (and other Zero Trust egress paths) can reach private IPs
through the tunnel.
Route: Creating a Route
Section titled “Route: Creating a Route”Basic route
const tunnel = yield* Cloudflare.Tunnel.Tunnel("MyTunnel");const route = yield* Cloudflare.Tunnel.Route("PrivateNet", { tunnelId: tunnel.tunnelId, network: "10.4.0.0/16",});Route with a comment and explicit virtual network
const route = yield* Cloudflare.Tunnel.Route("DcRoute", { tunnelId: tunnel.tunnelId, network: "10.50.0.0/16", comment: "Datacenter A private subnet", virtualNetworkId: vnet.id, adopt: true,});Tunnel
Section titled “Tunnel”Source:
packages/cloudflare/src/Tunnel/Tunnel.ts
A Cloudflare Tunnel that establishes a secure connection from your origin to Cloudflare’s edge.
Tunnel: Creating a Tunnel
Section titled “Tunnel: Creating a Tunnel”Basic tunnel
const tunnel = yield* Cloudflare.Tunnel.Tunnel("MyTunnel");// Run the connector with: cloudflared tunnel run --token <Redacted.value(tunnel.token)>Tunnel with ingress rules
const tunnel = yield* Cloudflare.Tunnel.Tunnel("Web", { ingress: [ { hostname: "app.example.com", service: "http://localhost:3000" }, { service: "http_status:404" }, ],});Tunnel: Managing Tunnels at Runtime
Section titled “Tunnel: Managing Tunnels at Runtime”The Tunnel resource manages a single, statically-declared tunnel as part of
a stack. To create, read, update, or delete tunnels on the fly from inside
a deployed Worker, bind one of the runtime tunnel clients instead. Each
provisions a least-privilege AccountApiToken and injects it into the
Worker:
ReadTunnel— read-only (get,list,getToken,getConfiguration); scoped toCloudflare Tunnel Read.WriteTunnel— mutating (create,update,delete,putConfiguration); scoped toCloudflare Tunnel Write.ReadWriteTunnel— the full CRUD surface; scoped to both.
// initconst tunnels = yield* Cloudflare.Tunnel.ReadWriteTunnel();
return { fetch: Effect.gen(function* () { const tunnel = yield* tunnels.create({ name: "on-demand-tunnel" }); const token = yield* tunnels.getToken(tunnel.id!); return HttpServerResponse.json({ id: tunnel.id, token }); }),};Tunnel: Looking up an existing Tunnel
Section titled “Tunnel: Looking up an existing Tunnel”Tunnel.lookup reads a tunnel Alchemy doesn’t manage (created with
cloudflared or by another stack), found by tunnelId or name, so
routes, configurations and DNS records can point at it. It is read during
plan/deploy and never created, updated or deleted.
const tunnel = Cloudflare.Tunnel.Tunnel.lookup({ name: "home-lab" });yield* Cloudflare.DNS.Record("Admin", { zoneId: zone.zoneId, name: "admin.example.com", type: "CNAME", content: Output.interpolate`${tunnel.tunnelId}.cfargotunnel.com`, proxied: true,});VirtualNetwork
Section titled “VirtualNetwork”Source:
packages/cloudflare/src/Tunnel/VirtualNetwork.ts
A Cloudflare Zero Trust Virtual Network — an isolated routing namespace for Cloudflare Tunnel private networks.
Virtual networks let you run overlapping CIDR ranges side by side: each
Route can target a virtualNetworkId, and WARP clients
switch between virtual networks to choose which copy of 10.0.0.0/8
they see. Every account starts with a single default virtual network.
Name and comment are mutable in place. Deleting a virtual network
requires that no routes reference it — express that relationship by
passing vnet.virtualNetworkId into your Routes so destroy
ordering is correct.
VirtualNetwork: Creating a Virtual Network
Section titled “VirtualNetwork: Creating a Virtual Network”Basic virtual network
const vnet = yield* Cloudflare.Tunnel.VirtualNetwork("Staging", { comment: "staging private network",});Route a tunnel CIDR through the virtual network
const tunnel = yield* Cloudflare.Tunnel.Tunnel("MyTunnel");yield* Cloudflare.Tunnel.Route("StagingNet", { tunnelId: tunnel.tunnelId, network: "10.4.0.0/16", virtualNetworkId: vnet.virtualNetworkId,});VirtualNetwork: Default network
Section titled “VirtualNetwork: Default network”// Only one default per account — promoting demotes the previous one.const vnet = yield* Cloudflare.Tunnel.VirtualNetwork("Primary", { isDefaultNetwork: true,});VirtualNetwork: Looking up an existing Virtual Network
Section titled “VirtualNetwork: Looking up an existing Virtual Network”VirtualNetwork.lookup reads a virtual network Alchemy doesn’t manage
(the account’s default network, or one created in the dashboard or by
another stack), found by virtualNetworkId or name, so routes can
target it. It is read during plan/deploy and never created, updated or
deleted.
const vnet = Cloudflare.Tunnel.VirtualNetwork.lookup({ name: "staging" });yield* Cloudflare.Tunnel.Route("StagingNet", { tunnelId: tunnel.tunnelId, network: "10.4.0.0/16", virtualNetworkId: vnet.virtualNetworkId,});WarpConnector
Section titled “WarpConnector”Source:
packages/cloudflare/src/Tunnel/WarpConnector.ts
A Cloudflare WARP Connector tunnel — a software site-to-site connector
that extends a private network into Cloudflare Zero Trust without
running cloudflared.
The resource manages the tunnel record itself (CRUD); a WARP Connector
host joins it at runtime using the token attribute. Pair with
Route to route private CIDRs through the connector and
VirtualNetwork to isolate overlapping address space.
WarpConnector: Creating a WARP Connector
Section titled “WarpConnector: Creating a WARP Connector”Basic WARP Connector tunnel
const connector = yield* Cloudflare.Tunnel.WarpConnector("SiteA", { name: "site-a-connector",});// Provision the host with: warp-cli connector new <Redacted.value(connector.token)>Route a private network through the connector
yield* Cloudflare.Tunnel.Route("SiteANet", { tunnelId: connector.tunnelId, network: "10.8.0.0/16",});WarpConnector: Renaming
Section titled “WarpConnector: Renaming”// Renaming creates a new tunnel with a new tunnelId.const connector = yield* Cloudflare.Tunnel.WarpConnector("SiteA", { name: "site-a-connector-v2",});WarpConnector: Looking up an existing connector
Section titled “WarpConnector: Looking up an existing connector”WarpConnector.lookup references a connector Alchemy doesn’t manage
(created in the dashboard or by another stack), found by tunnelId or
name. It is read during plan/deploy and never created or deleted. Its
token is read too.
const siteA = Cloudflare.Tunnel.WarpConnector.lookup({ name: "site-a-connector" });yield* Cloudflare.Tunnel.Route("SiteANetwork", { tunnelId: siteA.tunnelId, network: "10.9.0.0/16",});WriteTunnel
Section titled “WriteTunnel”Source:
packages/cloudflare/src/Tunnel/WriteTunnel.ts
Binding that lets a Worker create, update, and delete Cloudflare Tunnels at runtime.
Creates a scoped AccountApiToken with only the Cloudflare Tunnel Write permission and binds its outputs into the Worker (the token value as a
secret_text binding) so runtime code can authenticate.
WriteTunnel: Mutating tunnels at runtime
Section titled “WriteTunnel: Mutating tunnels at runtime”Bind the write client
Bind once in the Init phase; every method is available on the returned client.
const tunnels = yield* Cloudflare.Tunnel.WriteTunnel();Create a tunnel
const tunnel = yield* tunnels.create({ name: "on-demand-tunnel" });Push ingress configuration
yield* tunnels.putConfiguration(tunnel.id!, { ingress: [ { hostname: "app.example.com", service: "http://localhost:3000" }, { service: "http_status:404" }, ],});Rename and delete a tunnel
yield* tunnels.update(tunnel.id!, { name: "renamed-tunnel" });yield* tunnels.delete(tunnel.id!);WriteTunnel: Runtime Layer
Section titled “WriteTunnel: Runtime Layer”Provide WriteTunnelBinding in the Worker’s runtime layer.
Effect.provide(Cloudflare.Tunnel.WriteTunnelBinding)