mcpField
C
cloudflare-sandbox

cloudflare-sandbox

github.com/jackspaceクラウド・DevOps1641 回インストール12 週間前に更新
リポジトリ

cloudflare-sandbox について

cloudflare-sandbox は、Workers で Cloudflare Sandboxes SDK を使うためのスキルガイドです。コンテナ実行、セッション、ファイル操作に加え、コンテナの一時性とデータの永続化方法を説明します。

主な機能

  1. 01コンテナ内でのコマンド実行
  2. 02シェルセッションと作業ディレクトリの管理
  3. 03ファイル操作と Git リポジトリのチェックアウト
  4. 04コードコンテキストとバックグラウンドプロセスの実行
  5. 05コンテナのライフサイクルとデータ永続化の扱い

活用シーン

  1. 01コーディングエージェント向けの一時実行環境
  2. 02同一セッションでの複数コマンド実行
  3. 03ビルド、テスト、データ処理の実行
  4. 04コールドスタートと外部ストレージへのバックアップ対応

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/jackspace/claudeskillz --skill cloudflare-sandbox

インストール後、Claude Code で/cloudflare-sandboxを入力して読み込まれたか確認します。

同梱ファイルREADME.mdSKILL.json

詳細

Cloudflare Sandboxes SDK

ステータス:本番環境対応(オープンベータ) 最終更新日:2025-10-29 依存関係:cloudflare-worker-base、cloudflare-durable-objects(理解を深めるために推奨) 最新バージョン:@cloudflare/[email protected]、Docker イメージ:cloudflare/sandbox:0.4.12


クイックスタート(15 分)

1. SDK をインストールして Wrangler をセットアップする
npm install @cloudflare/sandbox@latest

wrangler.jsonc:

{
  "name": "my-sandbox-worker",
  "main": "src/index.ts",
  "compatibility_flags": ["nodejs_compat"],
  "containers": [{
    "class_name": "Sandbox",
    "image": "cloudflare/sandbox:0.4.12",
    "instance_type": "lite"
  }],
  "durable_objects": {
    "bindings": [{
      "class_name": "Sandbox",
      "name": "Sandbox"
    }]
  },
  "migrations": [{
    "tag": "v1",
    "new_sqlite_classes": ["Sandbox"]
  }]
}

これが重要な理由:

  • nodejs_compat は、SDK が必要とする Node.js API を有効にします
  • containers は Ubuntu コンテナイメージを定義します
  • durable_objects バインディングは永続的なルーティングを有効にします
  • migrations は Sandbox クラスを登録します
2. 最初の Sandbox Worker を作成する
import { getSandbox, type Sandbox } from '@cloudflare/sandbox';
export { Sandbox } from '@cloudflare/sandbox';

type Env = {
  Sandbox: DurableObjectNamespace<Sandbox>;
};

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // Get sandbox instance (creates if doesn't exist)
    const sandbox = getSandbox(env.Sandbox, 'my-first-sandbox');

    // Execute Python code
    const result = await sandbox.exec('python3 -c "print(2 + 2)"');

    return Response.json({
      output: result.stdout,
      success: result.success,
      exitCode: result.exitCode
    });
  }
};

重要:

  • Worker から @cloudflare/sandbox の { Sandbox } を必ずエクスポートしてください
  • Sandbox ID によってルーティング先が決まります(同じ ID = 同じコンテナ)
  • 最初のリクエストでコンテナが作成されます(コールドスタートに約 2~3 分)
  • 2 回目以降のリクエストは高速です(1 秒未満)
3. デプロイしてテストする
npm run deploy
curl https://your-worker.workers.dev

出力例:

{
  "output": "4\n",
  "success": true,
  "exitCode": 0
}

アーキテクチャ(3 層モデルを理解する)

Sandboxes の仕組み
┌─────────────────────────────────────────┐
│  Your Worker (Layer 1)                  │
│  - Handles HTTP requests                │
│  - Calls getSandbox()                   │
│  - Uses sandbox.exec(), writeFile(), etc│
└──────────────┬──────────────────────────┘
               │ RPC via Durable Object
┌──────────────▼──────────────────────────┐
│  Durable Object (Layer 2)               │
│  - Routes by sandbox ID                 │
│  - Maintains persistent identity        │
│  - Geographic stickiness                │
└──────────────┬──────────────────────────┘
               │ Container API
┌──────────────▼──────────────────────────┐
│  Ubuntu Container (Layer 3)             │
│  - Full Linux environment               │
│  - Python 3.11, Node 20, Git, etc.      │
│  - Filesystem: /workspace, /tmp, /home  │
│  - Process isolation (VM-based)         │
└─────────────────────────────────────────┘

重要なポイント:Workers は API ロジックを処理し(高速)、Durable Objects はリクエストをルーティングし(永続的な ID)、コンテナはコードを実行します(フル機能)。


コンテナのライフサイクルに関する重要事項(最も重要なセクション!)

コンテナの状態
┌─────────┐  First request  ┌────────┐  ~10 min idle  ┌──────┐
│ Not     │ ───────────────>│ Active │ ─────────────> │ Idle │
│ Created │                 │        │                │      │
└─────────┘                 └───┬────┘                └──┬───┘
                                │ ^                      │
                                │ │ New request          │
                                │ └──────────────────────┘
                                │                         │
                                ▼                         ▼
                            Files persist          ALL FILES DELETED
                            Processes run          ALL PROCESSES KILLED
                            State maintained       ALL STATE RESET
最大の注意点:デフォルトでは一時的

コンテナがアクティブな間(最後のリクエストから約 10 分間):

  • ✅ /workspace、/tmp、/home 内のファイルは保持されます
  • ✅ バックグラウンドプロセスは実行を続けます
  • ✅ シェル環境変数は維持されます
  • ✅ セッションの作業ディレクトリは保持されます

コンテナがアイドル状態になると(非アクティブになった後):

  • ❌ すべてのファイルが削除されます(ファイルシステム全体がリセットされます)
  • ❌ すべてのプロセスが終了します
  • ❌ すべてのシェル状態が失われます
  • ⚠️ 次のリクエストでは新しいコンテナがゼロから作成されます

これは従来のサーバーとは異なります。Sandbox は設計上、一時的なものです。

永続性への対応

重要なデータの場合:外部ストレージを使用する

// Save to R2 before container goes idle
await sandbox.writeFile('/workspace/data.txt', content);
const fileData = await sandbox.readFile('/workspace/data.txt');
await env.R2.put('backup/data.txt', fileData);

// Restore on next request
const restored = await env.R2.get('backup/data.txt');
if (restored) {
  await sandbox.writeFile('/workspace/data.txt', await restored.text());
}

ビルド成果物の場合:一時的なものとして扱うか、キャッシュを使用する

// Check if setup needed (handles cold starts)
const exists = await sandbox.readdir('/workspace/project').catch(() => null);
if (!exists) {
  await sandbox.gitCheckout(repoUrl, '/workspace/project');
  await sandbox.exec('npm install', { cwd: '/workspace/project' });
}
// Now safe to run build
await sandbox.exec('npm run build', { cwd: '/workspace/project' });

セッション管理(チャットエージェントのゲームチェンジャー)

セッションとは?

セッションは、1 つの Sandbox 内のbash シェルコンテキストです。ターミナルのタブのようなものです。

主な特性:

  • 各セッションは個別の作業ディレクトリを持ちます
  • セッション間で同じファイルシステムを共有します
  • 同じセッション内では、コマンドをまたいで作業ディレクトリが保持されます
  • 複数ステップのワークフローに最適です
パターン:チャットベースのコーディングエージェント
type ConversationState = {
  sandboxId: string;
  sessionId: string;
};

// First message: Create sandbox and session
const sandboxId = `user-${userId}`;
const sandbox = getSandbox(env.Sandbox, sandboxId);
const sessionId = await sandbox.createSession();

// Store in conversation state (database, KV, etc.)
await env.KV.put(`conversation:${conversationId}`, JSON.stringify({
  sandboxId,
  sessionId
}));

// Later messages: Reuse same session
const state = await env.KV.get(`conversation:${conversationId}`);
const { sandboxId, sessionId } = JSON.parse(state);
const sandbox = getSandbox(env.Sandbox, sandboxId);

// Commands run in same context
await sandbox.exec('cd /workspace/project', { session: sessionId });
await sandbox.exec('ls -la', { session: sessionId }); // Still in /workspace/project
await sandbox.exec('git status', { session: sessionId }); // Still in /workspace/project
セッションを使わない場合(よくある間違い)
// ❌ WRONG: Each command runs in separate session
await sandbox.exec('cd /workspace/project');
await sandbox.exec('ls'); // NOT in /workspace/project (different session)
パターン:並列実行
const session1 = await sandbox.createSession();
const session2 = await sandbox.createSession();

// Run different tasks simultaneously
await Promise.all([
  sandbox.exec('python train_model.py', { session: session1 }),
  sandbox.exec('node generate_reports.js', { session: session2 })
]);

Sandbox の命名戦略

ユーザーごとの Sandbox(永続的なワークスペース)
const sandbox = getSandbox(env.Sandbox, `user-${userId}`);

メリット:アクティブに使用している間(アイドル時間 10 分)、ユーザーの作業が保持されます デメリット:地理的な固定(最初のリクエストによって場所が決まります) 用途:インタラクティブなノートブック、IDE、永続的なワークスペース

セッションごとの Sandbox(毎回新規)
const sandboxId = `session-${Date.now()}-${crypto.randomUUID()}`;
const sandbox = getSandbox(env.Sandbox, sandboxId);
// Always destroy after use
await sandbox.destroy();

メリット:クリーンな環境で、状態が混在しません デメリット:リクエスト間の永続性がありません 用途:単発のコード実行、CI/CD、テスト

タスクごとの Sandbox(冪等で追跡可能)
const sandbox = getSandbox(env.Sandbox, `build-${repoName}-${commitSha}`);

メリット:再現可能、デバッグ可能、キャッシュ可能 デメリット:明示的なクリーンアップ戦略が必要です 用途:ビルドシステム、データパイプライン、自動化されたワークフロー


コア API リファレンス

Sandbox の取得
import { getSandbox } from '@cloudflare/sandbox';

const sandbox = getSandbox(env.Sandbox, 'unique-sandbox-id');
// Creates new sandbox if doesn't exist, or gets existing one
コマンドの実行
// Basic execution
const result = await sandbox.exec('python3 script.py');
console.log(result.stdout);   // Standard output
console.log(result.stderr);   // Standard error
console.log(result.exitCode); // Exit code (0 = success)
console.log(result.success);  // Boolean (exitCode === 0)

// With options
const result = await sandbox.exec('npm install', {
  cwd: '/workspace/project',        // Working directory
  timeout: 120000,                   // Timeout in ms (default: 30s)
  session: sessionId,                // Session ID
  env: { NODE_ENV: 'production' }   // Environment variables
});

// Always check exit codes!
if (!result.success) {
  throw new Error(`Command failed: ${result.stderr}`);
}
ファイル操作
// Write file
await sandbox.writeFile('/workspace/data.txt', 'content');

// Read file
const content = await sandbox.readFile('/workspace/data.txt');

// Create directory
await sandbox.mkdir('/workspace/project', { recursive: true });

// List directory
const files = await sandbox.readdir('/workspace');
console.log(files); // ['data.txt', 'project']

// Delete file/directory
await sandbox.rm('/workspace/data.txt');
await sandbox.rm('/workspace/project', { recursive: true });
Git 操作
// Clone repository (optimized, faster than exec('git clone'))
await sandbox.gitCheckout(
  'https://github.com/user/repo',
  '/workspace/repo'
);

// Now use standard git commands
await sandbox.exec('git status', { cwd: '/workspace/repo' });
await sandbox.exec('git diff', { cwd: '/workspace/repo' });
コードインタープリター(Jupyter のような環境)
// Create Python context
const ctx = await sandbox.createCodeContext({ language: 'python' });

// Execute code - last expression auto-returned
const result = await sandbox.runCode(`
import pandas as pd
df = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})
df['a'].sum()  # This value is automatically returned
`, { context: ctx });

console.log(result.results[0].text); // "6"
console.log(result.logs); // Output from print() statements
console.log(result.error); // Any errors
バックグラウンドプロセス
// Start long-running process
const proc = await sandbox.spawn('python server.py');
console.log(proc.pid);

// Check if still running
const running = await sandbox.isProcessRunning(proc.pid);

// Kill process
await sandbox.killProcess(proc.pid);
クリーンアップ
// Destroy sandbox permanently
await sandbox.destroy();
// All files deleted, container removed, cannot be recovered

重要なルール

常に実施すること

✅ 終了コードを確認する - if (!result.success) { handle error } ✅ 複数ステップのワークフローではセッションを使用する - 作業ディレクトリを保持します ✅ コールドスタートに対応する - ファイルがあると決めつけず、存在するか確認します ✅ タイムアウトを設定する - 長時間の処理でハングするのを防ぎます ✅ 一時的なサンドボックスを破棄する - 一時的なサンドボックスやセッションベースのサンドボックスをクリーンアップします ✅ 永続化には外部ストレージを使用する - 重要なデータには R2/KV/D1 を使用します ✅ ユーザー入力を検証する - コマンドインジェクションを防ぐため、exec() の前にサニタイズします ✅ Sandbox クラスをエクスポートする - export { Sandbox } from '@cloudflare/sandbox'

絶対にしないこと

❌ アイドル状態の後もファイルが保持されると思い込む - コンテナは約 10 分後にリセットされます ❌ 終了コードを無視する - 必ず result.success または result.exitCode を確認します ❌ セッションを使わずにコマンドを連結する - cd /dir の後に ls を実行しても機能しません ❌ サニタイズしていないユーザー入力を実行する - コードインタープリターを使用するか、十分に検証します ❌ nodejs_compat フラグを忘れる - wrangler.jsonc で必須です ❌ マイグレーションを省略する - Durable Objects にはマイグレーションエントリーが必要です ❌ プレビュー URL に .workers.dev を使用する - カスタムドメインが必要です ❌ サンドボックスを無制限に作成する - リークを防ぐため、一時的なものは破棄します


既知の問題の予防

このスキルは、文書化されている 10 件の問題を防ぎます。

問題 #1: nodejs_compat フラグがない

エラー: ReferenceError: fetch is not defined または Buffer is not defined ソース: https://developers.cloudflare.com/sandbox/get-started/ 発生する理由: SDK は、標準の Workers では利用できない Node.js API を必要とします 予防策: wrangler.jsonc に "compatibility_flags": ["nodejs_compat"] を追加します

問題 #2: マイグレーションがない

エラー: Error: Class 'Sandbox' not found ソース: https://developers.cloudflare.com/durable-objects/ 発生する理由: Durable Objects はマイグレーションを介して登録する必要があります 予防策: wrangler.jsonc に migrations 配列を含めます

問題 #3: ファイルの永続性を前提とする

エラー: 非アクティブ状態の後にファイルが消える ソース: https://developers.cloudflare.com/sandbox/concepts/sandboxes/ 発生する理由: コンテナは約 10 分後にアイドル状態になり、すべての状態がリセットされます 予防策: 外部ストレージ(R2/KV)を使用するか、リクエストごとにファイルの存在を確認します

問題 #4: セッションのディレクトリに関する混乱

エラー: コマンドが間違ったディレクトリで実行される ソース: https://developers.cloudflare.com/sandbox/concepts/sessions/ 発生する理由: 明示的に指定しない限り、exec() は毎回新しいセッションを使用します 予防策: createSession() でセッションを作成し、関連するすべてのコマンドに渡します

問題 #5: 終了コードを無視する

エラー: コマンドが失敗したのに成功したと思い込む ソース: シェルのベストプラクティス 発生する理由: result.success または result.exitCode を確認していません 予防策: 必ず確認します: if (!result.success) throw new Error(result.stderr)

問題 #6: コールドスタートへの未対応

エラー: 依存関係がインストールされていないため、コマンドが失敗する ソース: https://developers.cloudflare.com/sandbox/concepts/sandboxes/ 発生する理由: アイドル期間の後にコンテナがリセットされます 予防策: コマンドを実行する前に、セットアップが必要か確認します

問題 #7: Docker が起動していない(ローカル開発)

エラー: ローカル開発中に Failed to build container ソース: https://developers.cloudflare.com/sandbox/get-started/ 発生する理由: ローカル開発には Docker デーモンが必要です 予防策: npm run dev の前に Docker Desktop が起動していることを確認します

問題 #8: バージョンの不一致(パッケージと Docker イメージ)

エラー: API メソッドが利用できない、または予期しない動作をする ソース: GitHub issues 発生する理由: npm パッケージのバージョンと Docker イメージのバージョンが一致していません 予防策: @cloudflare/sandbox パッケージと cloudflare/sandbox イメージのバージョンを一致させます

問題 #9: 一時的なサンドボックスをクリーンアップしない

エラー: リソースの枯渇、予期しないコスト ソース: リソース管理のベストプラクティス 発生する理由: サンドボックスを破棄せずに作成しています 予防策: 一時的なサンドボックスでは、finally ブロック内で await sandbox.destroy() を実行します

Issue #10:コマンドインジェクションの脆弱性

エラー:サニタイズされていないユーザー入力によるセキュリティ侵害 原因:セキュリティのベストプラクティス 発生理由:ユーザー入力を直接 exec() に渡しているためです 防止策:コードインタープリター API を使用するか、入力を十分に検証・サニタイズします


設定ファイルのリファレンス

wrangler.jsonc(完全な例)
{
  "name": "my-sandbox-app",
  "main": "src/index.ts",
  "compatibility_date": "2025-10-29",
  "compatibility_flags": ["nodejs_compat"],

  "containers": [{
    "class_name": "Sandbox",
    "image": "cloudflare/sandbox:0.4.12",
    "instance_type": "lite"
  }],

  "durable_objects": {
    "bindings": [{
      "class_name": "Sandbox",
      "name": "Sandbox"
    }]
  },

  "migrations": [{
    "tag": "v1",
    "new_sqlite_classes": ["Sandbox"]
  }],

  "env": {
    "ANTHROPIC_API_KEY": {
      "description": "Optional: For AI features"
    }
  },

  "observability": {
    "enabled": true
  }
}

これらの設定の理由:

  • nodejs_compat:SDK の動作に必要です
  • containers.image:特定のバージョンを指定することで、一貫性を確保します
  • instance_type: "lite":最小のインスタンスです。より多くのリソースが必要な場合は "large" に変更します
  • migrations:Sandbox Durable Object クラスを登録します
  • observability:デバッグ用のロギングを有効にします
Dockerfile(任意 — ローカル開発用)

ベースイメージを拡張する場合にのみ必要です。

FROM cloudflare/sandbox:0.4.12

# Install additional tools
RUN apt-get update && apt-get install -y \
    ffmpeg \
    imagemagick \
    && rm -rf /var/lib/apt/lists/*

# Expose port for preview URLs (local dev only)
EXPOSE 8080

よくあるパターン

パターン 1:単発のコード実行
export default {
  async fetch(request: Request, env: Env) {
    const { code, language } = await request.json();

    // Create ephemeral sandbox
    const sandboxId = `exec-${Date.now()}-${crypto.randomUUID()}`;
    const sandbox = getSandbox(env.Sandbox, sandboxId);

    try {
      // Create code context
      const ctx = await sandbox.createCodeContext({ language });

      // Execute code safely
      const result = await sandbox.runCode(code, {
        context: ctx,
        timeout: 10000
      });

      return Response.json({
        result: result.results?.[0]?.text,
        logs: result.logs,
        error: result.error
      });
    } finally {
      // Always cleanup
      await sandbox.destroy();
    }
  }
};

使用する場面:コード実行用 API エンドポイント、コードプレイグラウンド、学習プラットフォーム

パターン 2:ユーザー用の永続的なワークスペース
export default {
  async fetch(request: Request, env: Env) {
    const userId = request.headers.get('X-User-ID');
    const { command, sessionId: existingSession } = await request.json();

    // User-specific sandbox (persists while active)
    const sandbox = getSandbox(env.Sandbox, `user-${userId}`);

    // Get or create session
    let sessionId = existingSession;
    if (!sessionId) {
      sessionId = await sandbox.createSession();
    }

    // Execute command in persistent context
    const result = await sandbox.exec(command, {
      session: sessionId,
      timeout: 30000
    });

    return Response.json({
      sessionId, // Return for next request
      output: result.stdout,
      error: result.stderr,
      success: result.success
    });
  }
};

使用する場面:対話型コーディング環境、ノートブック、IDE、開発ワークスペース

パターン 3:CI/CD ビルドパイプライン
async function runBuild(repoUrl: string, commit: string, env: Env) {
  const sandboxId = `build-${repoUrl.split('/').pop()}-${commit}`;
  const sandbox = getSandbox(env.Sandbox, sandboxId);

  try {
    // Clone repository
    await sandbox.gitCheckout(repoUrl, '/workspace/repo');

    // Checkout specific commit
    await sandbox.exec(`git checkout ${commit}`, {
      cwd: '/workspace/repo'
    });

    // Install dependencies
    const install = await sandbox.exec('npm install', {
      cwd: '/workspace/repo',
      timeout: 180000 // 3 minutes
    });

    if (!install.success) {
      throw new Error(`Install failed: ${install.stderr}`);
    }

    // Run build
    const build = await sandbox.exec('npm run build', {
      cwd: '/workspace/repo',
      timeout: 300000 // 5 minutes
    });

    if (!build.success) {
      throw new Error(`Build failed: ${build.stderr}`);
    }

    // Save artifacts to R2
    const dist = await sandbox.exec('tar -czf dist.tar.gz dist', {
      cwd: '/workspace/repo'
    });
    const artifact = await sandbox.readFile('/workspace/repo/dist.tar.gz');
    await env.R2.put(`builds/${commit}.tar.gz`, artifact);

    return { success: true, artifactKey: `builds/${commit}.tar.gz` };
  } finally {
    // Optional: Keep sandbox for debugging or destroy
    // await sandbox.destroy();
  }
}

使用する場面:ビルドシステム、テストパイプライン、デプロイの自動化

パターン 4:Claude Code を使用する AI エージェント
async function runClaudeCodeOnRepo(
  repoUrl: string,
  task: string,
  env: Env
): Promise<{ diff: string; logs: string }> {
  const sandboxId = `claude-${Date.now()}`;
  const sandbox = getSandbox(env.Sandbox, sandboxId);

  try {
    // Clone repository
    await sandbox.gitCheckout(repoUrl, '/workspace/repo');

    // Run Claude Code CLI with secure environment injection
    // ⚠️ SECURITY: Use env option instead of shell export to prevent key exposure in logs
    const result = await sandbox.exec(
      `claude -p "${task}" --permission-mode acceptEdits`,
      {
        cwd: '/workspace/repo',
        timeout: 300000, // 5 minutes
        env: {
          ANTHROPIC_API_KEY: env.ANTHROPIC_API_KEY
        }
      }
    );

    // Get diff of changes
    const diff = await sandbox.exec('git diff', {
      cwd: '/workspace/repo'
    });

    return {
      diff: diff.stdout,
      logs: result.stdout
    };
  } finally {
    await sandbox.destroy();
  }
}

使用する場面:コードの自動リファクタリング、コード生成、AI を活用した開発


同梱リソースの使用

スクリプト(scripts/)
  • setup-sandbox-binding.sh - 対話形式での wrangler.jsonc 設定
  • test-sandbox.ts - Sandbox のセットアップをテストする検証スクリプト

使用例:

# Setup wrangler config
./scripts/setup-sandbox-binding.sh

# Test sandbox
npx tsx scripts/test-sandbox.ts
リファレンス(references/)
  • references/persistence-guide.md - コンテナのライフサイクルと永続性の詳細な解説
  • references/session-management.md - 高度なセッションパターンとベストプラクティス
  • references/common-errors.md - 解決策を含むエラーの完全な一覧
  • references/naming-strategies.md - さまざまなユースケースに応じた Sandbox ID の選び方

Claude がこれらを読み込むタイミング:

  • 状態の問題やコールドスタートをデバッグするときは、persistence-guide.md を読み込みます
  • 複数ステップのワークフローやチャットエージェントを構築するときは、session-management.md を読み込みます
  • 特定のエラーが発生したときは、common-errors.md を読み込みます
  • Sandbox のアーキテクチャを設計するときは、naming-strategies.md を読み込みます

高度なトピック

地理的な分散

Sandbox ID への最初のリクエストによって、その地理的な配置場所が決まります(Durable Objects 経由)。

グローバルアプリの場合:

// Option 1: Multiple sandboxes per user (better latency)
const region = request.cf?.colo || 'default';
const sandbox = getSandbox(env.Sandbox, `user-${userId}-${region}`);

// Option 2: Single sandbox (simpler, higher latency for distant users)
const sandbox = getSandbox(env.Sandbox, `user-${userId}`);
エラー処理の戦略
async function safeSandboxExec(
  sandbox: Sandbox,
  cmd: string,
  options?: any
) {
  try {
    const result = await sandbox.exec(cmd, {
      ...options,
      timeout: options?.timeout || 30000
    });

    if (!result.success) {
      console.error(`Command failed: ${cmd}`, {
        exitCode: result.exitCode,
        stderr: result.stderr
      });

      return {
        success: false,
        error: result.stderr,
        exitCode: result.exitCode
      };
    }

    return {
      success: true,
      output: result.stdout,
      exitCode: 0
    };
  } catch (error) {
    console.error(`Sandbox error:`, error);
    return {
      success: false,
      error: error.message,
      exitCode: -1
    };
  }
}
セキュリティの強化
// Input validation
function sanitizeCommand(input: string): string {
  const dangerous = ['rm -rf', '$(', '`', '&&', '||', ';', '|'];
  for (const pattern of dangerous) {
    if (input.includes(pattern)) {
      throw new Error(`Dangerous pattern detected: ${pattern}`);
    }
  }
  return input;
}

// Use code interpreter instead of direct exec for untrusted code
async function executeUntrustedCode(code: string, sandbox: Sandbox) {
  const ctx = await sandbox.createCodeContext({ language: 'python' });
  return await sandbox.runCode(code, { context: ctx, timeout: 10000 });
}

依存関係

必須:

  • @cloudflare/[email protected] - Sandbox SDK
  • wrangler@latest - デプロイ用 CLI
  • Docker Desktop - ローカル開発専用

任意:

  • @anthropic-ai/sdk - AI 機能用
  • @cloudflare/workers-types - TypeScript 型定義

公式ドキュメント


パッケージのバージョン(2025-10-29 に検証済み)

{
  "dependencies": {
    "@cloudflare/sandbox": "^0.4.12"
  },
  "devDependencies": {
    "wrangler": "^3.80.0",
    "@cloudflare/workers-types": "^4.20241106.0"
  }
}

Docker イメージ:cloudflare/sandbox:0.4.12


本番環境での例

このスキルは、Cloudflare の公式チュートリアルに基づいています:


トラブルシューティング

問題:「Class 'Sandbox' not found」

解決策:wrangler.jsonc に migrations を追加し、Worker 内に export { Sandbox } があることを確認します

問題:時間が経つとファイルが消える

解決策:コンテナは約10分後にアイドル状態になります。永続化にはR2/KVを使用するか、環境を再構築してください。

問題:コマンドが間違ったディレクトリで実行される

解決策:createSession()でセッションを作成し、関連するすべてのコマンドにsessionIdを渡してください。

問題:ローカル開発中にDockerエラーが発生する

解決策:npm run devを実行する前に、Docker Desktopが起動していることを確認してください。

問題:「fetch is not defined」

解決策:wrangler.jsoncに"compatibility_flags": ["nodejs_compat"]を追加してください。


セットアップ完了チェックリスト

  • npm install @cloudflare/sandbox@latest
  • compatibility_flagsにnodejs_compatを追加する
  • 正しいイメージバージョンを指定してコンテナ設定を追加する
  • Durable Objectsのバインディングを追加する
  • Sandboxクラスのマイグレーションを追加する
  • WorkerでSandboxクラスをエクスポートする:export { Sandbox } from '@cloudflare/sandbox'
  • Docker Desktopが起動している(ローカル開発のみ)
  • シンプルなexecコマンドでテストする
  • 終了コードが確認されていることを検証する
  • 一時的なサンドボックスのクリーンアップを実装する
  • コールドスタート時の動作をテストする

質問や問題がありますか?

  1. 個別のエラー解決策については、references/common-errors.mdを確認してください。
  2. wrangler.jsoncの設定ですべての手順を確認してください。
  3. 公式ドキュメントを確認してください:https://developers.cloudflare.com/sandbox/
  4. ローカル開発用にDockerが起動していることを確認してください。
  5. パッケージのバージョンがDockerイメージのバージョンと一致していることを確認してください。

コメント