サンドボックス内で動いているサービスを、公開プレビュー URL で公開します。詳細は Preview URLs の概念 を参照してください。
受信した HTTP および WebSocket リクエストを、正しいサンドボックスコンテナへルーティングします。Worker の fetch ハンドラーの先頭で、アプリケーションロジックより前に呼び出してください。プレビュー URL のリクエストを自動で傍受して転送します。
proxyToSandbox(request: Request, env: Env): Promise<Response | null>パラメーター:
request-fetchハンドラーから渡される受信Requestオブジェクト。env- Sandbox バインディングを含むEnvオブジェクト。
戻り値: Promise<Response | null> — リクエストがプレビュー URL に一致し、サンドボックスへルーティングされた場合は Response、一致せずアプリケーションロジックで処理すべき場合は null。
この関数はリクエストのホスト名を調べ、公開済みポートのサブドメインパターン(例: 8080-sandbox-id-token.yourdomain.com)に一致するかを判定します。一致した場合、proxyToSandbox() は正しい Durable Object へリクエストをプロキシし、サンドボックスサービスが処理します。HTTP と WebSocket のアップグレードリクエストの両方に対応します。
import { proxyToSandbox, getSandbox } from "@cloudflare/sandbox";
export { Sandbox } from "@cloudflare/sandbox";
export default {
async fetch(request, env) {
// Always call proxyToSandbox first to handle preview URL requests
const proxyResponse = await proxyToSandbox(request, env);
if (proxyResponse) return proxyResponse;
// Your application routes
const sandbox = getSandbox(env.Sandbox, "my-sandbox");
// ...
return new Response("Not found", { status: 404 });
},
};import { proxyToSandbox, getSandbox } from "@cloudflare/sandbox";
export { Sandbox } from "@cloudflare/sandbox";
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// Always call proxyToSandbox first to handle preview URL requests
const proxyResponse = await proxyToSandbox(request, env);
if (proxyResponse) return proxyResponse;
// Your application routes
const sandbox = getSandbox(env.Sandbox, 'my-sandbox');
// ...
return new Response('Not found', { status: 404 });
}
};ポートを公開し、サンドボックス内で動いているサービスにアクセスするためのプレビュー URL を取得します。
const response = await sandbox.exposePort(port: number, options: ExposePortOptions): Promise<ExposePortResponse>パラメーター:
port- 公開するポート番号(1024-65535)options:hostname- Worker のドメイン名(例:'example.com')。https://8080-sandbox-abc123token.example.comのようなワイルドカードサブドメイン付きプレビュー URL を組み立てるために必須です。.workers.devドメインはワイルドカード DNS パターンに対応していないため使えません。name- ポートの分かりやすい名前(任意)token- プレビュー URL 用のカスタムトークン(任意)。1〜16 文字で、小文字(a-z)、数字(0-9)、ハイフン(-)、アンダースコア(_)のみです。指定しない場合、16 文字のランダムトークンが自動生成されます。
戻り値: port、url(プレビュー URL)、name を含む Promise<ExposePortResponse>
// Extract hostname from request
const { hostname } = new URL(request.url);
// Basic usage with auto-generated token
await sandbox.startProcess("python -m http.server 8000");
const exposed = await sandbox.exposePort(8000, { hostname });
console.log("Available at:", exposed.url);
// https://8000-sandbox-id-abc123random.yourdomain.com
// With custom token for stable URLs across restarts
const stable = await sandbox.exposePort(8080, {
hostname,
token: "my_service_v1", // 1-16 chars: a-z, 0-9, _
});
console.log("Stable URL:", stable.url);
// https://8080-sandbox-id-my_service_v1.yourdomain.com
// With custom token for stable URLs across deployments
await sandbox.startProcess("node api.js");
const api = await sandbox.exposePort(3000, {
hostname,
name: "api",
token: "prod-api-v1", // URL stays same across restarts
});
console.log("Stable API URL:", api.url);
// https://3000-sandbox-id-prod-api-v1.yourdomain.com
// Multiple services with custom tokens
await sandbox.startProcess("npm run dev");
const frontend = await sandbox.exposePort(5173, {
hostname,
name: "frontend",
token: "dev-ui",
});// Extract hostname from request
const { hostname } = new URL(request.url);
// Basic usage with auto-generated token
await sandbox.startProcess('python -m http.server 8000');
const exposed = await sandbox.exposePort(8000, { hostname });
console.log('Available at:', exposed.url);
// https://8000-sandbox-id-abc123random.yourdomain.com
// With custom token for stable URLs across restarts
const stable = await sandbox.exposePort(8080, {
hostname,
token: 'my_service_v1' // 1-16 chars: a-z, 0-9, _
});
console.log('Stable URL:', stable.url);
// https://8080-sandbox-id-my_service_v1.yourdomain.com
// With custom token for stable URLs across deployments
await sandbox.startProcess('node api.js');
const api = await sandbox.exposePort(3000, {
hostname,
name: 'api',
token: 'prod-api-v1' // URL stays same across restarts
});
console.log('Stable API URL:', api.url);
// https://3000-sandbox-id-prod-api-v1.yourdomain.com
// Multiple services with custom tokens
await sandbox.startProcess('npm run dev');
const frontend = await sandbox.exposePort(5173, {
hostname,
name: 'frontend',
token: 'dev-ui'
});カスタムトークンを使うと、コンテナの再起動やデプロイをまたいでプレビュー URL を一定にできます。次の場合に便利です。
- 本番環境 - ユーザーやチームと安定した URL を共有する
- 開発ワークフロー - ブックマークや連携を維持する
- CI/CD パイプライン - テストやデプロイスクリプトで一定の URL を参照する
トークンの要件:
- 長さは 1〜16 文字
- 小文字(a-z)、数字(0-9)、ハイフン(-)、アンダースコア(_)のみ
- サンドボックスごとに一意である必要があります(異なるポートで同じトークンは再利用できません)
// Production API with stable URL
const { url } = await sandbox.exposePort(8080, {
hostname: "api.example.com",
token: "v1-stable", // Always the same URL
});
// Error: Token collision prevention
await sandbox.exposePort(8081, { hostname, token: "v1-stable" });
// Throws: Token 'v1-stable' is already in use by port 8080
// Success: Re-exposing same port with same token (idempotent)
await sandbox.exposePort(8080, { hostname, token: "v1-stable" });
// Works - same port, same token// Production API with stable URL
const { url } = await sandbox.exposePort(8080, {
hostname: 'api.example.com',
token: 'v1-stable' // Always the same URL
});
// Error: Token collision prevention
await sandbox.exposePort(8081, { hostname, token: 'v1-stable' });
// Throws: Token 'v1-stable' is already in use by port 8080
// Success: Re-exposing same port with same token (idempotent)
await sandbox.exposePort(8080, { hostname, token: 'v1-stable' });
// Works - same port, same tokenトークンが、特定の公開済みポートへのアクセスを許可されているかを検証します。カスタム認証やルーティングロジックに使えます。
const isValid = await sandbox.validatePortToken(port: number, token: string): Promise<boolean>パラメーター:
port- 確認するポート番号token- 検証するトークン
戻り値: Promise<boolean> - トークンがそのポートで有効なら true、それ以外は false
// Custom validation in your Worker
export default {
async fetch(request, env) {
const url = new URL(request.url);
// Extract token from custom header or query param
const customToken = request.headers.get("x-access-token");
if (customToken) {
const sandbox = getSandbox(env.Sandbox, "my-sandbox");
const isValid = await sandbox.validatePortToken(8080, customToken);
if (!isValid) {
return new Response("Invalid token", { status: 403 });
}
}
// Handle preview URL routing
const proxyResponse = await proxyToSandbox(request, env);
if (proxyResponse) return proxyResponse;
// Your application routes
return new Response("Not found", { status: 404 });
},
};// Custom validation in your Worker
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
// Extract token from custom header or query param
const customToken = request.headers.get('x-access-token');
if (customToken) {
const sandbox = getSandbox(env.Sandbox, 'my-sandbox');
const isValid = await sandbox.validatePortToken(8080, customToken);
if (!isValid) {
return new Response('Invalid token', { status: 403 });
}
}
// Handle preview URL routing
const proxyResponse = await proxyToSandbox(request, env);
if (proxyResponse) return proxyResponse;
// Your application routes
return new Response('Not found', { status: 404 });
}
};公開済みポートを解除し、そのプレビュー URL を閉じます。
await sandbox.unexposePort(port: number): Promise<void>パラメーター:
port- 公開を解除するポート番号
await sandbox.unexposePort(8000);await sandbox.unexposePort(8000);現在公開されているすべてのポートの情報を取得します。
const response = await sandbox.getExposedPorts(): Promise<GetExposedPortsResponse>戻り値: ports 配列(port、url、name を含む)を持つ Promise<GetExposedPortsResponse>
const { ports } = await sandbox.getExposedPorts();
for (const port of ports) {
console.log(`${port.name || port.port}: ${port.url}`);
}const { ports } = await sandbox.getExposedPorts();
for (const port of ports) {
console.log(`${port.name || port.port}: ${port.url}`);
}サンドボックス内で動いている WebSocket サーバーに接続します。Worker がサンドボックス内のサービスと WebSocket 接続を確立する必要があるときに使います。
よくある用途:
- カスタム認証や認可付きで、受信した WebSocket アップグレードリクエストをルーティングする
- Worker から接続し、サンドボックスサービスからリアルタイムデータを取得する
公開プレビュー URL で WebSocket サービスを公開する場合は、代わりに exposePort() と proxyToSandbox() を使います。例は WebSocket 接続ガイド を参照してください。
const response = await sandbox.wsConnect(request: Request, port: number): Promise<Response>パラメーター:
request- 受信した WebSocket アップグレードリクエストport- ポート番号(1024-65535、3000 を除く)
戻り値: Promise<Response> - 接続を確立する WebSocket レスポンス
import { getSandbox } from "@cloudflare/sandbox";
export { Sandbox } from "@cloudflare/sandbox";
export default {
async fetch(request, env) {
if (request.headers.get("Upgrade")?.toLowerCase() === "websocket") {
const sandbox = getSandbox(env.Sandbox, "my-sandbox");
return await sandbox.wsConnect(request, 8080);
}
return new Response("WebSocket endpoint", { status: 200 });
},
};import { getSandbox } from "@cloudflare/sandbox";
export { Sandbox } from "@cloudflare/sandbox";
export default {
async fetch(request: Request, env: Env): Promise<Response> {
if (request.headers.get('Upgrade')?.toLowerCase() === 'websocket') {
const sandbox = getSandbox(env.Sandbox, 'my-sandbox');
return await sandbox.wsConnect(request, 8080);
}
return new Response('WebSocket endpoint', { status: 200 });
}
};- Preview URLs の概念 - プレビュー URL の仕組み
- サービス公開ガイド - サービスの起動、ポート公開、リクエストルーティングの一連の流れ
- WebSocket 接続ガイド - プレビュー URL 経由の WebSocket ルーティング
- Commands API - バックグラウンドプロセスの起動
- Tunnels API - 手早い開発向けの設定不要な
*.trycloudflare.comURL