Skip to main content
Docker is the simplest sandbox provider for local development and trusted single-host self-hosting. Roomote starts one worker container per task, connects it to the configured Docker network, streams logs back to the task view, and stops the container when the task is finished.

When to use Docker

Use Docker when:
  • you are developing Roomote locally
  • you are trying Roomote on one trusted host
  • task volume is modest enough for the host machine
  • you want the fewest external sandbox accounts and credentials
  • you want resumable tasks to restart the same workspace on the same host
Move to a hosted provider when multiple users run heavier tasks, when task work should not compete with the Roomote server, or when you need stronger provider-managed isolation.

Configuration

Docker does not need provider API credentials. Select Docker during setup or from Settings > Sandboxes. Common env vars:
Local development builds roomote-worker:local automatically. Self-hosted Compose deployments normally use docker-compose.compute-docker.yml, which sets the worker image, platform, network, and release path for sibling worker containers. For production deployments, prefer an immutable registry-qualified worker image tag when workers need a published image instead of a local tag.

Resource and network isolation

Every Docker task receives a dedicated bridge network. In Compose deployments, Roomote attaches the API and, when enabled, the optional preview proxy to that network; sibling task containers and datastore containers are not reachable. The controller reconciles replacement API and preview-proxy containers onto running task networks, removes empty task networks periodically, and reaps stale provisioning containers after a restart. Environments that use Docker projects also receive a dedicated Docker daemon and workspace volume. Customer Compose services share the task’s network namespace so configured preview ports keep the same task-scoped routing, while their Docker control plane is not exposed to other tasks. The daemon, inner containers, network, and workspace volume are stopped or removed with the task lifecycle. Workers default to 2 CPUs, 4 GiB of memory with no additional swap, 512 PIDs, a requested 20 GiB writable-layer quota, and three 10 MiB JSON log files. The dedicated Docker daemon used by Docker-project tasks receives an 8 GiB memory limit by default while inheriting the other worker resource limits. The variables above can tune those bounds. Writable-layer quotas require a Docker storage driver that supports --storage-opt size. When the driver rejects that option, Roomote refuses to start the task rather than allowing untrusted code to consume the host disk. Configure a quota-capable Docker data root. Operators that enforce an equivalent host-level quota can explicitly set DOCKER_WORKER_ALLOW_UNBOUNDED_DISK=true; Roomote then logs a warning and starts without --storage-opt size. Completed resumable tasks keep their stopped container and writable layer so a follow-up can restart the same workspace. Roomote retains at most 10 containers for 24 hours by default. Configure DOCKER_STANDBY_MAX_COUNT and DOCKER_STANDBY_MAX_AGE_HOURS to change those bounds; a count of 0 disables Docker standby retention. The five-minute retention sweep removes the oldest or expired containers and their task networks. These retention limits are also editable under Settings > Sandboxes > Local Docker > Advanced settings. Process environment variables take precedence and appear as locked values in Settings. The default internet egress policy allows public repository and tool access while installing immutable blackhole routes for private, shared-address, and cloud metadata ranges (including AWS/GCP/Azure, Alibaba, and Oracle endpoints). The task’s own, more-specific network route still reaches its API and preview proxy peers. In networked self-host deployments, direct connections to the Docker bridge gateway are also blocked without disrupting its use as the public-egress next hop. Local development blocks metadata ranges but retains private and gateway access because its API runs on the host. The worker never receives the network-administration capability needed to remove the policy. Set DOCKER_WORKER_EGRESS_POLICY=none for tasks that need only the Roomote API and preview proxy.

Security notes

Docker sandboxes require the Roomote controller to create and manage worker containers. Production Compose routes those operations through an internal socket proxy that allows only the container, exec, image, network, and volume API sections Roomote needs; the controller does not mount the raw socket. Treat the proxy and Docker host as trusted infrastructure, and do not use Docker sandboxes as a multi-tenant isolation boundary for untrusted operators or repositories.

Verify setup

  1. select Docker as the sandbox provider
  2. use Validate environment in Settings → Sandboxes (Local Docker section) to check the Docker daemon, worker image, and worker release archive before starting anything
  3. start a small task from an environment
  4. confirm the task can clone the repository and run a simple command
  5. open task logs and verify output streams back to Roomote
  6. check that the worker container stops after the task completes
The validation runs in the background worker service (the process with Docker socket access), so it reflects exactly what task boots will see.

Common issues

Before creating any sandbox resources, Roomote preflights the Docker environment: it checks that the daemon responds, and that the worker image is available locally (pulling it when a registry hosts it). When a boot fails, the task startup screen explains the failure category; the sections below map each one to a fix.
  • Roomote couldn’t reach the Docker daemon. Start Docker Desktop (or the Docker Engine service) and confirm the host running the controller can access the Docker socket. In production Compose, check the socket proxy container.
  • Roomote couldn’t find or pull the worker image. Build or publish the worker image configured in DOCKER_WORKER_IMAGE (for local development, pnpm dev builds roomote-worker:local). For private registries, make sure the host is logged in.
  • A required host port is already in use. Another process holds a port the sandbox needs. Stop it, or change the conflicting service’s port, then retry.
  • The worker release archive is missing. The Docker provider installs the worker from a local release archive. For local development, run pnpm dev --use-release (or the worker-release build step) so the archive exists before starting tasks.
  • The worker failed while contacting the Roomote API (fetch failed). The container cannot reach the API URL from inside Docker. Verify R_PUBLIC_URL/the API address resolves from a container (often via host.docker.internal) and that the API is running.
  • The worker did not start in time, or the container exited during boot. Open the task’s failure details for the container logs and process list — they include the underlying crash, missing dependency, or fetch failure.
  • The task cannot reach Roomote services. Check DOCKER_WORKER_NETWORK and the Compose network used by the API and controller.
  • A worker reports that its disk limit is unsupported. Configure a Docker storage driver with per-container writable-layer quota support. Only set DOCKER_WORKER_ALLOW_UNBOUNDED_DISK=true when an equivalent host-level quota is already enforced.
  • Docker’s address pools are exhausted. List Roomote-managed task networks and remove only unused ones:
    Docker asks for confirmation and prunes only networks with no attached containers. On Docker Desktop with the WSL2 backend, restart Docker Desktop if released networks do not restore address space. If exhaustion recurs, set Docker’s default-address-pools in the Docker Engine configuration to a larger private range that does not overlap the host, VPN, or deployment networks, then restart Docker. Roomote does not assign static task subnets because host and VPN ranges differ between deployments.