出站处理程序让你使用受信任的代码拦截并修改来自沙箱的 HTTP 流量。
使用它们可以:
- 允许或拒绝特定的源站目标
- 安全地注入授权请求头或令牌
- 透明地重新路由流量
- 为出站流量添加自定义策略(例如拒绝特定 HTTP 请求)
- 连接到 Workers 绑定,如 KV、R2 与 Durable Objects
使用 enableInternet = false 默认阻止公共互联网访问:
import { Sandbox } from "@cloudflare/sandbox";
export class MySandbox extends Sandbox {
enableInternet = false;
}import { Sandbox } from "@cloudflare/sandbox";
export class MySandbox extends Sandbox {
enableInternet = false;
}当 enableInternet 为 false 时,只有你稍后在本页通过 allowedHosts 或出站处理程序显式允许的流量才能离开沙箱。仅端口 80、443 与 DNS 可用,且 DNS 查询使用 Cloudflare 的 DNS 服务器。
你可以使用 Sandbox 类上的 allowedHosts 与 deniedHosts 属性过滤出站流量。
设置 allowedHosts 后,它会成为默认拒绝的允许列表。不在列表中的任何主机或 IP 都会被拒绝,只有匹配的目标才能到达 outbound 或 outboundByHost 处理程序。
allowedHosts 与 deniedHosts 也支持简单的 glob 模式,其中 * 匹配任意字符序列。
默认情况下,Sandbox 允许互联网访问,你可以设置 deniedHosts 以禁止特定主机或 IP:
import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };
export class MySandbox extends Sandbox {
deniedHosts = ["some-nefarious-website.com", "141.101.64.0/18"];
}import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };
export class MySandbox extends Sandbox {
deniedHosts = ["some-nefarious-website.com", "141.101.64.0/18"];
}你也可以默认禁用互联网访问,但允许特定主机与 IP:
import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };
export class MySandbox extends Sandbox {
// default internet access to off unless overridden by 'allowedHosts' or outbound proxy
enableInternet = false;
// overrides enableInternet = false
allowedHosts = ["allowed.com"];
}import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };
export class MySandbox extends Sandbox {
// default internet access to off unless overridden by 'allowedHosts' or outbound proxy
enableInternet = false;
// overrides enableInternet = false
allowedHosts = ["allowed.com"];
}出站处理程序是可编程的出站代理,在与沙箱相同的机器上运行。它们可以访问所有 Workers 绑定。
使用 outbound 拦截所有出站 HTTP 与 HTTPS 流量:
import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };
export class MySandbox extends Sandbox {}
MySandbox.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);
};import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };
export class MySandbox extends Sandbox {}
MySandbox.outbound = async (
request: Request,
env: Env,
ctx: OutboundHandlerContext,
) => {
if (request.method !== "GET") {
console.log(`Blocked ${request.method} to ${request.url}`);
return new Response("Method Not Allowed", { status: 405 });
}
return fetch(request);
};使用 outboundByHost 将特定域名或 IP 地址映射到处理函数:
import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };
export class MySandbox extends Sandbox {}
MySandbox.outboundByHost = {
"my.worker": async (request, env, ctx) => {
// Run arbitrary Workers logic from this hostname
return await someWorkersFunction(request.body);
},
};import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };
export class MySandbox extends Sandbox {}
MySandbox.outboundByHost = {
"my.worker": async (
request: Request,
env: Env,
ctx: OutboundHandlerContext,
) => {
// Run arbitrary Workers logic from this hostname
return await someWorkersFunction(request.body);
},
};来自沙箱对 http://my.worker 的调用会调用处理程序,该处理程序在 Workers 运行时中运行,位于沙箱之外。
deniedHosts 与 allowedHosts 在任何出站处理程序之前评估。如果使用 allowedHosts,请在其中包含主机名,以便 outbound 或 outboundByHost 能够运行。outboundByHost 处理程序优先于通配的 outbound 处理程序。
因为出站处理程序在 Workers 运行时中运行——位于沙箱之外——它们可以持有沙箱本身永远看不到的密钥。沙箱发出普通 HTTP 请求,处理程序在将其转发到上游服务之前附加凭据。
export class MySandbox extends Sandbox {}
MySandbox.outboundByHost = {
"github.com": (request, env, ctx) => {
const requestWithAuth = new Request(request);
requestWithAuth.headers.set("x-auth-token", env.SECRET);
return fetch(requestWithAuth);
},
};export class MySandbox extends Sandbox {}
MySandbox.outboundByHost = {
"github.com": (request: Request, env: Env, ctx: OutboundHandlerContext) => {
const requestWithAuth = new Request(request);
requestWithAuth.headers.set("x-auth-token", env.SECRET);
return fetch(requestWithAuth);
},
};这对智能体工作负载尤其有用,因为你无法完全信任沙箱内运行的代码。使用此模式:
- 令牌不会暴露给沙箱。 密钥位于 Worker 环境中,永远不会传入沙箱。
- 无需在沙箱内轮换令牌。 在 Worker 环境中轮换密钥,每个请求都会立即使用新密钥。
- 按主机与按实例的规则。 将
outboundByHost与ctx.containerId结合,将凭据或权限限定到特定沙箱实例。
此处,ctx.containerId 从 KV 查找按实例的密钥:
export class MySandbox extends Sandbox {}
MySandbox.outboundByHost = {
"my-internal-vcs.dev": async (request, env, ctx) => {
const authKey = await env.KEYS.get(ctx.containerId);
const requestWithAuth = new Request(request);
requestWithAuth.headers.set("x-auth-token", authKey);
return fetch(requestWithAuth);
},
};export class MySandbox extends Sandbox {}
MySandbox.outboundByHost = {
"my-internal-vcs.dev": async (
request: Request,
env: Env,
ctx: OutboundHandlerContext,
) => {
const authKey = await env.KEYS.get(ctx.containerId);
const requestWithAuth = new Request(request);
requestWithAuth.headers.set("x-auth-token", authKey);
return fetch(requestWithAuth);
},
};沙箱默认拦截 HTTPS 流量——Sandbox 类上将 interceptHttps 设为 true。
当 HTTPS 拦截处于活动状态时,沙箱启动后会在 /etc/cloudflare/certs/cloudflare-containers-ca.crt 创建临时 CA 文件。
无论发行版如何,Sandbox 运行时都会尽力自动信任此 CA。启动时,它会检查各大 Linux 系列中常见的系统 CA 捆绑位置,并配置常见的 CA 环境变量,使 Node.js、curl、Python requests 与 Git 等运行时自动信任该证书。
出站处理程序仅拦截 HTTP 与 HTTPS 流量。端口 80 与 443 以外的流量永远不会通过 outbound 或 outboundByHost 路由。
如果设置 enableInternet = false,该流量会被拒绝。DNS 查询是唯一例外,但它们仅发往 Cloudflare 的 DNS 服务器。这可防止使用任意 DNS 目标进行数据外泄。
使用 outboundHandlers 定义命名处理程序,然后使用 setOutboundByHost() 在运行时将它们分配给特定主机。你也可以使用 setOutboundHandler() 全局应用处理程序。
你还可以使用 setOutboundByHosts()、setAllowedHosts()、setDeniedHosts()、allowHost()、denyHost()、removeAllowedHost() 与 removeDeniedHost() 管理运行时策略。
这使受信任的 Worker 能够持有凭据,而无需将其暴露给不受信任的沙箱:
import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };
export class MySandbox extends Sandbox {}
MySandbox.outboundHandlers = {
authenticatedGithub: async (request, env, ctx) => {
const githubToken = env.GITHUB_TOKEN;
return authenticateGitHttpsRequest(request, githubToken, ctx.containerId);
},
};import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };
export class MySandbox extends Sandbox {}
MySandbox.outboundHandlers = {
authenticatedGithub: async (
request: Request,
env: Env,
ctx: OutboundHandlerContext,
) => {
const githubToken = env.GITHUB_TOKEN;
return authenticateGitHttpsRequest(request, githubToken, ctx.containerId);
},
};从 Worker 以编程方式将处理程序应用于主机:
import { Sandbox, ContainerProxy, getSandbox } from "@cloudflare/sandbox";
export { ContainerProxy };
export default {
async fetch(request, env) {
const sandbox = getSandbox(env.Sandbox, "agent-session");
// Give the sandbox access to github.com during setup
await sandbox.setOutboundByHost("github.com", "authenticatedGithub");
await sandbox.exec("node setup.js");
// Remove access once setup is complete
await sandbox.removeOutboundByHost("github.com");
},
};import { Sandbox, ContainerProxy, getSandbox } from "@cloudflare/sandbox";
export { ContainerProxy };
export default {
async fetch(request: Request, env: Env) {
const sandbox = getSandbox(env.Sandbox, "agent-session");
// Give the sandbox access to github.com during setup
await sandbox.setOutboundByHost("github.com", "authenticatedGithub");
await sandbox.exec("node setup.js");
// Remove access once setup is complete
await sandbox.removeOutboundByHost("github.com");
},
};请求按此顺序评估:
- 首先检查
deniedHosts。匹配的主机或 IP 会立即被拒绝。 - 接下来检查
allowedHosts。设置后,不在列表中的任何主机或 IP 都会被拒绝。匹配的主机继续到出站处理程序;若未设置处理程序,则出口到公共互联网。 - 使用
setOutboundByHost()设置的实例级规则在类级outboundByHost规则之前检查。 - 按主机处理程序始终优先于通配处理程序,因此
outboundByHost在outbound之前运行。 - 使用
setOutboundHandler()设置的实例级处理程序在类级outbound处理程序之前检查。 - 如果没有处理程序匹配,当请求匹配了
allowedHosts或enableInternet = true时,仍可出口到公共互联网。否则会被拒绝。
wrangler dev 支持出站拦截。会在沙箱的网络命名空间中生成一个 sidecar 进程。它应用 TPROXY 规则,将匹配的流量路由到本地 Workerd 实例,以镜像生产行为。
- 连接到 Workers 绑定 — 从沙箱访问 KV、R2、Durable Objects 及其他绑定
- 处理出站流量(Containers) — 出站处理程序的 Container SDK API
- Sandbox 选项 — 配置沙箱行为
- 环境变量 — 配置密钥与环境变量