docs/install/podman.md
Run the OpenClaw Gateway in a rootless Podman container, managed by your current non-root user.
The intended model is:
openclaw CLI is the control plane.~/.openclaw by default.openclaw --container <name> ... instead of sudo -u openclaw, podman exec, or a separate service user.systemd --user if you want Quadlet-managed auto-startsudo only if you want loginctl enable-linger "$(whoami)" for boot persistence on a headless hostSetup details:
./scripts/podman/setup.sh builds openclaw:local in your rootless Podman store by default, or uses OPENCLAW_IMAGE / OPENCLAW_PODMAN_IMAGE if you set one.~/.openclaw/openclaw.json with gateway.mode: "local" if missing.~/.openclaw/.env with OPENCLAW_GATEWAY_TOKEN if missing.~/.openclaw/.env and passes explicit runtime env vars to the container; it does not hand the full env file to Podman.Quadlet-managed setup:
./scripts/podman/setup.sh --quadlet
Quadlet is a Linux-only option because it depends on systemd user services.
You can also set OPENCLAW_PODMAN_QUADLET=1.
Optional build/setup env vars:
OPENCLAW_IMAGE or OPENCLAW_PODMAN_IMAGE -- use an existing/pulled image instead of building openclaw:localOPENCLAW_DOCKER_APT_PACKAGES -- install extra apt packages during image buildOPENCLAW_EXTENSIONS -- pre-install plugin dependencies at build timeOPENCLAW_INSTALL_BROWSER -- pre-install Chromium and Xvfb for browser automation (set to 1 to enable)Container start:
./scripts/run-openclaw-podman.sh launch
The script starts the container as your current uid/gid with --userns=keep-id and bind-mounts your OpenClaw state into the container.
Onboarding:
./scripts/run-openclaw-podman.sh launch setup
Then open http://127.0.0.1:18789/ and use the token from ~/.openclaw/.env.
Host CLI default:
export OPENCLAW_CONTAINER=openclaw
Then commands such as these will run inside that container automatically:
openclaw dashboard --no-open
openclaw gateway status --deep # includes extra service scan
openclaw doctor
openclaw channels login
On macOS, Podman machine may make the browser appear non-local to the gateway. If the Control UI reports device-auth errors after launch, use the Tailscale guidance in Podman + Tailscale.
<a id="podman--tailscale"></a>
For HTTPS or remote browser access, follow the main Tailscale docs.
Podman-specific note:
127.0.0.1.tailscale serve over openclaw gateway --tailscale serve.See:
If you ran ./scripts/podman/setup.sh --quadlet, setup installs a Quadlet file at:
~/.config/containers/systemd/openclaw.container
Useful commands:
systemctl --user start openclaw.servicesystemctl --user stop openclaw.servicesystemctl --user status openclaw.servicejournalctl --user -u openclaw.service -fAfter editing the Quadlet file:
systemctl --user daemon-reload
systemctl --user restart openclaw.service
For boot persistence on SSH/headless hosts, enable lingering for your current user:
sudo loginctl enable-linger "$(whoami)"
~/.openclaw~/.openclaw/workspace~/.openclaw/.env./scripts/run-openclaw-podman.shThe launch script and Quadlet bind-mount host state into the container:
OPENCLAW_CONFIG_DIR -> /home/node/.openclawOPENCLAW_WORKSPACE_DIR -> /home/node/.openclaw/workspaceBy default those are host directories, not anonymous container state, so
openclaw.json, per-agent auth-profiles.json, channel/provider state,
sessions, and workspace survive container replacement.
The Podman setup also seeds gateway.controlUi.allowedOrigins for 127.0.0.1 and localhost on the published gateway port so the local dashboard works with the container's non-loopback bind.
Useful env vars for the manual launcher:
OPENCLAW_PODMAN_CONTAINER -- container name (openclaw by default)OPENCLAW_PODMAN_IMAGE / OPENCLAW_IMAGE -- image to runOPENCLAW_PODMAN_GATEWAY_HOST_PORT -- host port mapped to container 18789OPENCLAW_PODMAN_BRIDGE_HOST_PORT -- host port mapped to container 18790OPENCLAW_PODMAN_PUBLISH_HOST -- host interface for published ports; default is 127.0.0.1OPENCLAW_GATEWAY_BIND -- gateway bind mode inside the container; default is lanOPENCLAW_PODMAN_USERNS -- keep-id (default), auto, or hostThe manual launcher reads ~/.openclaw/.env before finalizing container/image defaults, so you can persist these there.
If you use a non-default OPENCLAW_CONFIG_DIR or OPENCLAW_WORKSPACE_DIR, set the same variables for both ./scripts/podman/setup.sh and later ./scripts/run-openclaw-podman.sh launch commands. The repo-local launcher does not persist custom path overrides across shells.
Quadlet note:
127.0.0.1 published ports, --bind lan inside the container, and keep-id user namespace.OPENCLAW_NO_RESPAWN=1, Restart=on-failure, and TimeoutStartSec=300.127.0.0.1:18789:18789 (gateway) and 127.0.0.1:18790:18790 (bridge).~/.openclaw/.env as a runtime EnvironmentFile for values such as OPENCLAW_GATEWAY_TOKEN, but it does not consume the manual launcher's Podman-specific override allowlist.~/.config/containers/systemd/openclaw.container directly, then reload and restart the service.podman logs -f openclawpodman stop openclawpodman rm -f openclawopenclaw dashboard --no-openopenclaw gateway status --deep (RPC probe + extra
service scan)--userns=keep-id and --user <your uid>:<your gid> by default. Ensure the host config/workspace paths are owned by your current user.gateway.mode=local): Ensure ~/.openclaw/openclaw.json exists and sets gateway.mode="local". scripts/podman/setup.sh creates this if missing.openclaw --container <name> ... explicitly, or export OPENCLAW_CONTAINER=<name> in your shell.openclaw update fails with --container: Expected. Rebuild/pull the image, then restart the container or the Quadlet service.systemctl --user daemon-reload, then systemctl --user start openclaw.service. On headless systems you may also need sudo loginctl enable-linger "$(whoami)".:Z on Linux when SELinux is enforcing or permissive.