Skip to content

fix(openclaw): use named volume for home dir to fix crash loop#831

Open
yasinBursali wants to merge 4 commits intoLight-Heart-Labs:mainfrom
yasinBursali:fix/openclaw-crash-loop
Open

fix(openclaw): use named volume for home dir to fix crash loop#831
yasinBursali wants to merge 4 commits intoLight-Heart-Labs:mainfrom
yasinBursali:fix/openclaw-crash-loop

Conversation

@yasinBursali
Copy link
Copy Markdown
Contributor

What

Replace the OpenClaw bind mount ./data/openclaw/home:/home/node/.openclaw with a named Docker volume (openclaw-home).

Why

Docker creates bind mount directories as root:root on the host. The container's node user cannot write to /home/node/.openclaw/openclaw.json, so inject-token.js Part 1 fails silently. The gateway then starts without allowedOrigins, and since --bind lan requires explicit origins (OpenClaw 2026.3.8+), the gateway crash-loops.

How

Named volumes are initialized by Docker with the image's directory ownership (node:node), so inject-token.js can write the patched config with allowedOrigins and dangerouslyAllowHostHeaderOriginFallback. The workspace bind mount (./config/openclaw/workspace) is preserved as an overlay on the named volume.

Testing

  • docker compose config validates cleanly
  • Manual: fresh install, verify OpenClaw starts without crash loop
  • Manual: verify Control UI loads at http://localhost:7860
  • Verify: docker exec dream-openclaw ls -la /home/node/.openclaw/ shows node ownership

Review

Critique Guardian: APPROVED WITH WARNINGS

Platform Impact

  • macOS: Named volumes work identically on Docker Desktop
  • Linux: Named volumes work identically on Docker Engine
  • Windows/WSL2: Named volumes work identically on Docker Desktop

yasinBursali and others added 2 commits April 6, 2026 20:52
The bind mount ./data/openclaw/home:/home/node/.openclaw created a
root-owned directory on the host. The container's node user could not
write the patched runtime config (inject-token.js Part 1), causing the
gateway to start without allowedOrigins and crash-loop on non-loopback
bind.

Replace with a named volume (openclaw-home) which Docker initializes
with the image's directory ownership, allowing inject-token.js to write
the config with allowedOrigins and dangerouslyAllowHostHeaderOriginFallback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase 06 wrote openclaw.json, auth-profiles.json, and models.json to
data/openclaw/home/ which was a bind mount. Now that the compose uses a
named volume (openclaw-home), these files are invisible to the container.

Remove the writes — inject-token.js patches the runtime config from the
read-only config templates at container startup, so installer seeding is
not needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Part 1 of inject-token.js patches allowedOrigins and
dangerouslyAllowHostHeaderOriginFallback into ~/.openclaw/openclaw.json,
but that write fails with EACCES when the volume is root-owned. The
gateway reads its config from /tmp/openclaw-config.json (Part 3 output),
which was missing the gateway.controlUi section entirely.

Add the same gateway patches (allowedOrigins, allowInsecureAuth,
dangerouslyDisableDeviceAuth, dangerouslyAllowHostHeaderOriginFallback)
to Part 3's merge logic so the merged config always has them regardless
of whether Part 1 succeeds. Also pass OPENCLAW_EXTERNAL_PORT to the
container so inject-token.js can build correct origin URLs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@yasinBursali
Copy link
Copy Markdown
Contributor Author

Update: Fix for gateway.controlUi in merged config

Testing confirmed the named volume alone doesn't fix the crash — the volume is still root-owned, and Part 3's merged config (which the gateway actually reads) was missing the gateway.controlUi section entirely.

New commit adds gateway patching to Part 3 of inject-token.js:

  • allowedOrigins with http://localhost:<port> and http://127.0.0.1:<port>
  • dangerouslyAllowHostHeaderOriginFallback: true
  • allowInsecureAuth: true
  • dangerouslyDisableDeviceAuth: true

This ensures the merged config at /tmp/openclaw-config.json always has the correct gateway settings, regardless of whether Part 1's write to ~/.openclaw/openclaw.json succeeds.

Also passes OPENCLAW_EXTERNAL_PORT to the container so inject-token.js can build correct origin URLs.

@yasinBursali
Copy link
Copy Markdown
Contributor Author

Update: Fix for root-owned volume (Update 3 findings)

The gateway reads ~/.openclaw/openclaw.json at startup BEFORE loading $OPENCLAW_CONFIG. Even though Part 3 now correctly patches the merged config, the gateway applies its default security policy first from the home-dir config — which doesn't exist because the volume is root-owned.

New commit: Run entrypoint as user: "0:0" (root), chown -R 1000:1000 /home/node/.openclaw before running inject-token.js, then exec into docker-entrypoint.sh for the gateway. The chown is a no-op on subsequent starts once ownership is set.

This should resolve both the permission denied and the allowedOrigins issues together.

The OpenClaw gateway reads ~/.openclaw/openclaw.json at startup BEFORE
loading $OPENCLAW_CONFIG. The named volume is created root-owned by
Docker, so inject-token.js (running as node uid 1000) cannot write the
patched config with allowedOrigins.

Run the entrypoint as root (user: 0:0), chown the home dir to
node:node (uid 1000), then exec into docker-entrypoint.sh which handles
the actual gateway process. The chown runs once at container startup
and is a no-op on subsequent starts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@yasinBursali yasinBursali force-pushed the fix/openclaw-crash-loop branch from 779e1e2 to d495fe5 Compare April 6, 2026 21:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant