Run Docker-in-Docker
Last updated Oct 23, 2026 Note
This page documents Sandbox SDK 0.x for existing applications. For new applications, refer to Sandboxes. To move an existing application to @cloudflare/sandbox 1.0, refer to Migrate from Sandbox SDK 0.x.
This guide shows you how to run Docker inside a Sandbox, enabling you to build and run container images from within a secure sandbox.
When to use Docker-in-Docker
Use Docker-in-Docker when you need to:
- Develop containerized applications - Run
docker buildto create images from Dockerfiles - Run Docker as part of CI/CD - Respond to code changes and build and push images using Cloudflare Containers
- Run arbitrary container images - Start containers from an end-user provided image
Create a Docker-enabled image
Create a custom Dockerfile that combines the sandbox binary with Docker. The Docker daemon runs as root:
Dockerfiledockerfile
FROM docker:dind
# Use the musl build so it runs on Alpine-based docker:dind
COPY --from=docker.io/cloudflare/sandbox:0.12.14-musl /container-server/sandbox /sandbox
COPY --from=docker.io/cloudflare/sandbox:0.12.14-musl /usr/lib/libstdc++.so.6 /usr/lib/libstdc++.so.6
COPY --from=docker.io/cloudflare/sandbox:0.12.14-musl /usr/lib/libgcc_s.so.1 /usr/lib/libgcc_s.so.1
COPY --from=docker.io/cloudflare/sandbox:0.12.14-musl /bin/bash /bin/bash
COPY --from=docker.io/cloudflare/sandbox:0.12.14-musl /usr/lib/libreadline.so.8 /usr/lib/libreadline.so.8
COPY --from=docker.io/cloudflare/sandbox:0.12.14-musl /usr/lib/libreadline.so.8.2 /usr/lib/libreadline.so.8.2
# Start dockerd without iptables or IP forwarding, wait up to 60 seconds
# for it to accept connections, then keep running
RUN printf '#!/bin/sh\n\
set -eu\n\
dockerd-entrypoint.sh dockerd --iptables=false --ip6tables=false --ip-forward=false --exec-opt native.cgroupdriver=cgroupfs &\n\
timeout 60 sh -c "until docker version >/dev/null 2>&1; do sleep 0.2; done"\n\
echo "Docker is ready"\n\
wait\n' > /usr/local/bin/start-docker.sh && chmod +x /usr/local/bin/start-docker.sh
# Mount /tmp before the sandbox starts. Otherwise the docker:dind
# entrypoint mounts a new /tmp over the sandbox's session files.
ENTRYPOINT ["/bin/sh", "-c", "mountpoint -q /tmp || mount -t tmpfs none /tmp; exec /sandbox \"$@\"", "--"]
CMD ["/usr/local/bin/start-docker.sh"]
Match the cloudflare/sandbox image tag to the version of @cloudflare/sandbox in your Worker.
The sandbox runs the CMD script when it starts:
--iptables=false,--ip6tables=false, and--ip-forward=falsestop Docker from changing network settings that Containers do not allow.--exec-opt native.cgroupdriver=cgroupfsmakes Docker manage cgroups directly instead of through systemd, which the container does not run.- If dockerd does not accept connections within 60 seconds, the script exits and the sandbox stops, so the failure shows up in your logs. Set
SANDBOX_LOG_LEVELtodebugto log the output of dockerd. Refer to Sandbox options.
The script does not appear in listProcesses(), because the sandbox starts it outside its process list.
Working with disabled iptables
Cloudflare Containers do not support iptables manipulation. The --iptables=false and --ip6tables=false flags prevent Docker from attempting to configure network rules, which would otherwise fail.
To send or receive traffic from a container running within Docker-in-Docker, use the --network=host flag with docker run. A docker build step that uses the network, such as a package install, also needs docker build --network=host.
This allows you to connect to the container, but it means each inner container has access to your outer container's network stack. Ensure you understand the security implications of this setup before proceeding.
Deployed sandboxes only
Docker-in-Docker does not work under wrangler dev. Docker needs a privileged container, and local development cannot start one.
Use Docker in your sandbox
Once deployed, you can run Docker commands through the sandbox. Docker becomes ready a few seconds after the sandbox starts, so wait for docker version to succeed first:
import { getSandbox } from "@cloudflare/sandbox";
const sandbox = getSandbox(env.Sandbox, "docker-sandbox");
// Wait for the Docker daemon
const ready = await sandbox.exec(
"timeout 60 sh -c 'until docker version >/dev/null 2>&1; do sleep 0.2; done'",
);
if (!ready.success) {
throw new Error("Docker did not start");
}
// Build an image
await sandbox.writeFile(
"/workspace/Dockerfile",
`
FROM alpine:latest
RUN apk add --no-cache curl
CMD ["echo", "Hello from Docker!"]
`,
);
const build = await sandbox.exec(
"docker build --network=host -t my-image /workspace",
);
if (!build.success) {
console.error("Build failed:", build.stderr);
}
// Run a container
const run = await sandbox.exec("docker run --network=host --rm my-image");
console.log(run.stdout); // "Hello from Docker!"
import { getSandbox } from "@cloudflare/sandbox";
const sandbox = getSandbox(env.Sandbox, "docker-sandbox");
// Wait for the Docker daemon
const ready = await sandbox.exec(
"timeout 60 sh -c 'until docker version >/dev/null 2>&1; do sleep 0.2; done'",
);
if (!ready.success) {
throw new Error("Docker did not start");
}
// Build an image
await sandbox.writeFile(
"/workspace/Dockerfile",
`
FROM alpine:latest
RUN apk add --no-cache curl
CMD ["echo", "Hello from Docker!"]
`,
);
const build = await sandbox.exec(
"docker build --network=host -t my-image /workspace",
);
if (!build.success) {
console.error("Build failed:", build.stderr);
}
// Run a container
const run = await sandbox.exec("docker run --network=host --rm my-image");
console.log(run.stdout); // "Hello from Docker!"
Limitations
Docker-in-Docker in Cloudflare Containers has the following limitations:
- No iptables - Network isolation features that rely on iptables are not available
- Ephemeral storage - Built images and containers are lost when the sandbox sleeps. You must persist them manually.
- No local development - Docker cannot start under
wrangler dev
Related resources
- Dockerfile reference - Customize your sandbox image
- Execute commands - Run commands in the sandbox
- Background processes - Manage long-running processes
Was this helpful?
YesNo
On this page
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/sandbox/sdk/guides/docker-in-docker/#page","headline":"Run Docker-in-Docker","description":"Run Docker commands inside a Sandbox SDK 0.x container.","url":"https://developers.cloudflare.com/sandbox/sdk/guides/docker-in-docker/","inLanguage":"en","image":"https://developers.cloudflare.com/sandbox/sdk/guides/docker-in-docker/og.png?v=a9338674365fe277","dateModified":"2026-10-23","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
description: Run commands with streaming output, error handling, and shell access in the Sandbox SDK 0.x. title: Execute commands image: https://developers.cloudflare.com/sandbox/sdk/guides/execute-commands/og.png?v=a53821d6788827fe
Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/sandbox/llms.txt
Use this file to discover all available pages before exploring further.
Docs