Skip to content

Cloudflare.Tunnel reference

Source: src/Cloudflare/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",
});

Source: src/Cloudflare/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.

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",
});

Source: src/Cloudflare/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.

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);

Provide ReadTunnelBinding in the Worker’s runtime layer.

Effect.provide(Cloudflare.Tunnel.ReadTunnelBinding)

Source: src/Cloudflare/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”
// init
const 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 });
}),
};

Provide ReadWriteTunnelBinding in the Worker’s runtime layer.

Effect.provide(Cloudflare.Tunnel.ReadWriteTunnelBinding)

Source: src/Cloudflare/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.

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,
});

Source: src/Cloudflare/Tunnel/Tunnel.ts

A Cloudflare Tunnel that establishes a secure connection from your origin to Cloudflare’s edge.

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" },
],
});

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 to Cloudflare Tunnel Read.
  • WriteTunnel — mutating (create, update, delete, putConfiguration); scoped to Cloudflare Tunnel Write.
  • ReadWriteTunnel — the full CRUD surface; scoped to both.
// init
const 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 });
}),
};

Source: src/Cloudflare/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,
});
// Only one default per account — promoting demotes the previous one.
const vnet = yield* Cloudflare.Tunnel.VirtualNetwork("Primary", {
isDefaultNetwork: true,
});

Source: src/Cloudflare/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.

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",
});
// Renaming creates a new tunnel with a new tunnelId.
const connector = yield* Cloudflare.Tunnel.WarpConnector("SiteA", {
name: "site-a-connector-v2",
});

Source: src/Cloudflare/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.

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!);

Provide WriteTunnelBinding in the Worker’s runtime layer.

Effect.provide(Cloudflare.Tunnel.WriteTunnelBinding)