How to Set Up Cloudflare Containers with computerd for a Full Linux Backend

The Cloudflare Container backend provides a complete Linux user-space environment for Durable Objects by running the computerd daemon inside a sandbox container, which mounts a virtual file system via FUSE and exposes a capn-web RPC endpoint for bidirectional sync.

The cloudflare/computer repository implements a containerized backend that moves the execution layer out of the JavaScript runtime and into a proper Linux environment. By deploying the computerd binary as the container entrypoint, you gain access to a full filesystem, shell execution, and native tooling while maintaining durability through the Durable Object's SQLite-backed virtual file system (VFS).

Architecture Overview

The system operates across three distinct layers that work together to present a unified workspace.

Three-Layer Architecture

Layer Responsibility Key Component
Host (Durable Object) Holds the authoritative SQLite VFS, starts the container, and opens a capn-web WorkspaceRPC session. packages/computer/src/backends/container/cloudflare-container.ts
Container Runs the computerd binary, which mounts the VFS, tracks dirty writes, and serves the RPC transport. packages/computerd/src/cli/computerd.ts
FUSE / Shim Provides a mount point (/workspace by default) that mirrors the VFS inside the container, letting any Linux tool see the same files the DO sees. packages/computerd/src/fuse/backend.ts

The Durable Object remains the source of truth for all filesystem state. The container runs an ephemeral copy that syncs changes via the capn-web protocol, while the FUSE layer translates kernel filesystem calls into RPC messages.

Boot Sequence and Initialization

Understanding the startup flow is critical for debugging connection issues.

1. Container Initialization

When the Durable Object calls container.start({enableInternet, env}), the platform launches your container image. The image's ENTRYPOINT must point to the pre-built computerd binary, which eliminates the need for a Node.js runtime inside the container.

2. Health Probing

Before establishing the RPC channel, the host repeatedly sends HEAD /health requests to the container. The endpoint returns 200 only after the HTTP server binds and, in the case of native FUSE mounts, after the filesystem is successfully mounted at MOUNT_POINT.

3. Reverse-Dial RPC Handshake

Instead of requiring the host to know the container's internal IP address, computerd implements a reverse-dial pattern. The host either upgrades to /ws directly or issues a POST /connect request, prompting computerd to open an outbound WebSocket that loops back through the DO's egress interceptor. This creates a bidirectional capn-web session for VFS synchronization and command execution.

Required Environment Variables

The computerd binary consumes several environment variables to configure its runtime behavior. These are defined in packages/computerd/src/cli/computerd.ts.

Variable Default Meaning
PORT 45678 (Cloudflare backend pins to 8080) HTTP / WebSocket server port.
MOUNT_POINT /workspace Path inside the container where the FUSE mount is created.
FUSE_MOUNT auto Backend selection: auto probes /dev/fuse (Linux) or macFUSE (macOS) and falls back to the userspace shim; fuse / macfuse force the real kernel driver; shim forces the shim; none disables mounting.
UPSTREAM_URL unset When set, computerd starts a sync client that pushes/pulls VFS revisions to the DO.
EXEC_LOG_MAX_BYTES runner default Limits the in-memory log retained for each exec command.
LOG_FILE unset If set, all console output is also appended to this file.

Implementation Steps

Follow these concrete steps to containerize your Durable Object workload.

Step 1: Build the computerd Binary

First, compile the static binary for your target architecture. This produces a self-contained executable that runs without Node.js.

npm run build:bin --workspace @cloudflare/computerd

# Output: artifacts/computerd/computerd-linux-x64

Step 2: Create the Container Image

Use the canonical Dockerfile pattern from examples/container/Dockerfile. This installs FUSE libraries and sets computerd as the entrypoint.

FROM --platform=linux/amd64 debian:stable-slim

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
         fuse3 libfuse2t64 ca-certificates \
    && rm -rf /var/lib/apt/lists/*

COPY build/computerd-linux-x64 /usr/local/bin/computerd
RUN chmod +x /usr/local/bin/computerd

ENV PORT=8080
ENV MOUNT_POINT=/workspace
ENV FUSE_MOUNT=auto
EXPOSE 8080

ENTRYPOINT ["/usr/local/bin/computerd"]

The image must include fuse3 and libfuse2 (or libfuse2t64 on newer Debian) to support the kernel filesystem interface.

Step 3: Configure the Durable Object Backend

In your Durable Object implementation, instantiate CloudflareContainerBackend from packages/computer/src/backends/container/cloudflare-container.ts and pass it to the Workspace constructor.

import { Workspace } from "@cloudflare/computer";
import {
  CloudflareContainerBackend,
  withWorkspaceContainer,
} from "@cloudflare/computer/backends/container";

export class Agent extends withWorkspaceContainer(
  class extends DurableObject<Env> {}
) {
  readonly workspace = new Workspace({
    storage: this.ctx.storage,
    backends: [
      new CloudflareContainerBackend({
        container: () => this,
        workspace: { binding: "Agent", id: this.ctx.id.toString() },
      }),
    ],
  });

  async initialize() {
    await this.workspace.ready();
    await this.workspace.fs.mkdir("/workspace", { recursive: true });
    await this.workspace.fs.writeFile(
      "/workspace/hello.txt",
      "Hello from the container!\n"
    );
  }
}

The withWorkspaceContainer mixin provides the container lifecycle methods, while CloudflareContainerBackend handles the start(), health checks, and RPC session management.

Step 4: Execute Commands in the Linux Environment

Once the workspace is ready, use the runtime.exec API to run shell commands inside the container. Because the VFS is mounted at /workspace, files written via workspace.fs are immediately visible to Linux tools.

const run = await this.workspace.runtime.exec("ls -la /workspace", {
  encoding: "utf8",
});
const { stdout, exitCode } = await run.result();
console.log(stdout, exitCode);

The exec implementation streams stdout/stderr back to the DO and respects the EXEC_LOG_MAX_BYTES limit configured via environment variables.

Summary

  • Three-layer architecture: The Durable Object holds the authoritative SQLite VFS, the container runs computerd, and FUSE provides the kernel interface.
  • Reverse-dial RPC: The container initiates the WebSocket connection via POST /connect, eliminating the need for static container IPs.
  • Environment-driven configuration: Use PORT, MOUNT_POINT, and FUSE_MOUNT to control the runtime without code changes.
  • Source files: Core logic resides in packages/computerd/src/cli/computerd.ts, packages/computerd/src/fuse/backend.ts, and packages/computer/src/backends/container/cloudflare-container.ts.
  • Deployment pattern: Build the static binary, package it in a FUSE-capable image, and deploy with CloudflareContainerBackend.

Frequently Asked Questions

What is the difference between the FUSE backend and the userspace shim?

The FUSE backend (enabled when FUSE_MOUNT=fuse or auto-detected on Linux) creates a real kernel filesystem mount at /dev/fuse, allowing any Linux process to interact with the VFS through standard syscalls. The userspace shim (used when FUSE_MOUNT=shim or when /dev/fuse is unavailable) intercepts filesystem calls at the application layer, providing compatibility for environments lacking kernel FUSE support or requiring unprivileged execution. According to packages/computerd/src/fuse/backend.ts, the shim is automatically selected when kernel access is restricted.

Why does computerd use a reverse-dial connection instead of accepting inbound WebSockets?

The reverse-dial pattern solves the ephemeral IP problem in serverless container environments. As implemented in packages/computer/src/backends/container/cloudflare-container.ts, the Durable Object sends a POST /connect request to the container, which prompts computerd to open an outbound WebSocket that tunnels back through the DO's egress proxy. This avoids the need for the host to know the container's dynamic internal IP address and works seamlessly with Cloudflare's network topology.

How does filesystem durability work if the container is ephemeral?

The Durable Object maintains the authoritative SQLite VFS, while the container holds only a synced cache. When computerd starts with UPSTREAM_URL set (as configured in packages/computerd/src/cli/computerd.ts), it establishes a sync client that pulls the current VFS revision from the DO on startup and pushes dirty writes back in real-time. If the container restarts, the new instance simply re-syncs with the DO's SQLite database, ensuring no data loss occurs during container recycling.

Can I run computerd on macOS for local development?

Yes, computerd supports macOS through the macFUSE driver. When FUSE_MOUNT=auto is set (the default), the binary probes for macFUSE availability in packages/computerd/src/fuse/backend.ts before falling back to the userspace shim. For local development without kernel extensions, the shim provides full compatibility, though with slightly different performance characteristics than the native FUSE implementation.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →