Who hits this: You run Docker Compose with Gateway plus CLI or agent-related containers; Gateway logs look healthy, but sub-session tools throw gateway closed (1008): pairing required, or RPC is healthy yet pairing still fails. Takeaway: This is rarely fixed by “reinstalling the image again”—it is usually a combination of bind surface, token, trusted proxy CIDRs (trustedProxies), and inter-container URLs; this article provides a symptom matrix, Compose snippet, six-step runbook, and three KPIs. How it fits: alongside the official docker-setup.sh + GHCR, pairing and token, and Docker networking triage articles.
OpenClaw Gateway owns long-lived connections and routing; when the CLI or sub-session tools talk to Gateway over WebSocket/HTTP, the process being up is not enough—the caller must be a trusted network identity from Gateway’s perspective, and pairing must still be valid. Docker puts each service in its own network namespace: if you set http://127.0.0.1:18789 inside the CLI container, traffic hits that container, not the host or another service.
http://openclaw-gateway:18789 (example).172.16.0.0/12, 10.0.0.0/8, and your custom network CIDR) so client identity is evaluated correctly.Unlike the three-OS install overview, Compose is less about “which OS” and more about which network is trusted inside which container.
When you reproduce the issue, keep three log fingerprints side by side: Gateway startup lines, subagent stack traces, and the attachable network Subnet from docker inspect—many 1008 cases collapse to “trusted range not declared,” not the model or channel.
| Symptom snapshot | Check first (ordered) | Typical root cause |
|---|---|---|
| Container A cannot reach 127.0.0.1:18789 | Switch to service-name URL, then published ports and listen address | Wrong localhost semantics |
| RPC healthy but sessions_spawn returns 1008 | Pairing list → trustedProxies → bind triad | Subagent path treated as external / not paired |
| Logs mention trusted proxy / pairing | Align compose network CIDR with gateway.auth config | Subnet missing from trusted set |
| Only after a version upgrade | Diff old vs. new default bind/auth; compare migrated .openclaw volume | Tightened defaults or stale pairing |
Note: If you use the official docker-setup.sh flow, still validate service names and volumes through this network-contract lens—see the GHCR and Control UI Runbook.
| gateway.bind (concept) | Best for | Compose friction |
|---|---|---|
| loopback | Single all-in-one container or host-only access | Other service containers cannot treat it as local loopback |
| lan / custom listen | Multiple services and cross-container RPC | Requires token/auth and a tightened exposure story |
| trusted reverse proxy | Nginx/Caddy in front | Must match the reverse-proxy checklist for downstream sources |
trustedProxies (example CIDRs)The table below is illustrative: always read your real subnet from docker network inspect, do not copy blindly.
| Network type | Example CIDR | What you do |
|---|---|---|
| Default Docker bridge | 172.17.0.0/16 (environment-dependent) | Check whether Gateway sees source IPs inside that range |
| Compose custom network | for example 172.18.0.0/16–172.30.x.x | Add the whole subnet to trustedProxies (not single container IPs) |
| overlay / swarm | allocated by orchestrator | Same principle: target subnets, not volatile pod IPs |
OPENCLAW_GATEWAY_URL=http://openclaw-gateway:18789 (match your compose service name).OPENCLAW_GATEWAY_TOKEN matches on both sides; if you use a file token, confirm the mount is readable by the container UID.openclaw gateway status → openclaw doctor → reproduce the subagent action and grep logs for 1008 / pairing.# Snippet example (service names and env placeholders — replace before production)
services:
openclaw-gateway:
environment:
- OPENCLAW_CONFIG_DIR=/config
- OPENCLAW_GATEWAY_TOKEN=${OPENCLAW_GATEWAY_TOKEN}
volumes:
- ./config:/config
networks: [oc-net]
openclaw-cli:
environment:
- OPENCLAW_CONFIG_DIR=/config
- OPENCLAW_GATEWAY_URL=http://openclaw-gateway:18789
- OPENCLAW_GATEWAY_TOKEN=${OPENCLAW_GATEWAY_TOKEN}
volumes:
- ./config:/config
networks: [oc-net]
networks:
oc-net: { driver: bridge }
gateway.auth.token fingerprint or env hash between containers; block release if they diverge.These KPIs are engineering observability suggestions; they are not an upstream SLA commitment.
“Image comes up” is not enough: subagents and session tools need a stable Gateway, predictable network identity, and consistent config volumes. Iterating with single-container docker run on a laptop is a different failure surface than a fixed Compose stack with persistent volumes on a dedicated remote Mac—the latter matches unsupervised and scheduled jobs much more closely.
Ephemeral VPS or shared desktops may demo quickly yet often lack a consistent disk and network baseline; when you need Gateway, reverse proxy, and automation in one trust zone with room to scale, multi-region Apple Silicon cloud hosts with monthly or quarterly terms are often easier than repeatedly hand-building temporary Docker hosts. MACCOME offers physical isolation and six-region placement so you can split “always-on Gateway” from “build/signing” tiers; review rental rates and the cloud Mac support and help center, then wire env vars using this runbook.
Rollout order: close the six-step loop inside one Compose project first, then decide whether Gateway and other workloads should move to separate remote nodes.
FAQ
When code 1008 appears, should I immediately change bind to LAN?
Work through Table 1 first: often it is service-name URL or trustedProxies, not blindly widening the listen surface. If you expand exposure, align token and firewall together. More pairing scenarios: pairing and token checklist.
Can I curl 127.0.0.1:18789 on the host instead of probing from the container?
That is a valid host-side health check, but it does not replace verifying container-to-Gateway connectivity via the service name—the namespaces differ. For help: cloud Mac support and help center.
Is this redundant with the Docker networking triage article?
Networking triage covers compose namespaces and CLI reachability; the official Docker article focuses on image paths. This runbook specifically bridges subagent pairing with trustedProxies. You can also read MCP and Skills verification next.