#Preconfigured runs in docker
63 messages · Page 1 of 1 (latest)
Let me verify the docs location and then I’ll pull the exact Docker/onboarding bits from the docs/source.
I found the Docker docs plus the non-interactive onboarding path. I’m pulling one more bit from the setup script so I don’t hand-wave the recommended Compose pattern.
Yes, this is doable, and the cleanest pattern is:
- No system service inside Docker
- One
openclaw-gatewayservice - One
openclaw-clihelper service - Persist only config + workspace via volumes
- Use non-interactive onboarding before first
compose up
A few best practices from the docs/source:
- Do not use
--install-daemonin the container flow. For Compose-only, let Docker be the supervisor. - Persist these paths:
OPENCLAW_CONFIG_DIR→/home/node/.openclawOPENCLAW_WORKSPACE_DIR→/home/node/.openclaw/workspace
- Before the gateway is started, run setup through
openclaw-gatewaywith--entrypoint node, notopenclaw-cli.openclaw-cliis meant for post-start use because it shares the gateway network namespace.
- For Docker, set:
gateway.mode = localgateway.bind = langateway.controlUi.allowedOrigins = ["http://localhost:18789","http://127.0.0.1:18789"]
- Use SecretRefs/env-backed secrets instead of baking tokens into
openclaw.jsonwhen possible. - Use
--skip-healthduring bootstrap, otherwise non-interactive onboarding waits for a gateway that is not up yet.
So yes, there is a non-interactive onboarding path.
Example bootstrap:
docker compose run --rm --no-deps --entrypoint node openclaw-gateway \
dist/index.js onboard --non-interactive \
--mode local \
--auth-choice openai-api-key \
--secret-input-mode ref \
--gateway-auth token \
--gateway-token-ref-env OPENCLAW_GATEWAY_TOKEN \
--skip-skills \
--skip-health \
--accept-risk
docker compose run --rm --no-deps --entrypoint node openclaw-gateway \
dist/index.js config set --batch-json '[{"path":"gateway.mode","value":"local"},{"path":"gateway.bind","value":"lan"},{"path":"gateway.controlUi.allowedOrigins","value":["http://localhost:18789","http://127.0.0.1:18789"]}]'
docker compose up -d openclaw-gateway
Then post-start, use the CLI container for extra setup:
docker compose run --rm openclaw-cli dashboard --no-open
docker compose run --rm openclaw-cli channels add --channel discord --token "$DISCORD_BOT_TOKEN"
One important caveat: fully non-interactive only works for API-key/token based setup. Things like WhatsApp QR login or some OAuth flows still need a human step.
Relevant docs:
- https://docs.openclaw.ai/install/docker
- https://docs.openclaw.ai/cli/onboard
- https://docs.openclaw.ai/start/wizard-cli-automation
- https://docs.openclaw.ai/cli/channels
If you want, I can turn this into a ready-to-run docker-compose.yml + bootstrap script for your provider.
I want to centrally monitor all messages and discussions from these agents. What are my options? Ideally I want to put them in a database
I’m checking the docs/source for the supported ways to capture agent conversations and whether there’s a built-in database sink versus file/session export.
Short version: today the canonical conversation store is the on-disk session transcripts, not a built-in SQL database backend.
Your main options are:
-
Use the session JSONL files as the source of truth
Best if you want the full chat history / tool calls / discussions.Paths on the gateway host:
~/.openclaw/agents/<agentId>/sessions/sessions.json~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl
In your Docker setup, that means reading from the mounted
OPENCLAW_CONFIG_DIR, for example:OPENCLAW_CONFIG_DIR/agents/<agentId>/sessions/*.jsonl
This is what I’d use for a DB ingest pipeline into Postgres, ClickHouse, Elasticsearch, etc.
-
Enable diagnostics + OpenTelemetry export
Best if you want central monitoring, dashboards, alerts, latency/cost/message-flow metrics.
OpenClaw supports OTLP export via the diagnostics-otel plugin. That gives you:
- metrics
- traces
- logs
And the spans/events already include useful fields like:
sessionKeysessionIdchatIdmessageId- provider/model
- token/cost info
Good fit for Grafana/Tempo/Loki, Elastic, Datadog, Honeycomb, etc.
-
Ship the gateway log file
Useful for ops, but not the best canonical transcript source.Default file log:
/tmp/openclaw/openclaw-YYYY-MM-DD.log
My recommendation:
- If you want exact conversations in a database: ingest the session
*.jsonltranscripts - If you want observability: also enable OTel diagnostics
- If you want both: do both, they solve different problems
A good Docker pattern is:
- mount
OPENCLAW_CONFIG_DIR - run OpenClaw normally
- add a sidecar that tails
agents/*/sessions/*.jsonl
- parse and insert into your DB
I do not see a first-class “store sessions directly in Postgres/MySQL” config in the docs right now.
Docs:
- https://docs.openclaw.ai/reference/session-management-compaction
- https://docs.openclaw.ai/logging
- https://docs.openclaw.ai/install/docker
If you want, I can sketch a recommended architecture for:
- Postgres
- ClickHouse
- or OTel Collector + database sink
is it possible to monitor and log tool calls?
I’m checking whether tool calls are exposed through transcripts only, regular logs, or the diagnostics/OTel path too, so I can answer this cleanly.
Yes, but with an important nuance:
There isn’t a dedicated built-in “tool audit log” database sink that I can see.
The supported ways to monitor tool calls today are:
-
Session transcripts (best audit trail)
Tool calls + tool results are persisted in the session transcript JSONL files.
That is the most complete source if you want exact history.Path:
~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl
In Docker, read them from your mounted
OPENCLAW_CONFIG_DIR. -
Live verbose output (good for watching runs)
/verbose onshows tool calls as separate tool-summary bubbles/verbose fullalso shows tool outputs
I’d be careful with this in group chats, because it can expose internals/tool output.
-
Plugin hooks (best for real-time custom logging to DB/queue)
OpenClaw exposes hooks for:before_tool_callafter_tool_calltool_result_persist
So if you want “every tool call goes to Postgres/Kafka/Redis/HTTP collector”, a small plugin is the cleanest real-time path.
-
Gateway logs
Some tool-related summaries/output can land in logs, and those can be shipped centrally, but logs are not as clean/canonical as the session transcript.
One very important security note:
logging.redactSensitive: "tools"only masks console tool summaries- it does not rewrite the stored transcript
- and it does not protect file logs / OTLP logs the same way
So if you export logs/transcripts to a DB, treat them as sensitive.
My recommendation:
- For exact tool auditing: ingest the session
*.jsonl - For real-time monitoring: add a plugin using
before_tool_call+after_tool_call - For dashboards/ops: use diagnostics/OTel alongside that
Docs:
If you want, I can sketch a minimal plugin design that writes tool calls into Postgres.
lets go back to docker question. what's the best image to use for docker-based runs?
I’m checking the Docker docs for the supported image tags so I don’t guess and accidentally steer you to the wrong one.
For most Docker-based runs, I’d use:
ghcr.io/openclaw/openclaw:<version>
So, a pinned version tag, not latest.
My practical recommendation:
- Production / stable setup: use a specific version tag
Example:ghcr.io/openclaw/openclaw:2026.2.26 - Quickstart / personal testing:
ghcr.io/openclaw/openclaw:latest - Bleeding edge / bugfix verification:
ghcr.io/openclaw/openclaw:main
Why:
- Pinned version is best for reproducibility and predictable upgrades
latestis convenient, but less controlled
mainis for “I want the newest fix right now and accept breakage”
If you need custom extras, then I’d build your own image instead of relying purely on GHCR, especially if you want:
- extra apt packages
- bundled extensions
- sandbox-related customization
The docs call out the prebuilt image here:
export OPENCLAW_IMAGE="ghcr.io/openclaw/openclaw:latest"
./scripts/docker/setup.sh
And the common tags are:
mainlatest
<version>
Docs:
- https://docs.openclaw.ai/install/docker
- https://github.com/openclaw/openclaw/pkgs/container/openclaw
If you want, I can give you a recommended docker-compose.yml using a pinned image plus persistent volumes.
okay, let's say I update the image and mount an old volume - how do I ensure smooth upgrade? what if something does not work?
The safe mental model is:
the container is disposable, the mounted state is not.
So for smooth Docker upgrades, I’d do this:
-
Pin image tags
- Prefer
ghcr.io/openclaw/openclaw:<version> - Avoid blindly tracking
latestfor anything important
- Prefer
-
Back up the mounted state before switching images
- Back up
OPENCLAW_CONFIG_DIR - Also back up
OPENCLAW_WORKSPACE_DIRif it’s a separate mount
- Back up
-
Replace the container, don’t “update inside” it
docker compose pulldocker compose up -d
- I would not treat
openclaw updateinside the container as the main Docker upgrade path
-
Run doctor after the new image starts
docker compose exec openclaw-gateway openclaw doctor --non-interactive- If you want automatic repair/migration:
docker compose exec openclaw-gateway openclaw doctor --repair --non-interactive
-
Verify immediately
docker compose logs -f openclaw-gatewaycurl -fsS http://127.0.0.1:18789/healthz- Deep check:
docker compose exec openclaw-gateway node dist/index.js health --token "$OPENCLAW_GATEWAY_TOKEN"
A couple important nuances:
- OpenClaw does auto-run some doctor migrations on startup when it detects legacy config
- But I’d still run an explicit
doctor --non-interactiveafter an upgrade so you can see what changed
If something breaks:
Fast rollback
- switch back to the previous image tag
- restore the volume backup/snapshot
- start the old container again
That second step matters. Rolling back only the container image is not always enough if the newer version already migrated state/config.
Best-practice upgrade flow
If you want near-zero drama, do upgrades like this:
- snapshot/copy volume
- start the new image against the copied volume in a staging compose project
- run doctor + health checks there
- only then point prod at the new image
That’s the cleanest answer to “what if something doesn’t work?”
Docs:
- https://docs.openclaw.ai/install/docker
- https://docs.openclaw.ai/install/updating
- https://docs.openclaw.ai/gateway/doctor
- https://docs.openclaw.ai/install/migrating
If you want, I can sketch a recommended Docker upgrade workflow with exact docker compose commands for backup, test, and rollback.
Let me check the workspace docs so I can tell you the minimum files/layout to preseed without inventing anything.
Yep, for that you want openclaw setup, not onboarding.
Plain openclaw setup does exactly this:
- initializes
~/.openclaw/openclaw.json - creates/points the agent workspace
- does not run the full onboarding wizard unless you add wizard/onboarding flags
So the simplest Docker-friendly flow is:
docker compose exec openclaw-gateway \
openclaw setup --workspace /home/node/.openclaw/workspace
Then put your files into that mounted workspace:
AGENTS.mdSOUL.mdUSER.mdIDENTITY.mdTOOLS.md
Optional but useful:
HEARTBEAT.mdMEMORY.mdmemory/
A few important details:
- You do not need
BOOTSTRAP.mdif you’re restoring an already-defined personality/workspace openclaw setupis fine here, because it initializes config/workspace without forcing the interactive ritual- OpenClaw expects the workspace to just be a normal directory with those files, there’s no hidden “workspace database” you need to initialize separately
Also, workspace is separate from state/config:
- workspace/persona files live in the workspace dir
- auth, sessions, channel credentials, config live under
~/.openclaw/
So if you later want a fully preseeded install, you usually preseed both:
- the workspace
- the state dir
Docs:
- https://docs.openclaw.ai/cli/setup
- https://docs.openclaw.ai/concepts/agent-workspace
- https://docs.openclaw.ai/reference/wizard
If you want, I can give you a minimal Docker bootstrap recipe for:
- mounted preseeded workspace
- mounted state dir
- zero onboarding on first boot
I’m checking whether the docs spell out the exact mount pattern so I don’t suggest a Docker layout that fights the workspace path.
The reliable way is:
1) mount them explicitly
In Compose, mount both paths, not just one:
services:
openclaw-gateway:
image: ghcr.io/openclaw/openclaw:<version>
volumes:
- ${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw
- ${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace
That is the same pattern the Docker docs/useful setup script use.
2) pre-create both host directories
Before first start:
mkdir -p "$OPENCLAW_CONFIG_DIR"
mkdir -p "$OPENCLAW_WORKSPACE_DIR"
If you want them preseeded:
- put
openclaw.json, auth/session state, etc. intoOPENCLAW_CONFIG_DIR - put
AGENTS.md,SOUL.md,USER.md, etc. intoOPENCLAW_WORKSPACE_DIR
3) initialize config/workspace once
If config is not already there:
docker compose run --rm openclaw-cli \
setup --workspace /home/node/.openclaw/workspace
That gives you a valid state dir + workspace without full onboarding.
4) verify inside the container
docker compose exec openclaw-gateway ls -la /home/node/.openclaw
docker compose exec openclaw-gateway ls -la /home/node/.openclaw/workspace
You should see:
- config/state under
/home/node/.openclaw
- your persona/workspace files under
/home/node/.openclaw/workspace
practical rule
If you’re doing this by hand, think of it as:
- state dir = machine/runtime state
- workspace dir = agent personality + memory files
If you want, I can write you a minimal compose + bootstrap script that guarantees both exist before the gateway starts.
I’m grabbing the repo’s Docker layout so I can give you a recipe that matches the actual service names and paths.
Yep, here’s a minimal no-onboarding Docker recipe that guarantees both state and workspace exist.
1) directory layout
openclaw-docker/
.env
docker-compose.yml
data/
state/
workspace/
2) .env
OPENCLAW_IMAGE=ghcr.io/openclaw/openclaw:latest
OPENCLAW_CONFIG_DIR=./data/state
OPENCLAW_WORKSPACE_DIR=./data/workspace
OPENCLAW_GATEWAY_PORT=18789
OPENCLAW_BRIDGE_PORT=18790
OPENCLAW_GATEWAY_BIND=lan
OPENCLAW_GATEWAY_TOKEN=replace-me-with-a-random-token
OPENCLAW_TZ=UTC
3) docker-compose.yml
services:
openclaw-gateway:
image: ${OPENCLAW_IMAGE}
environment:
HOME: /home/node
TERM: xterm-256color
OPENCLAW_GATEWAY_TOKEN: ${OPENCLAW_GATEWAY_TOKEN}
TZ: ${OPENCLAW_TZ}
volumes:
- ${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw
- ${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace
ports:
- "${OPENCLAW_GATEWAY_PORT}:18789"
- "${OPENCLAW_BRIDGE_PORT}:18790"
init: true
restart: unless-stopped
command:
[
"node",
"dist/index.js",
"gateway",
"--bind",
"${OPENCLAW_GATEWAY_BIND}",
"--port",
"18789",
]
openclaw-cli:
image: ${OPENCLAW_IMAGE}
network_mode: "service:openclaw-gateway"
environment:
HOME: /home/node
TERM: xterm-256color
OPENCLAW_GATEWAY_TOKEN: ${OPENCLAW_GATEWAY_TOKEN}
BROWSER: echo
TZ: ${OPENCLAW_TZ}
volumes:
- ${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw
- ${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace
stdin_open: true
tty: true
init: true
entrypoint: ["node", "dist/index.js"]
depends_on:
- openclaw-gateway
4) preseed both directories
Run this from the openclaw-docker/ folder:
mkdir -p ./data/state ./data/workspace
mkdir -p ./data/state/identity
mkdir -p ./data/state/agents/main/agent
mkdir -p ./data/state/agents/main/sessions
Now copy in what you already have:
preseed workspace
cp /somewhere/AGENTS.md ./data/workspace/
cp /somewhere/SOUL.md ./data/workspace/
cp /somewhere/USER.md ./data/workspace/
cp /somewhere/IDENTITY.md ./data/workspace/ 2>/dev/null || true
cp /somewhere/TOOLS.md ./data/workspace/ 2>/dev/null || true
cp /somewhere/MEMORY.md ./data/workspace/ 2>/dev/null || true
optional: preseed state too
If you are restoring an existing install:
rsync -a /somewhere/.openclaw/ ./data/state/
That carries over config, auth, sessions, credentials, etc.
5) initialize config/workspace without onboarding
Before starting the gateway, run:
docker compose run --rm --no-deps --entrypoint node openclaw-gateway \
dist/index.js setup --workspace /home/node/.openclaw/workspace
Optional but nice to pin local Docker behavior:
docker compose run --rm --no-deps --entrypoint node openclaw-gateway \
dist/index.js config set --batch-json '[{"path":"gateway.mode","value":"local"},{"path":"gateway.bind","value":"lan"},{"path":"gateway.controlUi.allowedOrigins","value":["http://localhost:18789","http://127.0.0.1:18789"]}]'
6) start it
docker compose up -d openclaw-gateway
7) verify both mounts are really there
docker compose exec openclaw-gateway ls -la /home/node/.openclaw
docker compose exec openclaw-gateway ls -la /home/node/.openclaw/workspace
docker compose exec openclaw-gateway node dist/index.js health --token "$OPENCLAW_GATEWAY_TOKEN"
how this works
data/state= config/auth/sessions/credentialsdata/workspace=AGENTS.md,SOUL.md, memory files, etc.setupinitializes things without running full onboarding
- if you already copied a mature workspace, you do not need
BOOTSTRAP.md
Docs:
- https://docs.openclaw.ai/install/docker
- https://docs.openclaw.ai/cli/setup
- https://docs.openclaw.ai/concepts/agent-workspace
- https://docs.openclaw.ai/install/migrating
If you want, I can turn this into a single bootstrap.sh you can just run once.
give me ready to run docker compose
Yep, here’s a ready-to-run minimal Docker Compose setup.
.env
OPENCLAW_IMAGE=ghcr.io/openclaw/openclaw:latest
OPENCLAW_CONFIG_DIR=./data/state
OPENCLAW_WORKSPACE_DIR=./data/workspace
OPENCLAW_GATEWAY_PORT=18789
OPENCLAW_BRIDGE_PORT=18790
OPENCLAW_GATEWAY_BIND=lan
OPENCLAW_GATEWAY_TOKEN=replace-this-with-a-random-hex-token
OPENCLAW_TZ=UTC
docker-compose.yml
services:
openclaw-gateway:
image: ${OPENCLAW_IMAGE}
environment:
HOME: /home/node
TERM: xterm-256color
OPENCLAW_GATEWAY_TOKEN: ${OPENCLAW_GATEWAY_TOKEN}
TZ: ${OPENCLAW_TZ}
volumes:
- ${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw
- ${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace
ports:
- "${OPENCLAW_GATEWAY_PORT}:18789"
- "${OPENCLAW_BRIDGE_PORT}:18790"
init: true
restart: unless-stopped
command:
[
"node",
"dist/index.js",
"gateway",
"--bind",
"${OPENCLAW_GATEWAY_BIND}",
"--port",
"18789",
]
healthcheck:
test:
[
"CMD",
"node",
"-e",
"fetch('http://127.0.0.1:18789/healthz').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))",
]
interval: 30s
timeout: 5s
retries: 5
start_period: 20s
openclaw-cli:
image: ${OPENCLAW_IMAGE}
network_mode: "service:openclaw-gateway"
environment:
HOME: /home/node
TERM: xterm-256color
OPENCLAW_GATEWAY_TOKEN: ${OPENCLAW_GATEWAY_TOKEN}
BROWSER: echo
TZ: ${OPENCLAW_TZ}
volumes:
- ${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw
- ${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace
stdin_open: true
tty: true
init: true
entrypoint: ["node", "dist/index.js"]
depends_on:
- openclaw-gateway
first boot
mkdir -p ./data/state ./data/workspace
mkdir -p ./data/state/identity
mkdir -p ./data/state/agents/main/agent
mkdir -p ./data/state/agents/main/sessions
If you already have your workspace files:
cp /somewhere/AGENTS.md ./data/workspace/
cp /somewhere/SOUL.md ./data/workspace/
cp /somewhere/USER.md ./data/workspace/
cp /somewhere/IDENTITY.md ./data/workspace/ 2>/dev/null || true
cp /somewhere/TOOLS.md ./data/workspace/ 2>/dev/null || true
cp /somewhere/MEMORY.md ./data/workspace/ 2>/dev/null || true
Initialize without onboarding:
docker compose run --rm --no-deps --entrypoint node openclaw-gateway \
dist/index.js setup --workspace /home/node/.openclaw/workspace
Optional but nice:
docker compose run --rm --no-deps --entrypoint node openclaw-gateway \
dist/index.js config set --batch-json '[{"path":"gateway.mode","value":"local"},{"path":"gateway.bind","value":"lan"},{"path":"gateway.controlUi.allowedOrigins","value":["http://localhost:18789","http://127.0.0.1:18789"]}]'
Start it:
docker compose up -d openclaw-gateway
Check it:
docker compose logs -f openclaw-gateway
docker compose exec openclaw-gateway node dist/index.js health --token "$OPENCLAW_GATEWAY_TOKEN"
Then post-start stuff goes through openclaw-cli, for example:
docker compose run --rm openclaw-cli dashboard --no-open
docker compose run --rm openclaw-cli channels add --channel discord --token "$DISCORD_BOT_TOKEN"