On this page

On this page

Gateway

Podman backend

Selecting the native Podman CLI as a built-in backend, the Docker settings it reuses, and its rootless user-mapping rules.

This page covers Podman as the sandbox backend for agent tool execution. Running the Gateway itself in a rootless Podman container is a separate setup: see Podman.

Podman backend

Use sandbox.backend: "podman" to select the native podman CLI directly. This is a built-in backend, not a plugin. It does not check or select Docker, even when the docker executable is installed.

Podman reuses the existing sandbox.docker.* settings and the active native podman CLI context; it adds no separate connection configuration surface.

On Linux, a rootless local Podman backend launched from a delegated Gateway service uses a transient systemd user scope for its container commands. This keeps Podman and its container processes in the same user-manager cgroup tree, including when restarting an existing sandbox or running exec. The user manager and its bus must be available to the Gateway. Keep Delegate=yes, DelegateSubgroup=gateway, and the sandbox's resource limits enabled; switching the cgroup manager or clearing INVOCATION_ID does not repair this boundary.

Dependency-template builders stop before their installed files become reusable. On native Linux with cgroup v2 and systemd, OpenClaw captures the builder's exact engine-reported cgroup at startup and checks kernel population after killing its immutable container ID. This avoids waiting for Podman's physical cleanup on the preparation path; registry housekeeping still owns removal and crash recovery. An unavailable cgroup capture uses the engine's wait and termination checks. An unreadable or still-populated captured cgroup blocks template publication.

Rootless Podman defaults to --userns=keep-id for writable workspace mounts. A long-lived sandbox can reserve subordinate IDs and block unrelated --userns=auto workloads; remove it before starting those workloads. Set sandbox.docker.user to a nonzero numeric UID or UID:GID to control the container user. Rootless Podman rejects UID or GID 0 because Podman 4.x cannot remap namespace root while preserving workspace bind ownership; bake root-required setup into the image or use rootful Podman. Rootful Podman otherwise uses the workspace owner when available.

json5
{  agents: {    defaults: {      sandbox: {        mode: "all",        backend: "podman",        scope: "session",        workspaceAccess: "rw",        docker: {          image: "openclaw-sandbox:trixie-slim",          network: "none",          readOnlyRoot: true,          capDrop: ["ALL"],        },      },    },  },}

Build or pull the sandbox image into the selected Podman store before enabling the backend. From a source checkout, build the same sandbox Dockerfile with Podman:

bash
podman build -t openclaw-sandbox:trixie-slim -f scripts/docker/sandbox/Dockerfile .

Changing connections and upgrading existing sandboxes

OpenClaw follows the installed Podman client when both environment selectors are set: Podman 4.8 and newer prefer a nonempty CONTAINER_CONNECTION; Podman 4.7 prefers CONTAINER_HOST when it is present. The engine's server version does not decide this precedence. If OpenClaw cannot identify the client version with both selectors set, it refuses the ambiguous selection. Unset the unused selector or repair the client's podman --version command.

Each sandbox records its engine URI and, for Podman Machine, its SSH identity. The Gateway discovers the engine once per process, sharing concurrent discovery and retrying failed discovery. Preparation validates recorded targets against that captured endpoint. Commands on the prepared sandbox reuse the bound endpoint and full container ID without another discovery probe; native local execution explicitly selects --remote=false. If that engine or container disappears, the command reports Podman's error. Restore the original engine or prepare a new sandbox before retrying. Changing engine mode in containers.conf or replacing the Podman executable during a run is not supported; finish active runs before changing the engine. Restart the Gateway after changing the Podman connection, engine mode, or executable so it discovers the new runtime.

Earlier OpenClaw versions could pin CONTAINER_HOST even when the client selected CONTAINER_CONNECTION. After upgrading, those existing sandboxes can report "The active Podman connection changed." OpenClaw preserves the old sandbox and registry entry rather than removing a container on the newly selected engine.

Retire the old sandbox through its recorded endpoint before switching:

  1. Pause runs that use the affected sandbox. Use the same OS user, OpenClaw profile, config, and state directory as the Gateway for the commands below.
  2. Restore the original CONTAINER_HOST and, for Podman Machine, the original CONTAINER_SSHKEY. Unset CONTAINER_CONNECTION in that command environment. The original endpoint must be reachable, and a Podman Machine must be running.
  3. Use the affected sandbox's exact sessionKey. While all registered sandboxes use the restored target, openclaw sandbox list --json shows that key and the recorded URI and identity in backendTarget.globalArgs. Save these values before changing connections. If entries already span engines, the global list can fail; use the previously recorded key with the scoped recreation below. If that key is unknown, preserve the registry and identify the exact scope before continuing.
  4. Preserve any needed data in the container's writable layer, then run openclaw sandbox recreate --session "<sessionKey>". Review the preview before confirming. This removes the selected container; mounted workspace files remain.
  5. Set the intended CONTAINER_CONNECTION and unset the unused CONTAINER_HOST and CONTAINER_SSHKEY. Apply that environment to the Gateway and restart it. Check that the sandbox image and workspace are available on the selected engine. The next use creates a new sandbox there; it does not transfer the old container's writable layer.

If the original endpoint or identity cannot be restored, keep the registry entry and repair that connection first. Do not edit the recorded target or delete the registry entry to bypass the check. recreate --force only skips confirmation; it does not bypass endpoint validation.

Host init prerequisite

OpenClaw creates Podman sandboxes with --init so orphaned tool processes are reaped. The Podman engine host needs its init executable, normally catatonit. Installing it only inside the sandbox image does not satisfy this requirement. For Podman Machine, the executable belongs inside the machine, not on the client host.

On Debian or Ubuntu, minimal installs using --no-install-recommends can omit the helper. Include it explicitly when provisioning the engine host:

bash
sudo apt-get install podman catatonit

If sandbox creation reports lookup init binary or container-init binary not found on the host, install the helper or repair Podman's configured init_path/helper_binaries_dir in containers.conf, then retry. Podman can resolve helpers outside PATH; a successful podman info does not prove that --init works. Keep sandboxing and --init enabled rather than bypassing this prerequisite.

Podman notes:

  • Browser sandboxing is not supported by Podman; keep sandbox.browser.enabled off, or install Docker and select backend: "docker".
  • Local Podman engines and Podman Machine are supported. Podman Machine bind sources must be under the host home directory, which is its default shared volume. Arbitrary remote Podman connections are rejected; use the SSH backend for remote execution.
  • Custom tmpfs or bind mounts must not cover /run/podman-init; OpenClaw rejects them so sandbox cleanup continues to work.

Each running rootless Podman container holds a session keyring charged to the engine host user's kernel key quota. Busy hosts can exhaust the default quota and fail with create keyring: Disk quota exceeded even with free disk space. On the engine host, use sudo sysctl -w kernel.keys.maxkeys=2000 kernel.keys.maxbytes=200000 and persist both values in a file under /etc/sysctl.d/. OpenClaw retries a quota failure once after stopping at most one least-recently-used inactive sandbox; active contexts, live or uncertain exec processes, and persistent Docker exec custody prevent reclamation. Stopping preserves the writable layer but ends processes and clears tmpfs; regular idle and age removal policies are unchanged.

Was this useful?