Select with provider: cloudflare (alias cf) to run Linux commands inside
Cloudflare Containers behind a Cloudflare Worker. This is a delegated-run
provider: the local CLI builds a repo archive, owns the local lease claim,
renders the command, and streams timing output, while the Worker runner creates
the container, receives the upload, executes the command, and tears the
container down. There is no SSH lease.
Cloudflare Containers run behind container-enabled Durable Objects, which makes this provider a good fit for short Linux test jobs and warm repeated commands. It is not suitable for SSH-oriented or interactive desktop workflows.
For Worker-runtime JavaScript or TypeScript module execution, use the separate
Cloudflare Dynamic Workers provider
(provider: cloudflare-dynamic-workers, aliases cf-dynamic and cfdw).
Dynamic Workers do not provide Linux shell execution, archive sync, SSH, VNC, or
ports; they run module source through the Cloudflare Workers runtime.
- Targets: Linux only.
- Supported commands:
run,warmup,status,stop,list,doctor, and local-claimcleanup. - Run sessions:
run --keep --lease-output <path>writes a reusable lease handle with an exact cleanup command. - Sync: archive upload/extract (gzipped tar), not rsync.
- Coordinator: never brokered — this provider always runs direct from the
CLI against its own Worker runner, independent of any
CRABBOX_COORDINATORbroker. - Not supported: SSH, VNC, browser desktop, code-server, Actions hydration,
--download,--fresh-pr,--artifact-glob,--require-artifact, and--checksum(sync is archive-based, so there is no per-file checksum step). The provider also does not advertise a pond transport, sopond peersreports Cloudflare members astransport=none.
- A Cloudflare Workers Paid account with Durable Objects and Containers enabled.
- Wrangler authenticated for the target account.
- Docker (or a Docker-compatible daemon) available to Wrangler for image builds.
- The deployed Crabbox runner from
worker/wrangler.cloudflare.jsonc. - The Worker secret
CRABBOX_RUNNER_TOKEN. - CLI-side
CRABBOX_CLOUDFLARE_RUNNER_URLandCRABBOX_CLOUDFLARE_RUNNER_TOKEN.
The Worker entrypoint is worker/src/cloudflare-container-runner.ts. The
container image is built from worker/cloudflare-container.Dockerfile and runs
the Go HTTP runner in worker/cloudflare-container-runner.
Repo config should select the runner URL and remote workdir only. Keep the bearer token out of repo YAML.
provider: cloudflare
cloudflare:
apiUrl: https://crabbox-cloudflare-container-runner.example.workers.dev
workdir: /workspace/crabboxConfig keys map to the typed cloudflare section: apiUrl, token, and
workdir. The corresponding environment variables and flags are:
| Setting | Config key | Environment variable | Flag |
|---|---|---|---|
| Runner URL | apiUrl |
CRABBOX_CLOUDFLARE_RUNNER_URL |
--cloudflare-url |
| Workdir | workdir |
CRABBOX_CLOUDFLARE_WORKDIR |
--cloudflare-workdir |
| Token | token |
CRABBOX_CLOUDFLARE_RUNNER_TOKEN |
(none, by design) |
Keep the bearer token in a shell secret, credential manager, or user-level config:
export CRABBOX_CLOUDFLARE_RUNNER_URL=https://runner.example.workers.dev
export CRABBOX_CLOUDFLARE_RUNNER_TOKEN=...The token is intentionally not exposed as a command-line flag, because command-line arguments can be captured in shell history and process listings.
The workdir defaults to /workspace/crabbox and must resolve to an absolute
path. Broad system paths (/, /workspace, /usr, /var, and similar) are
rejected; pick a dedicated subdirectory.
Check the configured runner URL and token without creating a container:
crabbox doctor --provider cloudflareInstall dependencies and verify the Worker before deploy:
npm ci --prefix worker
npm run check --prefix worker
npm run build:cloudflare --prefix workerSet the runner bearer token as a Worker secret:
printf '%s' "$CRABBOX_CLOUDFLARE_RUNNER_TOKEN" \
| npx wrangler secret put CRABBOX_RUNNER_TOKEN \
--config worker/wrangler.cloudflare.jsoncDeploy the Worker and container image together:
npm run deploy:cloudflare --prefix workerThe deploy:cloudflare script passes --containers-rollout=immediate so Worker
and container changes roll out together. If you call Wrangler directly, include
that flag:
npx wrangler deploy \
--config worker/wrangler.cloudflare.jsonc \
--containers-rollout=immediateFor a repeatable local gate, deploy, and live smoke in one step, use:
scripts/deploy-cloudflare-smoke.shIt expects CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_API_TOKEN,
CRABBOX_CLOUDFLARE_RUNNER_TOKEN, and CRABBOX_CLOUDFLARE_RUNNER_URL in the
environment. Set CRABBOX_CLOUDFLARE_SKIP_DEPLOY=1 to run only the local checks
and live smoke, or CRABBOX_CLOUDFLARE_SKIP_SMOKE=1 to stop after deploy.
Inspect the deployed container app:
npx wrangler containers list --config worker/wrangler.cloudflare.jsonc
npx wrangler containers info <container-application-id> \
--config worker/wrangler.cloudflare.jsoncworker/wrangler.cloudflare.jsonc defines one Durable Object class per
predefined Cloudflare instance type. Crabbox maps every generic class to
standard-4, because the smaller Cloudflare tiers are far smaller than the
default Linux classes on other providers.
--class standard standard-4
--class fast standard-4
--class large standard-4
--class beast standard-4
Pick a smaller container explicitly with
--type lite|basic|standard-1|standard-2|standard-3|standard-4 for smoke tests
or quota control. --type accepts only these six values; anything else fails.
litesuits no-sync and quick command smoke tests.basicor astandard-*type is the right choice for archive sync.- Prefer
standard-*for dependency-heavy builds or tests; large module downloads can exhaust the smaller container disks before the command starts.
Cloudflare's current predefined types range from lite to standard-4;
standard-4 is 4 vCPU, 12 GiB memory, and 20 GB disk. Each class is capped at
max_instances: 4 in worker/wrangler.cloudflare.jsonc; change that value when
the account should allow more or fewer concurrent containers. For current
instance and account limits, see the Cloudflare Containers limits docs:
https://developers.cloudflare.com/containers/platform-details/limits/
With the runner URL and token configured, first exercise the deployed runner without uploading the checkout:
crabbox run \
--provider cloudflare \
--no-sync \
--timing-json \
--shell \
-- 'df -h / /tmp /workspace; printf "npm cache=%s\n" "${NPM_CONFIG_CACHE:-}"; printf "pnpm store="; pnpm config get store-dir'That one-shot run cleans up automatically. Use --keep when you want to inspect
or reuse the same container, then stop it explicitly:
crabbox run \
--provider cloudflare \
--keep \
--lease-output /tmp/cloudflare-session.json \
--no-sync \
--shell \
-- 'uname -a; command -v go node pnpm gh'
cat /tmp/cloudflare-session.json
crabbox stop --provider cloudflare <lease-id-or-slug>Then run a sync smoke from a checkout:
crabbox run \
--provider cloudflare \
--type basic \
--timing-json \
--shell \
-- 'test -f go.mod && rg -n "stopped_with_code" internal/providers/cloudflare'runcreates or reuses a container Durable Object, preparesworkdir, uploads a gzipped archive of the local checkout (unless--no-sync), extracts it, then relays stdout, stderr, and exit status.- Before upload, the provider checks remote disk headroom for both the archive and the extracted checkout, and fails early with a sizing hint if the selected type is too small.
warmupstarts a container and leaves it alive untilcrabbox stopor the configured TTL/idle deadline expires.statusandstopresolve local Crabbox claims, then call the runner.listreports local Cloudflare claims. Add--refreshto check runner state for those claims. The runner intentionally does not expose a global container enumeration API.- The default image includes Git, GitHub CLI (
gh),jq,ripgrep,curl, Go, Node, andpnpm; repo-specific dependencies still belong to the repo setup command. - npm and pnpm caches live under
/var/cache/crabbox(NPM_CONFIG_CACHE=/var/cache/crabbox/npm, pnpm store/var/cache/crabbox/pnpm), and the container filesystem persists while the lease is active. - The runner stores lease metadata in Durable Object storage and schedules
cleanup at the earlier of
--ttlor--idle-timeout. Uploads and command execution extend the idle deadline. crabbox cleanup --provider cloudflareonly checks local claims. It removes claims whose runner state is expired, stopped, or missing.
Cloudflare Containers can also reach Worker bindings through outbound handlers. Crabbox does not wire those by default, but custom runner images can add them: https://developers.cloudflare.com/containers/platform-details/workers-connections/
- Only Linux delegated
run,warmup,status,stop,list,doctor, and local-claim cleanup are supported. - SSH, VNC, browser desktop, code-server, Actions hydration,
--download, and--fresh-prare not supported. --checksumis not supported, because sync uses archive upload/extract rather than rsync.- The provider does not advertise a pond transport;
pond peersreports Cloudflare members astransport=nonerather than fabricating an endpoint. - Cleanup cannot discover containers that have no local Crabbox claim.
- Container capacity is bounded by the checked-in Wrangler bindings
(
max_instances) and the target account's Cloudflare Containers limits.