Running OpenClaw in Docker: images, volumes, and the port-binding trap
The official Docker setup, what must be volume-mounted for your agent to survive, and the default that quietly puts the Gateway on your network.
OpenClaw ships official Docker images (ghcr.io/openclaw/openclaw) and a Compose-based setup. Three things decide whether your containerized agent thrives: mount the state directories as volumes (or your agent’s memory dies with the container), pin a version tag instead of latest, and check what the Gateway port is bound to. The Docker setup’s default bind is lan, which is broader than the loopback default you may expect from a native install.
The official images
Images are published to GitHub Container Registry, with a Docker Hub mirror (whether to run these prebuilt images at all, versus npm or building from source, is its own decision):
ghcr.io/openclaw/openclaw:<version>is the pinned release, the right choice for anything you intend to keep. Tags likelatestandmainexist, but a long-running stateful agent shouldn’t follow a moving tag: surprise upgrades are how a working setup becomes a mystery, and the security audit itself flags unpinned installs.- The
-browservariants ship Chromium baked in. Get this one if your agent will browse or do anything screen-shaped, rather than installing a browser into a running container.
Volumes: the difference between an agent and an amnesiac
Inside the container, OpenClaw’s state lives under /home/node/.openclaw (config, sessions, workspace) and /home/node/.config/openclaw (auth secrets). The official Compose file mounts both from the host. The docs put it plainly: those paths survive container replacement. Everything rides on that mount: your agent’s whole identity is that directory. Get it right and containers become disposable: you can recreate, upgrade, and reboot and the agent comes back itself. Get it wrong and the first docker compose down erases your agent’s mind.
The port-binding trap
The one setting worth double-checking before anything else: the official Docker setup defaults the Gateway bind to lan (so the host can reach the dashboard through Docker’s port publishing), and the Compose file publishes port 18789. On a laptop behind a home router that’s merely worth knowing. On a VPS with a public address, a published Gateway port is the exact exposure OpenClaw’s own security docs say must never happen: an unauthenticated Gateway is remote control of a machine that can run commands. On any internet-facing host: bind to loopback (OPENCLAW_GATEWAY_BIND=loopback), publish the port to 127.0.0.1 only or not at all, and run openclaw security audit (inside the container, via docker compose exec) after every networking change.
Setup, and the fine print worth knowing
The repo ships a setup script (./scripts/docker/setup.sh) that prompts for provider keys, generates a Gateway token into .env (kept out of the container itself: .env vs env_file matters here), and starts Compose; there’s also a manual flow (docker compose run the onboarding, then docker compose up -d). Three facts from the official docs that save real debugging time:
- Building the image needs ~2 GB of RAM: on a 1 GB host the build gets OOM-killed with exit code 137. Use the prebuilt images on small machines.
127.0.0.1inside the container is the container, not your host. Local model runners like Ollama on the host are reached viahost.docker.internal.- The dashboard wants its token: the setup script writes it to
.env; you paste it athttp://127.0.0.1:18789/on first visit.
If you’d rather have all of that arrive assembled, that is what an Everpod pod is; if you’re building it yourself, the safe-hosting checklist is the standard worth holding your setup to.