This guide helps you build an OpenClaw base image for the ClawManager control plane, with automated config injection (API Key, Base URL, etc.) and persistent directory layout for multi-tenant scenarios.
The image now also includes an OpenClaw Agent service inside the container. It auto-registers to ClawManager, sends heartbeats, polls commands, manages the OpenClaw process, and exposes a local Gin-based health endpoint.
Prefer Dockerfile.openclaw for a one-shot build. If you need to install components manually inside the WebTop desktop and then docker commit, see Advanced: manual flow below.
In ClawManager batch scenarios, per-container manual setup does not scale. This project addresses:
- Pre-installed runtime: Node.js and the latest OpenClaw CLI, ready to use.
- Agent-driven bootstrap:
openclaw-agent(Go) runs as root at container start, seeds/config/.openclawfrom/defaults/.openclaw, reconciles channel plugins, fixes ownership, and drops privileges toabcbefore launching OpenClaw. - Dynamic injection: Environment variables update
openclaw.jsonwithout editing files in the desktop session.
The image is based on lscr.io/linuxserver/webtop:ubuntu-xfce. The Dockerfile installs Node.js and global OpenClaw, seeds /defaults/.openclaw, and ships the openclaw-agent binary as an s6 service. On every container start the agent performs all bootstrap work (defaults sync, extensions directory, XFCE autostart, config normalization, channel reconciliation) and then drops privileges to abc before launching openclaw gateway run. Runtime config lives under /config/.openclaw, not ~/.openclaw. Look for openclaw-agent lines in the container logs after startup.
Bash
docker build -f Dockerfile.openclaw -t openclaw:local .
Set shared memory: always pass
--shm-size="1gb"(at least 1GB) when running WebTop, or the browser/desktop stack may crash or behave oddly.
Bash
docker run -d \
--name=webtop-openclaw \
--shm-size="1gb" \
--restart unless-stopped \
-e PUID=1000 \
-e PGID=1000 \
-e TZ=Asia/Shanghai \
-e CLAWMANAGER_LLM_BASE_URL=https://your-gateway/v1 \
-e CLAWMANAGER_LLM_API_KEY=your-sk-key \
-e CLAWMANAGER_LLM_MODEL=gpt-4o \
-p 3000:3000 \
-p 3001:3001 \
openclaw:local
Adjust ports and placeholders as needed.
Set these in ClawManager or docker run to inject into openclaw.json:
| Variable | Config path | Purpose |
|---|---|---|
CLAWMANAGER_LLM_BASE_URL |
models.providers.auto.baseUrl |
Gateway or upstream base URL |
CLAWMANAGER_LLM_API_KEY |
apiKey |
Model API key |
CLAWMANAGER_LLM_MODEL |
primary / agents.defaults.models |
Model id replacement; supports a single id or a JSON array; handled by the agent's config normalizer |
CLAWMANAGER_OPENCLAW_CHANNELS_JSON |
channels (merge) |
JSON object with one or more channel keys (feishu, slack, …); shallow-merge into channels; invalid JSON aborts startup |
OPENCLAW_AGENT_INSTANCE_ID |
agent bootstrap | Required. Unique instance id used during /api/v1/agent/register |
OPENCLAW_AGENT_BOOTSTRAP_TOKEN |
agent bootstrap | Required. Bootstrap token for agent registration |
OPENCLAW_AGENT_CONTROL_PLANE_BASE_URL |
agent bootstrap | Required. ClawManager base URL |
OPENCLAW_AGENT_INITIAL_CONFIG_REVISION_ID |
agent bootstrap | Optional initial revision id |
OPENCLAW_AGENT_OPENCLAW_COMMAND |
process management | Optional. Defaults to openclaw gateway |
The agent default config is stored at /etc/openclaw-agent/config.yaml, seeded from /defaults/openclaw-agent/config.yaml, and the local health/debug server listens on :18080 by default.
The workflow .github/workflows/docker-ghcr.yml builds Dockerfile.openclaw on push to the default branch (main / master) or on v* tags, and pushes to GitHub Container Registry so you do not need a local docker build for releases.
Short checklist
- Push the repo to GitHub and confirm Build and push to GHCR succeeds under Actions.
- Find the package under Packages; the image is usually
ghcr.io/<user>/<repo>. - For private packages, run
docker login ghcr.iofirst; set the package to Public if you want anonymousdocker pull.
Bash
docker pull ghcr.io/<github_user>/<repo>:latest
docker run -d \
--name=webtop-openclaw \
--shm-size="1gb" \
--restart unless-stopped \
-e PUID=1000 -e PGID=1000 -e TZ=Asia/Shanghai \
-e CLAWMANAGER_LLM_BASE_URL=https://your-gateway/v1 \
-e CLAWMANAGER_LLM_API_KEY=your-sk-key \
-e CLAWMANAGER_LLM_MODEL=gpt-4o \
-e CLAWMANAGER_OPENCLAW_CHANNELS_JSON='{"feishu":{"enabled":true,"accounts":{"main":{"appId":"cli_xxx","appSecret":"your-secret"}}}}' \
-p 3000:3000 -p 3001:3001 \
ghcr.io/<github_user>/<repo>:latest
Pushing tags like v1.0.0 also publishes semver tags per the workflow metadata rules.
Use this when you must install extra tooling inside WebTop before saving an image. It is an alternative to Dockerfile.openclaw.
Open https://<IP>:3001, then in a terminal:
Bash
curl -fsSL https://deb.nodesource.com/setup_current.x | sudo -E bash -
sudo apt-get install -y nodejs
npm config set registry https://registry.npmmirror.com
sudo npm install -g openclaw@latest
- Seed defaults:
cp -rp /config/.openclaw /defaults/. - Install agent: copy the compiled
openclaw-agentbinary into/usr/local/bin/and installscripts/openclaw-agent-run/openclaw-agent-finishunder/etc/services.d/openclaw-agent/. The agent performs the/defaults→/configsync and env-based edits on every start. - Clean before image save:
rm -rf /config/.openclaw. If this step is skipped, new containers may not run first-boot init as expected.
Bash
docker commit webtop-running openclaw:v1.0
- Permissions: the agent runs
chown -R abc:abcon/config/.openclawand/config/.config/autostartbefore dropping toabc, so the default user can read/write persisted config. - Docker Compose: point
imageat your built tag, or usebuildwithdockerfile: Dockerfile.openclaw. Do not rely on the stockwebtopimage alone; it will not include this repo’s templates and agent service. - Standalone WebTop: if you do not use ClawManager batch features, you can skip the ClawManager-specific steps in the advanced flow.
