Handle outbound traffic
Outbound Workers are Workers that handle HTTP requests made by your container. They act as programmable egress proxies, running on the same machine as the container with access to all Workers bindings.
Use outbound Workers to route requests to Workers functions and their bindings (KV, R2, Durable Objects, etc.)
Use outbound to intercept outbound HTTP traffic regardless of destination:
import { Container } from "@cloudflare/containers";
export class MyContainer extends Container {}
MyContainer.outbound = async (request, env, ctx) => { if (request.method !== "GET") { console.log(`Blocked ${request.method} to ${request.url}`); return new Response("Method Not Allowed", { status: 405 }); } return fetch(request);};Use outboundByHost to map specific domain names or IP addresses to handler functions:
import { Container } from "@cloudflare/containers";
export class MyContainer extends Container {}
MyContainer.outboundByHost = { "my.worker": async (request, env, ctx) => { // Run arbitrary Workers logic from this hostname return await someWorkersFunction(request.body); },};The container calls http://my.worker and the handler runs entirely inside the Workers runtime, outside of the container sandbox.
If you define both, outboundByHost handlers take precedence over the catch-all outbound handler.
Outbound handlers have access to your Worker's bindings. Route container traffic to internal platform resources without changing application code.
export class MyContainer extends Container {}
MyContainer.outboundByHost = { "my.kv": async (request, env, ctx) => { const url = new URL(request.url); const key = url.pathname.slice(1); const value = await env.KV.get(key); return new Response(value); }, "my.r2": async (request, env, ctx) => { const url = new URL(request.url); // Scope access to this container's ID const path = `${ctx.containerId}${url.pathname}`; const object = await env.R2.get(path); return new Response(object?.body ?? null, { status: object ? 200 : 404 }); },};The container calls http://my.kv/some-key and the outbound handler resolves it using the KV binding.
The ctx argument exposes containerId, which lets you interact with the container's own Durable Object from an outbound handler.
"get-state.do": async (request, env, ctx) => { const id = env.MY_CONTAINER.idFromString(ctx.containerId); const stub = env.MY_CONTAINER.get(id); // Assumes getStateForKey is defined on your DO return stub.getStateForKey(request.body);},Use outboundHandlers to define named handlers, then assign them to specific hosts at runtime using setOutboundByHost(). You can also apply a handler globally with setOutboundHandler().
export class MyContainer extends Container {}
MyContainer.outboundHandlers = { kvAccess: async (request, env, ctx) => { const key = new URL(request.url).pathname.slice(1); const value = await env.KV.get(key); return new Response(value ?? "", { status: value ? 200 : 404 }); },};Apply handlers to hosts programmatically from your Worker:
async setUpContainer(req, env) { const container = await env.MY_CONTAINER.getByName("my-instance");
// Give the container access to KV on a specific host during setup await container.setOutboundByHost("my.kv", "kvAccess"); await container.exec("node setup.js");
// Remove access once setup is complete await container.removeOutboundByHost("my.kv");}To configure outbound interception directly on ctx.container, use interceptOutboundHttp for a specific IP or CIDR range, or interceptAllOutboundHttp for all traffic. Both accept a WorkerEntrypoint.
import { WorkerEntrypoint } from "cloudflare:workers";
export class MyOutboundWorker extends WorkerEntrypoint { fetch(request) { // Inspect, modify, or deny the request before passing it on return fetch(request); }}
// Inside your Container DurableObjectthis.ctx.container.start({ enableInternet: false });const worker = this.ctx.exports.MyOutboundWorker({ props: {} });await this.ctx.container.interceptAllOutboundHttp(worker);You can call these methods before or after starting the container, and even while connections are open. In-flight TCP connections pick up the new handler automatically — no connections are dropped.
// Intercept a specific CIDR rangeawait this.ctx.container.interceptOutboundHttp("203.0.113.0/24", worker);// Intercept by hostnamethis.ctx.container.interceptOutboundHttp("foo.com", worker);
// Update the handler while the container is runningconst updated = this.ctx.exports.MyOutboundWorker({ props: { phase: "post-install" },});await this.ctx.container.interceptOutboundHttp("203.0.113.0/24", updated);The Container class will call these methods automatically when using the various functions shown above.
wrangler dev supports outbound interception. A sidecar process is spawned inside the container's network namespace. It applies TPROXY rules to route matching traffic to the local Workerd instance, mirroring production behavior.
- Control outbound traffic (Sandboxes) — Sandbox SDK API for outbound handlers
- Environment variables and secrets — Configure secrets and environment variables
- Durable Object interface — Full
ctx.containerAPI reference