# How to run Docker inside a sandbox Run `sudo enable-docker` once in the sandbox. It installs Docker Engine, Buildx and Compose. After that, `docker` works as the sandbox user. **On Runtime, Docker runs inside a microVM of its own.** Every sandbox is a Firecracker microVM with its own Linux kernel. The Docker daemon, your containers and `docker build` all run inside that machine. Root inside it still cannot change its network, CPU, memory or cost. `docker run`, `docker build` and `docker compose` work as they do on any Linux machine. A 2 vCPU, 4 GiB sandbox costs $0.03125 an hour while its containers wait. With both CPUs busy, it costs $0.08 an hour ([pricing](/docs/pricing)). ## Run a container ```ts check import { Sandbox } from "withruntime"; await using sbx = await Sandbox.create({ diskMiB: 8192, timeoutSeconds: 1800 }); const slow = { check: true, timeoutMs: 600_000 } as const; await sbx.exec("sudo enable-docker", slow); const hello = await sbx.exec("docker run --rm hello-world", slow); console.log(hello.stdout); ``` ```python check from withruntime import Sandbox with Sandbox.create(disk_mib=8192, timeout_seconds=1800) as sbx: sbx.exec("sudo enable-docker", check=True, timeout_ms=600_000) hello = sbx.exec("docker run --rm hello-world", check=True, timeout_ms=600_000) print(hello.stdout) ``` ```bash no-run sudo enable-docker # once per sandbox; the first docker command runs it too docker run --rm hello-world docker compose up -d ``` `enable-docker` installs Docker Engine, Buildx and Compose from Ubuntu's archive, and starts them. After that, `docker` works without `sudo`. Installs take longer than the 60-second default for a command, so set `timeoutMs` for them. ## Run a Compose project and open it in a browser Upload the project, start it, and share the published port as a private HTTPS preview: ```ts check import { Sandbox } from "withruntime"; await using sbx = await Sandbox.create({ diskMiB: 16_384, timeoutSeconds: 3600 }); const slow = { check: true, timeoutMs: 900_000 } as const; await sbx.files.upload("./app", "/workspace/app"); await sbx.exec("sudo enable-docker", slow); await sbx.exec("docker compose up -d --build", { ...slow, cwd: "/workspace/app" }); const preview = await sbx.previews.create(8080); // the port compose publishes console.log(preview.url, preview.token); ``` ```python check from withruntime import Sandbox with Sandbox.create(disk_mib=16_384, timeout_seconds=3600) as sbx: sbx.files.upload("./app", "/workspace/app") sbx.exec("sudo enable-docker", check=True, timeout_ms=900_000) sbx.exec("docker compose up -d --build", cwd="/workspace/app", check=True, timeout_ms=900_000) preview = sbx.previews.create(8080) # the port compose publishes print(preview["url"]) ``` A published port (`-p 8080:80`) listens inside the sandbox. A preview shares it, and `runtime sandboxes port-forward 8080` brings it to your own machine. A preview is private by default. A request needs its token, sent in the `x-runtime-preview-token` header ([share a port](/docs/javascript#share-a-port)). ## Start every sandbox with Docker ready Build a custom image whose recipe installs Docker. Every sandbox made from it skips the install. With `--no-start`, the daemon starts on the first `docker` command: ```ts check import { Runtime } from "withruntime"; const runtime = new Runtime(); await runtime.images.build({ name: "docker", recipe: { commands: ["enable-docker --no-start"] }, }); await using sbx = await runtime.sandboxes.create({ image: "docker", diskMiB: 8192 }); await sbx.exec("docker run --rm hello-world", { check: true, timeoutMs: 300_000 }); ``` ```python check from withruntime import Runtime runtime = Runtime() runtime.images.build(name="docker", recipe={"commands": ["enable-docker --no-start"]}) with runtime.sandboxes.create(image="docker", disk_mib=8192) as sbx: sbx.exec("docker run --rm hello-world", check=True, timeout_ms=300_000) ``` Building an image is free. A stored image is charged by its size. An account without credit can store its first three images free ([custom images](/docs/images)). An image can also come from your own Dockerfile. That image runs as a Runtime image, without Docker in the sandbox at all. ## Options and limits | What | How it works | | ------------------------ | -------------------------------------------------------------------------------------------------------------- | | Install | `sudo enable-docker`, once per sandbox, or in an image with `enable-docker --no-start` | | Daemon | Starts on the first `docker` command after a boot; a sandbox that runs no containers spends nothing on it | | Disk | Images and containers live on the sandbox's disk. Ask for more than the default 4 GiB, such as `diskMiB: 8192` | | Pulls | Docker Hub images come through Google's public mirror, `mirror.gcr.io`, first | | Internet from containers | No proxy settings needed: their connections out go through the sandbox's relay | | Network rules | The sandbox's allow and deny lists apply to its containers too | | Published ports | Listen inside the sandbox; share them with a preview or `runtime sandboxes port-forward` | In a measurement on 24 September 2026, the default 4 GiB sandbox had about 2.5 GiB free. That is why the samples ask for 8 GiB or more ([disk, CPU and memory](/docs/sandbox-environment#disk-cpu-and-memory)). **Compose services calling each other.** Services, and containers on one Docker network, reach each other by name, as anywhere. Containers get no proxy settings, so nothing needs to go in `NO_PROXY`. ## Where this helps - An agent that builds and runs a multi-service app can do it in a sandbox and show you the result through a preview ([preview agent-built apps](/use-cases/preview-agent-built-apps)). - Integration tests that need a real Postgres or Redis get their own. It is discarded with the sandbox. - A [coding agent](/use-cases/coding-agent-sandbox) can run a repository's own `docker compose` setup unchanged. To learn why a microVM, and not a container, is the boundary, see [microVM vs container](/compare/microvm-vs-container) and [Firecracker vs Docker](/compare/firecracker-vs-docker). ## Start ```bash no-run npx withruntime sandboxes run --timeout 600 -- bash -c 'sudo enable-docker && docker run --rm hello-world' ``` A new account gets 100 free hours of a 1 GB machine in its first 30 days, with no card. The first run prints a link to approve in your browser. For full details, see [Docker in the sandbox environment](/docs/sandbox-environment#docker). Facts on this page were checked on 26 October 2026.