From ff8e960ae14a6e0b0cb8a80a69789c1e8eeecf60 Mon Sep 17 00:00:00 2001 From: Nim G Date: Fri, 6 Mar 2026 21:25:22 -0300 Subject: [PATCH 1/4] fix(build): grep for gosu to detect VPS Dockerfile patch, not docker.io MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The upstream Dockerfile now contains "docker.io" in its LABEL metadata (docker.io/library/node:22-bookworm), causing the old grep to return a false positive and skip the gosu+Docker patch. The container then crashed in the entrypoint with "gosu: command not found". Grep for "gosu" instead — it is only present after the patch is applied. --- deploy/host/build-openclaw.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deploy/host/build-openclaw.sh b/deploy/host/build-openclaw.sh index adb6e6a..a60b2e3 100755 --- a/deploy/host/build-openclaw.sh +++ b/deploy/host/build-openclaw.sh @@ -87,7 +87,9 @@ HOST_NEEDS_RESTORE=true # ── 4. Apply patches ──────────────────────────────────────────────── # 4a. Dockerfile: install Docker + gosu for nested Docker -if ! grep -q "docker.io" Dockerfile; then +# Note: grep for "gosu" specifically — the upstream Dockerfile contains "docker.io" in +# its LABEL metadata (docker.io/library/node:...) which would give a false positive. +if ! grep -q "gosu" Dockerfile; then echo "[build] Patching Dockerfile to install Docker + gosu..." sed -i '0,/^USER node/{/^USER node/i RUN apt-get update && apt-get install -y --no-install-recommends docker.io gosu gettext-base && usermod -aG docker node && rm -rf /var/lib/apt/lists/* }' Dockerfile From 835c0d3afb2f87c8bc30d7cb1b19af4a170c0ca5 Mon Sep 17 00:00:00 2001 From: Nim G Date: Fri, 6 Mar 2026 21:25:53 -0300 Subject: [PATCH 2/4] fix(workers): use valid-format placeholder IDs in wrangler.jsonc examples Wrangler 4.71 validates the entire config before executing any subcommand, including kv namespace create and d1 create. Empty string ("") for kv_namespaces id and non-UUID strings for d1 database_id both fail validation with a schema error before the create command can run. Replace both placeholders with valid-format dummy values that pass schema validation, so the user can run the create commands before filling in real IDs. The playbook already documents updating these values after creation. --- workers/ai-gateway/wrangler.jsonc.example | 2 +- workers/log-receiver/wrangler.jsonc.example | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/workers/ai-gateway/wrangler.jsonc.example b/workers/ai-gateway/wrangler.jsonc.example index 5634db6..c5128e0 100644 --- a/workers/ai-gateway/wrangler.jsonc.example +++ b/workers/ai-gateway/wrangler.jsonc.example @@ -10,7 +10,7 @@ // Create namespace: wrangler kv namespace create AUTH_KV // Then paste the returned ID below. "kv_namespaces": [ - { "binding": "AUTH_KV", "id": "" } + { "binding": "AUTH_KV", "id": "00000000000000000000000000000000" } ], // Workers Logs: enables console.log in the worker diff --git a/workers/log-receiver/wrangler.jsonc.example b/workers/log-receiver/wrangler.jsonc.example index 9c7493c..b86611a 100644 --- a/workers/log-receiver/wrangler.jsonc.example +++ b/workers/log-receiver/wrangler.jsonc.example @@ -28,7 +28,7 @@ { "binding": "DB", "database_name": "openclaw-logs", - "database_id": "" + "database_id": "00000000-0000-0000-0000-000000000000" } ], From 85dfc8da1bcb38b9e67c1d3c3af51e8b13a47bc6 Mon Sep 17 00:00:00 2001 From: Nim G Date: Fri, 6 Mar 2026 21:26:54 -0300 Subject: [PATCH 3/4] docs(workers): document CF API token permissions, account ID, and prereqs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fresh deployment uncovered several setup gaps: 1. workers.dev subdomain must be registered before first deploy — wrangler exits immediately without a useful error if it hasn't been claimed. 2. CLOUDFLARE_API_TOKEN requires Workers Scripts:Edit, Workers KV Storage:Edit, and D1:Edit permissions in addition to Tunnel and DNS Edit. The previous list was incomplete, causing confusing 403 errors during kv namespace create and d1 create. 3. Multi-account tokens fail wrangler's /memberships lookup even when valid. Setting CLOUDFLARE_ACCOUNT_ID in .env bypasses the lookup. 4. cf-tunnel-setup.sh requires jq locally (not documented). Add it to the script header alongside CF_API_TOKEN. --- playbooks/01-workers.md | 15 +++++++++++++++ scripts/cf-tunnel-setup.sh | 3 +++ 2 files changed, 18 insertions(+) diff --git a/playbooks/01-workers.md b/playbooks/01-workers.md index 6c665e2..5b6c67c 100644 --- a/playbooks/01-workers.md +++ b/playbooks/01-workers.md @@ -14,6 +14,21 @@ This playbook deploys: - Cloudflare account with Workers enabled - Node.js and npm installed locally - `wrangler` CLI available (installed as devDependency) +- A **workers.dev subdomain** registered for your account (one-time setup: Cloudflare Dashboard → Workers & Pages → Overview → claim your `.workers.dev` subdomain) + +### Cloudflare API Token + +All `wrangler` commands in this playbook read the API token from `CLOUDFLARE_API_TOKEN` in `.env` (exported via `source-config.sh`). The token must have the following permissions: + +| Resource | Permission | +|----------|------------| +| Account — Cloudflare Tunnel | Edit | +| Zone — DNS | Edit | +| Account — Workers Scripts | Edit | +| Account — Workers KV Storage | Edit | +| Account — D1 | Edit | + +> **Multi-account:** If your Cloudflare API token covers multiple accounts, wrangler's `/memberships` lookup may fail or select the wrong account. Set `CLOUDFLARE_ACCOUNT_ID` in `.env` to your Cloudflare account ID (from `wrangler whoami`) to bypass the lookup. Without it, `wrangler kv namespace create` and `wrangler d1 create` may fail with a 403 even when the token is correct. ## Variables diff --git a/scripts/cf-tunnel-setup.sh b/scripts/cf-tunnel-setup.sh index fa4c3d7..2e456fe 100755 --- a/scripts/cf-tunnel-setup.sh +++ b/scripts/cf-tunnel-setup.sh @@ -21,6 +21,9 @@ set -euo pipefail # Environment: # CF_API_TOKEN Required — Cloudflare API token with Tunnel Edit + DNS Edit # CF_TUNNEL_TOKEN Optional — used to extract tunnel ID if --tunnel-id not given +# +# Local dependencies: +# jq Required — install with: brew install jq (macOS) / apt install jq (Linux) # Resolve paths via canonical config helper SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" From fbdc2709d120d7492eb97e79ad6ba696fdd46683 Mon Sep 17 00:00:00 2001 From: Nim G Date: Fri, 6 Mar 2026 21:48:40 -0300 Subject: [PATCH 4/4] fix(compose): use host networking for cloudflared With bridge networking, cloudflared's tunnel ingress routes to localhost:PORT inside the cloudflared container, not the host where openclaw gateway ports are published (127.0.0.1:PORT). This causes Cloudflare 520 errors on first deploy. Switch cloudflared to network_mode: host so localhost resolves to the host's loopback, matching the port bindings in the openclaw container. --- docker-compose.yml.hbs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml.hbs b/docker-compose.yml.hbs index 743fca7..bfc1410 100644 --- a/docker-compose.yml.hbs +++ b/docker-compose.yml.hbs @@ -112,7 +112,9 @@ services: command: tunnel run environment: - TUNNEL_TOKEN={{stack.cloudflare.tunnel_token}} - networks: [openclaw-net] + # Host networking so tunnel ingress can reach localhost-bound ports + # (openclaw gateway ports are published on 127.0.0.1, not on the bridge network). + network_mode: host deploy: resources: limits: