openclaw - 💡(How to fix) Fix Bug: openclaw-cli cannot connect to gateway when bind=lan on Docker Desktop macOS (Apple Silicon) [3 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#49318Fetched 2026-04-08 00:56:33
View on GitHub
Comments
3
Participants
3
Timeline
5
Reactions
0
Author
Timeline (top)
commented ×3closed ×1locked ×1

When running the gateway with gateway.bind=lan inside Docker Desktop on macOS (Apple Silicon), the openclaw-cli container cannot connect to the gateway via WebSocket, making all CLI commands fail. This breaks the documented device pairing flow (devices list / devices approve).

Error Message

Error: gateway timeout after 10000ms Gateway target: ws://127.0.0.1:18789 Source: local loopback Bind: lan

Root Cause

The CLI container shares the gateway's network namespace via network_mode: service:openclaw-gateway. With bind=lan, the gateway process listens on 0.0.0.0:18789.

From inside the CLI container:

  • ws://127.0.0.1:18789timeout (loopback doesn't reach the gateway process in this namespace configuration under Docker Desktop macOS)
  • ws://0.0.0.0:18789blocked by CLI security check (non-loopback plaintext ws://)
  • ws://127.0.0.1:18789 with explicit --token1006 abnormal closure (gateway rejects the connection)

The core tension: bind=lan is required on Docker Desktop macOS for the host browser to reach the gateway via the published port (127.0.0.1:18789 → container:18789). But bind=lan breaks CLI connectivity from within the shared network namespace.

With bind=loopback, the CLI works but the host browser cannot reach the gateway (Docker Desktop port forwarding doesn't work with loopback-bound processes inside containers).

Fix Action

Workaround

Direct file manipulation via docker exec:

docker exec <gateway-container> node -e "
const fs = require('fs');
const crypto = require('crypto');
const pendingPath = '/home/node/.openclaw/devices/pending.json';
const pairedPath  = '/home/node/.openclaw/devices/paired.json';

const pending = JSON.parse(fs.readFileSync(pendingPath, 'utf8'));
let paired = {};
try { paired = JSON.parse(fs.readFileSync(pairedPath, 'utf8')); } catch(e) {}

for (const [reqId, req] of Object.entries(pending)) {
  paired[req.deviceId] = { ...req, approvedAt: Date.now(), approvedBy: 'admin', token: crypto.randomBytes(32).toString('hex') };
}
fs.writeFileSync(pairedPath, JSON.stringify(paired, null, 2));
fs.writeFileSync(pendingPath, JSON.stringify({}, null, 2));
"

# Reload gateway
docker exec <gateway-container> sh -c "kill -USR1 \$(pgrep -f 'openclaw-gateway' | head -1)"

This works but bypasses the CLI entirely.

Code Example

# docker-compose.yml
services:
  openclaw-gateway:
    image: ghcr.io/openclaw/openclaw:2026.3.13-1
    platform: linux/arm64
    ports:
      - "127.0.0.1:18789:18789"
    command: ["node", "dist/index.js", "gateway", "--bind", "lan", "--port", "18789"]
    volumes:
      - openclaw_data:/home/node/.openclaw

  openclaw-cli:
    image: ghcr.io/openclaw/openclaw:2026.3.13-1
    platform: linux/arm64
    network_mode: "service:openclaw-gateway"
    environment:
      OPENCLAW_GATEWAY_TOKEN: ${OPENCLAW_GATEWAY_TOKEN}
      OPENCLAW_ALLOW_INSECURE_PRIVATE_WS: "1"
    volumes:
      - openclaw_data:/home/node/.openclaw
    entrypoint: ["node", "dist/index.js"]
    profiles: [cli]

---

curl http://127.0.0.1:18789/healthz  # returns 200 OK

---

docker compose --profile cli run --rm -T openclaw-cli devices list

---

Error: gateway timeout after 10000ms
Gateway target: ws://127.0.0.1:18789
Source: local loopback
Bind: lan

---

Error: gateway url override requires explicit credentials
Fix: pass --token *** --password ***

---

Error: gateway closed (1006 abnormal closure (no close frame)): no close reason
Gateway target: ws://127.0.0.1:18789
Source: cli --url

---

SECURITY ERROR: Gateway URL "ws://0.0.0.0:18789" uses plaintext ws:// to a non-loopback address.

---

docker exec <gateway-container> node -e "
const fs = require('fs');
const crypto = require('crypto');
const pendingPath = '/home/node/.openclaw/devices/pending.json';
const pairedPath  = '/home/node/.openclaw/devices/paired.json';

const pending = JSON.parse(fs.readFileSync(pendingPath, 'utf8'));
let paired = {};
try { paired = JSON.parse(fs.readFileSync(pairedPath, 'utf8')); } catch(e) {}

for (const [reqId, req] of Object.entries(pending)) {
  paired[req.deviceId] = { ...req, approvedAt: Date.now(), approvedBy: 'admin', token: crypto.randomBytes(32).toString('hex') };
}
fs.writeFileSync(pairedPath, JSON.stringify(paired, null, 2));
fs.writeFileSync(pendingPath, JSON.stringify({}, null, 2));
"

# Reload gateway
docker exec <gateway-container> sh -c "kill -USR1 \$(pgrep -f 'openclaw-gateway' | head -1)"
RAW_BUFFERClick to expand / collapse

Bug: openclaw-cli cannot connect to gateway when bind=lan on Docker Desktop macOS (Apple Silicon)

Repo: https://github.com/openclaw/openclaw
Discovered: 2026-03-18
Environment: Docker Desktop macOS, Apple Silicon (ARM64)
OpenClaw version: ghcr.io/openclaw/openclaw:2026.3.13-1


Summary

When running the gateway with gateway.bind=lan inside Docker Desktop on macOS (Apple Silicon), the openclaw-cli container cannot connect to the gateway via WebSocket, making all CLI commands fail. This breaks the documented device pairing flow (devices list / devices approve).

Environment

OSmacOS (Apple Silicon, ARM64)
DockerDocker Desktop for Mac
OpenClaw imageghcr.io/openclaw/openclaw:2026.3.13-1
gateway.bindlan (required for host browser access on Docker Desktop)
gateway.modelocal
CLI setupnetwork_mode: service:openclaw-gateway (as documented)

Steps to Reproduce

  1. Run gateway with --bind lan (required on Docker Desktop macOS so the host browser can reach the published port 127.0.0.1:18789):
# docker-compose.yml
services:
  openclaw-gateway:
    image: ghcr.io/openclaw/openclaw:2026.3.13-1
    platform: linux/arm64
    ports:
      - "127.0.0.1:18789:18789"
    command: ["node", "dist/index.js", "gateway", "--bind", "lan", "--port", "18789"]
    volumes:
      - openclaw_data:/home/node/.openclaw

  openclaw-cli:
    image: ghcr.io/openclaw/openclaw:2026.3.13-1
    platform: linux/arm64
    network_mode: "service:openclaw-gateway"
    environment:
      OPENCLAW_GATEWAY_TOKEN: ${OPENCLAW_GATEWAY_TOKEN}
      OPENCLAW_ALLOW_INSECURE_PRIVATE_WS: "1"
    volumes:
      - openclaw_data:/home/node/.openclaw
    entrypoint: ["node", "dist/index.js"]
    profiles: [cli]
  1. Confirm gateway is healthy and responding from the host:
curl http://127.0.0.1:18789/healthz  # returns 200 OK
  1. Open browser at http://127.0.0.1:18789/#token=<TOKEN> — UI loads, shows pairing required.

  2. Run the documented pairing flow:

docker compose --profile cli run --rm -T openclaw-cli devices list

Observed Behavior

Attempt 1 — no flags (CLI reads config with bind=lan, mode=local):

Error: gateway timeout after 10000ms
Gateway target: ws://127.0.0.1:18789
Source: local loopback
Bind: lan

Attempt 2 — with --url ws://127.0.0.1:18789 (no token):

Error: gateway url override requires explicit credentials
Fix: pass --token *** --password ***

Attempt 3 — with --url ws://127.0.0.1:18789 --token <TOKEN>:

Error: gateway closed (1006 abnormal closure (no close frame)): no close reason
Gateway target: ws://127.0.0.1:18789
Source: cli --url

Attempt 4 — with --url ws://0.0.0.0:18789 --token <TOKEN>:

SECURITY ERROR: Gateway URL "ws://0.0.0.0:18789" uses plaintext ws:// to a non-loopback address.

Expected Behavior

docker compose --profile cli run --rm openclaw-cli devices list should connect to the gateway and list pending device pairing requests, as documented in https://docs.openclaw.ai/install/docker#control-ui-token--pairing-docker

Root Cause Analysis

The CLI container shares the gateway's network namespace via network_mode: service:openclaw-gateway. With bind=lan, the gateway process listens on 0.0.0.0:18789.

From inside the CLI container:

  • ws://127.0.0.1:18789timeout (loopback doesn't reach the gateway process in this namespace configuration under Docker Desktop macOS)
  • ws://0.0.0.0:18789blocked by CLI security check (non-loopback plaintext ws://)
  • ws://127.0.0.1:18789 with explicit --token1006 abnormal closure (gateway rejects the connection)

The core tension: bind=lan is required on Docker Desktop macOS for the host browser to reach the gateway via the published port (127.0.0.1:18789 → container:18789). But bind=lan breaks CLI connectivity from within the shared network namespace.

With bind=loopback, the CLI works but the host browser cannot reach the gateway (Docker Desktop port forwarding doesn't work with loopback-bound processes inside containers).

Workaround

Direct file manipulation via docker exec:

docker exec <gateway-container> node -e "
const fs = require('fs');
const crypto = require('crypto');
const pendingPath = '/home/node/.openclaw/devices/pending.json';
const pairedPath  = '/home/node/.openclaw/devices/paired.json';

const pending = JSON.parse(fs.readFileSync(pendingPath, 'utf8'));
let paired = {};
try { paired = JSON.parse(fs.readFileSync(pairedPath, 'utf8')); } catch(e) {}

for (const [reqId, req] of Object.entries(pending)) {
  paired[req.deviceId] = { ...req, approvedAt: Date.now(), approvedBy: 'admin', token: crypto.randomBytes(32).toString('hex') };
}
fs.writeFileSync(pairedPath, JSON.stringify(paired, null, 2));
fs.writeFileSync(pendingPath, JSON.stringify({}, null, 2));
"

# Reload gateway
docker exec <gateway-container> sh -c "kill -USR1 \$(pgrep -f 'openclaw-gateway' | head -1)"

This works but bypasses the CLI entirely.

Questions

  1. Is bind=lan + network_mode: service:openclaw-gateway a supported configuration? The docs recommend it for Docker setups but it breaks CLI connectivity.
  2. Is there a supported way to run CLI commands against a bind=lan gateway from within the shared network namespace?
  3. Should the CLI support connecting to the gateway via the Docker bridge IP (e.g. 172.x.x.x) as a fallback when loopback fails?

References

extent analysis

Fix Plan

To resolve the issue of the openclaw-cli container not being able to connect to the gateway when bind=lan on Docker Desktop macOS (Apple Silicon), follow these steps:

  1. Modify the docker-compose.yml file:

    • Update the openclaw-cli service to use a specific IP address for the gateway that is reachable within the Docker network.
    • Since bind=lan listens on 0.0.0.0, we can use the Docker bridge IP as a fallback.
  2. Use the Docker bridge IP:

    • Find the IP address of the Docker bridge (usually 172.17.0.1 or similar) and use it to connect to the gateway from the CLI.
  3. Update the CLI command:

    • Run the CLI command with the --url option specifying the WebSocket URL with the Docker bridge IP.

Example modifications and commands:

# docker-compose.yml update
services:
  openclaw-gateway:
    # ... existing configuration ...
    networks:
      - openclaw-net

  openclaw-cli:
    # ... existing configuration ...
    networks:
      - openclaw-net
    command: ["node", "dist/index.js", "devices", "list", "--url", "ws://openclaw-gateway:18789"]

networks:
  openclaw-net:
    driver: bridge

Alternatively, if modifying docker-compose.yml is not preferred, you can directly specify the URL when running the CLI command:

docker compose --profile cli run --rm -T openclaw-cli devices list --url ws://openclaw-gateway:18789

Or, using the Docker bridge IP directly (replace 172.17.0.1 with your actual Docker bridge IP):

docker compose --profile cli run --rm -T openclaw-cli devices list --url ws://172.17.0.1:18789

Verification

To verify that the fix worked:

  • Run docker compose --profile cli run --rm openclaw-cli devices list and check if it successfully connects to the gateway and lists pending device pairing requests.
  • Ensure that the gateway remains accessible from the host browser at http://127.0.0.1:18789.

Extra Tips

  • When working with Docker networks, ensure that services are properly connected to the same network for them to communicate.
  • Using bind=lan with Docker Desktop on macOS requires careful consideration of how services within containers communicate with each other and the host.
  • Always refer to the latest documentation for Docker, Docker Desktop, and OpenClaw for the most current best practices and configurations.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix Bug: openclaw-cli cannot connect to gateway when bind=lan on Docker Desktop macOS (Apple Silicon) [3 comments, 3 participants]