docker CLI. Set the backend to "podman" to select native Podman directly. Sandboxing is off by default and does not require the Gateway itself to run in a container. SSH and OpenShell sandbox backends are also available; see Sandboxing.
Hosting multiple users? See Multi-tenant hosting for the one-cell-per-tenant model.
Prerequisites
- Docker Desktop (or Docker Engine) + Docker Compose v2
- At least 6 GB RAM for a local source image build; pre-built images avoid this build requirement
- Enough disk for images and logs
- On a VPS/public host, review Security hardening for network exposure, especially the Docker
DOCKER-USERfirewall chain
Containerized Gateway
1
Build the image
From the repo root:This builds the Gateway image locally as Pre-built images are published first to the GitHub Container Registry. GHCR is the primary registry for release automation, pinned deployments, and provenance checks. The same release publishes a Docker Hub mirror at Use
openclaw:local. To use a pre-built image instead:openclaw/openclaw:ghcr.io/openclaw/openclaw or openclaw/openclaw and avoid unofficial mirrors, which don’t share OpenClaw’s release timing or retention policy. Version-specific tags include releases such as 2026.9.3 and prereleases such as 2026.9.1-beta.1. Stable releases move latest and main; trailing-month Gateway releases move only extended-stable. Variants include slim, main-slim, extended-stable-slim, latest-browser, main-browser, and extended-stable-browser. The default images bundle the codex and diagnostics-otel plugins. A -browser variant also ships with Chromium baked in for the Gateway-controlled browser. The agent sandbox browser uses a separate image.2
Airgapped rerun
On offline hosts, transfer and load the image first:
--offline verifies OPENCLAW_IMAGE already exists locally, disables implicit Compose pulls/builds, then runs the normal flow: .env sync, permission fixes, onboarding, Gateway config sync, Compose startup.If OPENCLAW_SANDBOX=1, offline setup also checks the configured default and per-agent sandbox images on the daemon behind OPENCLAW_DOCKER_SOCKET, including the browser-contract label on Docker-backed browser images. If a required image is missing or stale, setup exits without changing sandbox config rather than reporting a broken success.3
Complete onboarding
The setup script runs onboarding automatically:
- prompts for provider API keys
- generates a Gateway token and writes it to
.env - creates the legacy auth-profile secret key directory
- starts the Gateway via Docker Compose
openclaw-gateway directly (with --no-deps --entrypoint node), since openclaw-cli shares the Gateway’s network namespace and only works once the Gateway container exists.4
Open the Control UI
Open With a custom
http://127.0.0.1:18789/ and paste the token written to .env into Settings. If you switched the container to password auth, use that password instead.Need the URL again?OPENCLAW_GATEWAY_PORT, replace port 18789 in the printed URL with your host port before opening it in the browser; keep the rest of the URL intact. Dashboard commands inside either container use the internal listener port.Using the Control UI browser
The Control UI Browser panel displays a browser controlled by the Gateway. It is separate from the browser on your laptop or phone that opens the dashboard. For a local managed browser with a Docker Gateway, Chromium must be available inside the Gateway container. For a new installation, use the official browser-equipped image with the normal Compose setup; no custom Dockerfile is needed:-browser tag instead of the moving
latest-browser tag. For an existing Compose installation, change OPENCLAW_IMAGE
in its .env to the browser variant, then pull and recreate the Gateway using
the same Compose files and overlays as your current deployment:
.env from the
current shell and defaults.
An existing home volume or bind mount covering /home/node/.cache/ms-playwright
can hide the image’s bundled Chromium. If browser discovery still fails after the
image switch, check those mounts. Preserve the data, then either provision
Chromium in the mounted home or adjust the mounts to leave the image’s browser
cache visible; recreating the container does not refresh a populated home volume.
For a new installation from a local source build, bake Chromium into the image:
- Keep browser control enabled (
browser.enabled). Use a local managed profile such asopenclawfor the container’s Chromium, not an extension, attach-only, or remote-CDP profile intended for another browser. - OpenClaw auto-detects the image’s Playwright-managed Chromium on Linux. An
explicit
browser.executablePathor profile executable path must point to a binary inside the container; a path from your laptop will not work there. - A headless container needs headless browser operation. Check explicit
browser.headless, profile headless settings, andOPENCLAW_BROWSER_HEADLESSoverrides if startup reports a missing display. See Browser configuration. - Connect with
operator.adminaccess to a Gateway advertisingbrowser.request. Open + → Browser in the Chat side panel, navigate to a page, and confirm that its snapshot loads and navigation works. Loading the dashboard alone does not verify that Chromium can start.
-browser image
does not build or configure that sandbox image.
Headless bootstrap
For an unattended container host, put provider, Gateway, and channel credentials in the Compose.env file so both the one-shot bootstrap container and the long-running Gateway receive the same values:
TELEGRAM_BOT_TOKEN in .env after bootstrap: --use-env leaves credential lookup to the environment without copying the token into openclaw.json, and the running Gateway needs the same variable. When channel config changes after startup, the Gateway’s config watcher hot-reloads the affected channel automatically.
See openclaw channels for credential-flag alternatives and other channel plugins.
Manual flow
.git. Pass the source identity as build arguments
as shown above so the image’s About screen reports the checked-out commit and
one build timestamp. scripts/docker/setup.sh resolves and passes both values
automatically.
Run
docker compose from the repo root. If you enabled OPENCLAW_EXTRA_MOUNTS or OPENCLAW_HOME_VOLUME, the setup script writes docker-compose.extra.yml; include it after any docker-compose.override.yml you maintain yourself, e.g. -f docker-compose.yml -f docker-compose.override.yml -f docker-compose.extra.yml.Upgrading container images
When you replace the OpenClaw image but keep the same mounted state/config, the new Gateway runs Doctor’s upgrade migrations under exclusive maintenance ownership and plugin convergence before readiness. Routine image upgrades should not require a separateopenclaw doctor --fix pass.
This includes agent database schema upgrades, shared-state audit migrations, and
legacy workspace setup imports. Before advancing database schemas, startup saves
verified SQLite copies beside the originals as
<database>.pre-startup-migration-<id>.bak. The shared database and affected agent
databases use the same backup ID. Config backups and retired workspace-file
archives follow the normal Doctor repair rules. Keep these files with your
pre-upgrade backup; a rollback must restore the matching state as well as the old
image. See rollback.
On FUSE filesystems such as Unraid’s shfs, a missing native no-replace rename
does not require an operator step. The migration owner publishes a complete,
exclusive hardlink, syncs it before removing the old name, and can recover an
interrupted source/claim pair without replacing another file. This preserves the
source inode and exact bytes. The filesystem must support same-directory hardlinks
and directory synchronization when native no-replace rename is unavailable.
Readiness remains false while the default or system agent database is refused,
and the readiness response includes the admission reason. A refused optional
agent remains isolated while healthy agents can serve requests.
Missing or drifted canonical SQLite indexes are rebuilt by the schema migration
owner before session startup completes. Repair warnings identify the agent,
database path, rebuilt indexes, and elapsed time. Current-schema shape refusal
reports list all affected databases in stable path order. Missing required tables,
incompatible columns, and other changes that cannot be reconstructed safely still require Doctor; startup
does not recreate a missing data table as an empty one.
Startup exits with code 78 when required state cannot be migrated safely:
for example, source identities conflict, data is unreadable, another writer owns
the state, or the filesystem provides no safe, durable way to publish a claim.
The retained source, claim, and backups are recovery inputs; do not delete them to
silence the error. If the filesystem lacks the required primitives, stop the
Gateway and expose the same data through its native backing filesystem before
retrying (for example, an Unraid pool path instead of the shfs share).
With a restart policy, Docker, Podman, or Kubernetes may show
the Gateway container restarting. Keep the mounted state volume, then run the
same image once with openclaw doctor --fix as the container command, using the
same state/config mounts the Gateway uses:
Source-built images with selected plugins
OPENCLAW_EXTENSIONS selects plugin manifest ids from the source checkout;
existing source-directory names are also accepted when they differ. The Docker
build resolves the selection to source directories once, installs production
dependencies, links each selected plugin’s own runtime dependencies under its
packaged root in /app/dist/extensions/<id>, and includes the selected plugin
runtime in the image. Source checkouts also compile first-party plugins
published separately with
openclaw.build.bundledDist: false; that marker still preserves the plugin’s
external npm or ClawHub ownership and does not change either artifact contract.
Unknown, invalid, or ambiguous ids fail the image build.
This includes WhatsApp: OPENCLAW_EXTENSIONS=whatsapp compiles and packages its
runtime. Ordinary source builds generate its runtime through the separate
external-plugin build path; root npm artifacts continue to exclude it. Selected
plugins must compile successfully; unselected external plugin source and
runtime output are pruned.
For example, these commands build separate, multi-architecture standalone
FakeCo Gateway images for ClickClack, Slack, and Microsoft Teams. ClawRouter is
already part of the root OpenClaw runtime, so the ClickClack image selects only
clickclack. The explicit empty browser argument keeps the default image free
of Chromium:
--platform linux/arm64 --load or --platform linux/amd64 --load for a
single native local build. Multi-platform output and attached SBOM/provenance
require a registry or another Buildx output that preserves attestations. After
pushing, inspect the manifest and deploy the immutable digest rather than the
mutable source-SHA tag:
OPENCLAW_EXTRA_MOUNTS=/path/to/fork/extensions/synology-chat:/app/extensions/synology-chat:ro. That overrides the matching compiled /app/dist/extensions/synology-chat bundle for the same plugin id. Restart the Gateway after adding or changing a mount; runtime loading and setup use the mounted source.
Observability
OpenTelemetry export is outbound from the Gateway container to your OTLP collector; it needs no published Docker port. To include the bundled exporter in a locally built image:diagnostics-otel; install clawhub:@openclaw/diagnostics-otel yourself only if you removed it. To enable export, allow and enable the diagnostics-otel plugin in config, then set diagnostics.otel.enabled=true (see the full example in OpenTelemetry export). Collector auth headers go through diagnostics.otel.headers, not Docker environment variables.
Prometheus metrics reuse the already-published Gateway port. Install clawhub:@openclaw/diagnostics-prometheus, enable the diagnostics-prometheus plugin, then scrape:
/metrics port or unauthenticated reverse-proxy path. See Prometheus metrics.
Health checks
Container probe endpoints (no auth required):HEALTHCHECK pings /healthz; repeated failures mark the container unhealthy so orchestrators can restart or replace it.
Use /startupz for an orchestrator startup or readiness probe so a failed channel account does not remove the otherwise healthy Gateway and Control UI from service. Use /readyz for monitoring that intentionally treats hard channel failures as not ready. See Health checks for response details.
Authenticated deep health snapshot:
Detailed topics
Environment variables
The full variable table, apt/pip build extras, and build-memory tuning.
Networking and storage
LAN vs loopback, host.docker.internal, Claude CLI, Bonjour, and mounted state.
Compose operations
Compose command table, sandbox/CI/DNS/EACCES accordions, and image refreshes.
Sandbox and troubleshooting
Enabling the agent sandbox plus the Docker troubleshooting accordions.
- Environment variables
- LAN vs loopback
- Host local providers
- Claude CLI backend in Docker
- Bonjour / mDNS
- Storage and persistence
- ClawDock migration
- Image contents and security scanning
- Weekly image refreshes
- Running on a VPS?
- Agent sandbox
- Troubleshooting
Related
- Install Overview — all installation methods
- Podman — Podman alternative to Docker
- Kubernetes — a minimal Kustomize starting point for running the Gateway on a cluster
- Ansible — automated server deployment with Tailscale VPN and firewall isolation
- Cloudflare Containers — experimental Worker plus container deployment with Litestream backups to R2
- Updating — keeping OpenClaw up to date
- Configuration — Gateway configuration after install