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

> Set up Cloudflare Containers with computerd for a full Linux backend. Learn how computerd provides a Linux user-space environment for Durable Objects using FUSE and capn-web RPC.

- Repository: [Cloudflare/computer](https://github.com/cloudflare/computer)
- Tags: how-to-guide
- Published: 2026-08-16

---

**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`](https://github.com/cloudflare/computer/blob/main/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`](https://github.com/cloudflare/computer/blob/main/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`](https://github.com/cloudflare/computer/blob/main/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`](https://github.com/cloudflare/computer/blob/main/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.

```bash
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.

```dockerfile
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`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/backends/container/cloudflare-container.ts) and pass it to the `Workspace` constructor.

```typescript
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.

```typescript
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`](https://github.com/cloudflare/computer/blob/main/packages/computerd/src/cli/computerd.ts), [`packages/computerd/src/fuse/backend.ts`](https://github.com/cloudflare/computer/blob/main/packages/computerd/src/fuse/backend.ts), and [`packages/computer/src/backends/container/cloudflare-container.ts`](https://github.com/cloudflare/computer/blob/main/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`](https://github.com/cloudflare/computer/blob/main/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`](https://github.com/cloudflare/computer/blob/main/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`](https://github.com/cloudflare/computer/blob/main/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`](https://github.com/cloudflare/computer/blob/main/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.