Cloudflare provider
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.
#Capabilities at a glance
- 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.
#Requirements
- 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.
#Configuration
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/crabbox
Config 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. Runner redirects are followed only when they keep the configured scheme, host, and effective port. Cross-origin redirects fail before command, environment, or upload bodies can be replayed to another destination. Runner error bodies and streamed error events redact the configured token and bearer-shaped credentials before they reach CLI diagnostics.
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 cloudflare
#Deploy
Install dependencies and verify the Worker before deploy:
npm ci --prefix worker
npm run check --prefix worker
npm run build:cloudflare --prefix worker
Set 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.jsonc
Deploy the Worker and container image together:
npm run deploy:cloudflare --prefix worker
The 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=immediate
For a repeatable local gate, deploy, and live smoke in one step, use:
scripts/deploy-cloudflare-smoke.sh
It 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.jsonc
#Instance types and capacity
worker/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/>
#Live smoke
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'
#Behavior
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.- Reuse,
status, andstopresolve local Crabbox claims before calling the runner and reject raw sandbox IDs without a matching claim. 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, checksum-verified 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/>
#Limitations
- 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.