Skip to content

bitbuilder-io/opencode-sandbox

 
 

Repository files navigation

OpenCode Sandbox Manager

A Cloudflare Worker that runs OpenCode inside Sandbox SDK containers, with subdomain-based routing to multiple isolated instances. Demonstrates programmatic command execution via execStream, git cloning, and directory backup/restore using R2.

How it works

Each sandbox gets its own subdomain. The Worker routes requests based on the first subdomain label:

Route Method Description
<id>.yourdomain.com/ GET OpenCode web UI
<id>.yourdomain.com/create POST Start the OpenCode server
<id>.yourdomain.com/run POST Execute a command (streams SSE via execStream)
<id>.yourdomain.com/gitClone POST Clone a git repo into the container
<id>.yourdomain.com/snapshot POST Back up a directory to R2
<id>.yourdomain.com/restore/:snapshotId POST Restore a directory from R2

The bare domain serves a static Alpine.js frontend that lets you interact with all of these.

Setup

1. Install dependencies

npm install

2. Configure your Anthropic API key

cp .dev.vars.example .dev.vars
# Edit .dev.vars and set ANTHROPIC_API_KEY

For production, set it as a secret:

wrangler secret put ANTHROPIC_API_KEY

3. Fill in your account ID and domain

In wrangler.jsonc, replace two placeholder values:

  • CLOUDFLARE_ACCOUNT_ID -- your Cloudflare account ID (find it in the dashboard URL or via wrangler whoami)
  • DOMAIN -- the domain you'll use for routing (e.g. yourdomain.com), plus update the routes entries to match

4. Create the R2 bucket and credentials

The snapshot/restore system stores backups in R2 using presigned URLs. You need an R2 bucket and API credentials.

# Create the bucket
wrangler r2 bucket create opencode-sandbox-snapshots

# Create an R2 API token in the Cloudflare dashboard:
#   R2 > Manage R2 API Tokens > Create API Token
# Then set both as secrets:
wrangler secret put R2_ACCESS_KEY_ID
wrangler secret put R2_SECRET_ACCESS_KEY

5. Set up wildcard DNS for subdomain routing

Subdomain routing requires a custom domain with a wildcard DNS record. Follow the Sandbox SDK production deployment guide to set this up.

In short: add a * CNAME record pointing to your Workers route. This takes a few minutes and only needs to be done once.

Update the routes in wrangler.jsonc to match your domain:

"routes": [
  { "pattern": "yourdomain.com/*", "zone_name": "yourdomain.com" },
  { "pattern": "*.yourdomain.com/*", "zone_name": "yourdomain.com" }
]

6. Deploy

npx wrangler deploy

For local development:

npm run dev

Note that subdomain routing won't work locally -- you'll hit the static frontend on localhost:8787 but can't route <id>.localhost:8787 to containers. Use wrangler deploy to test the full flow.

API examples

# Start a sandbox
curl -X POST https://my-sandbox.yourdomain.com/create

# Clone a repo
curl -X POST https://my-sandbox.yourdomain.com/gitClone \
  -H 'Content-Type: application/json' \
  -d '{"repo": "https://github.com/user/repo"}'

# Run a command (returns SSE stream)
curl -X POST https://my-sandbox.yourdomain.com/run \
  -H 'Content-Type: application/json' \
  -d '{"command": "ls -la /workspace"}'

# Snapshot a directory
curl -X POST https://my-sandbox.yourdomain.com/snapshot \
  -H 'Content-Type: application/json' \
  -d '{"dir": "/workspace"}'

# Restore a snapshot
curl -X POST https://my-sandbox.yourdomain.com/restore/<snapshot-id>

Try it: snapshot and restore walkthrough

Open the UI at your bare domain and follow these steps:

  1. Enter a sandbox ID (e.g. test) and click Create
  2. Clone a repo — paste https://github.com/cloudflare/workers-sdk into the Git clone field and click Clone
  3. Run ls /workspace to verify the files are there
  4. Click Snapshot — copy the returned snapshot ID
  5. Run rm -rf /workspace/* to delete everything
  6. Run ls /workspace again to confirm it's empty
  7. Paste the snapshot ID into the Restore field and click Restore
  8. Run ls /workspace one more time — the files are back

Tips

If you're putting container creation in a user's request path and want to avoid cold starts, check out cf-container-warm-pool. It maintains a pool of pre-warmed containers so the first request doesn't pay the startup cost.

Coming soon

  • Faster backups -- Backup and restore will get significantly faster and integrate directly with R2 without requiring separate API tokens.
  • Automatic snapshots -- On-start and on-stop hooks for automatic backup/restore, so sandbox state persists across container restarts without manual intervention.

Resources

About

Opencode Sandboxes on Cloudflare

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • HTML 54.4%
  • TypeScript 43.1%
  • Dockerfile 2.5%