Containerized OpenClaw Gateway setup with Docker and Docker Compose
8.4K
Containerized OpenClaw Gateway setup with Docker and Docker Compose.
This repository provides:
Dockerfile based on Ubuntu 24.04openclaw.json on first rundocker-compose.yml service definitionDockerfile: image build and gateway entrypoint scriptdocker-compose.yml: local runtime configurationscripts/create-tag.sh: local release tag creation helper.github/workflows/tag-build.yml: builds and pushes Docker image on tag push.github/workflows/sync-upstream-major.yml: manual workflow to sync latest upstream major tag.github/workflows/bats-tests.yml: runs bats unit tests for release script changestests/create-tag.bats: unit tests for release tag scriptLICENSE: MIT licensedocker compose up -d --build
docker compose ps
curl http://127.0.0.1:18789/healthz
docker compose logs -f openclaw-gateway
docker compose down
After the first startup, enter the container and run onboarding:
docker compose exec openclaw-gateway bash
openclaw onboard
Notes for first-time setup:
openclaw onboard again.By default, Compose maps the following host directories:
./.docker/openclaw/config -> /home/node/.openclaw./.docker/openclaw/workspace -> /home/node/.openclaw/workspaceThe container entrypoint creates these directories automatically when needed.
If /home/node/.openclaw/openclaw.json does not exist, the entrypoint generates it with:
gateway.mode from OPENCLAW_INIT_GATEWAY_MODE (default: local)gateway.bind from OPENCLAW_GATEWAY_BIND (default: lan)gateway.auth.token from OPENCLAW_GATEWAY_TOKEN, or auto-generated when emptygateway.controlUi.allowedOrigins from OPENCLAW_INIT_CONTROL_UI_ALLOWED_ORIGINS, or http://127.0.0.1:<port> by defaultIf a token is generated automatically, it is persisted in openclaw.json and reused on later starts.
You can place these in a .env file next to docker-compose.yml.
| Variable | Default | Description |
|---|---|---|
OPENCLAW_VERSION | latest | OpenClaw version passed to image build (install.sh --version) |
OPENCLAW_GATEWAY_BIND | lan | Gateway bind strategy passed to openclaw gateway --bind |
OPENCLAW_GATEWAY_PORT | 18789 | Gateway HTTP port |
OPENCLAW_BRIDGE_PORT | 18790 | Bridge port exposed by Compose |
OPENCLAW_GATEWAY_TOKEN | empty | Gateway auth token. If empty and config missing, one is generated |
OPENCLAW_INIT_GATEWAY_MODE | local | Initial gateway.mode for generated config |
OPENCLAW_INIT_CONTROL_UI_ALLOWED_ORIGINS | auto | JSON array string for allowed control UI origins |
OPENCLAW_GATEWAY_CONTROLUI_DANGEROUSLY_ALLOW_HOST_HEADER_ORIGIN_FALLBACK | false | Initial fallback behavior in generated config |
OPENCLAW_ALLOW_INSECURE_PRIVATE_WS | empty | Forwarded to container runtime environment |
OPENCLAW_CONFIG_DIR | ./.docker/openclaw/config | Host directory for OpenClaw state/config |
OPENCLAW_WORKSPACE_DIR | ./.docker/openclaw/workspace | Host directory for workspace |
CLAUDE_AI_SESSION_KEY | empty | Optional key forwarded into container |
CLAUDE_WEB_SESSION_KEY | empty | Optional key forwarded into container |
CLAUDE_WEB_COOKIE | empty | Optional cookie forwarded into container |
If you did not set OPENCLAW_GATEWAY_TOKEN manually, inspect the generated config:
jq -r '.gateway.auth.token' ./.docker/openclaw/config/openclaw.json
If jq is not installed:
grep -n '"token"' ./.docker/openclaw/config/openclaw.json
Build image:
docker build --build-arg OPENCLAW_VERSION=2026.3.11 -t openclaw:local .
Run container directly:
docker run --rm -it \
-p 18789:18789 -p 18790:18790 \
-e OPENCLAW_GATEWAY_BIND=lan \
-v "$PWD/.docker/openclaw/config:/home/node/.openclaw" \
-v "$PWD/.docker/openclaw/workspace:/home/node/.openclaw/workspace" \
openclaw:local gateway
Use the script from repository root:
./scripts/create-tag.sh
Optional: force a specific major version:
./scripts/create-tag.sh --major 2026.3.11
Script behavior:
git fetch --tags origin firstopenclaw/openclaw stable tags only (vX.Y.Z, excludes -beta.*)--major is provided, it must exist in openclaw/openclawvX.Y.Z, it creates vX.Y.ZvX.Y.Z, it creates the next patch tag vX.Y.Z.N (auto increment)Push manually when ready:
git push origin <tag>
Workflow: .github/workflows/tag-build.yml
git push of tag matching v*tenfyzhong/openclaw:<git-tag-without-v>tenfyzhong/openclaw:latestOPENCLAW_VERSION always uses major base (X.Y.Z)
v2026.3.11.2 builds with OPENCLAW_VERSION=2026.3.11Workflow: .github/workflows/sync-upstream-major.yml
Run manually from GitHub:
ActionsSync Latest Upstream Major TagRun workflowBehavior:
openclaw/openclawgit fetch --tags origintag-build.yml to build/push Docker imageConfigure repository secrets in Settings -> Secrets and variables -> Actions:
DOCKERHUB_USERNAME: Docker Hub usernameDOCKERHUB_TOKEN: Docker Hub access token (for docker/login-action)RELEASE_PUSH_TOKEN: GitHub token used by manual sync workflow to push tagsRELEASE_PUSH_TOKENRecommended: Fine-grained personal access token.
SettingsDeveloper settings -> Personal access tokens -> Fine-grained tokensGenerate new tokenRepository access: select only this repositoryRepository permissions:
Contents: Read and writeMetadata: Read-only (default)Settings -> Secrets and variables -> ActionsNew repository secretRELEASE_PUSH_TOKENAfter saving, rerun Sync Latest Upstream Major Tag workflow.
bats tests/create-tag.bats
CI workflow Bats Unit Tests runs automatically on:
mainmainmain branch on GitHubTo require CI success before merge and block direct pushes:
Settings -> Branches -> Add branch protection ruleBranch name pattern to mainRequire a pull request before mergingRequire status checks to pass before mergingBats Unit Tests / batsRequire branches to be up to date before merging (recommended)Include administrators (recommended)Restrict who can push to matching branches and leaving only trusted automation/usersAllow force pushes and Allow deletions disabledlan. Ensure your host firewall and network policy are appropriate.OPENCLAW_GATEWAY_TOKEN for non-local environments.This project is licensed under the MIT License. See LICENSE for details.
Content type
Image
Digest
sha256:4f270b951…
Size
1.2 GB
Last updated
5 days ago
docker pull tenfyzhong/openclaw