2026 OpenClaw Docker on a VPS
Exit 137 and Control UI errors at a glance

mem_limit · first-run WASM wait · allowedOrigins · compose exec pairing · copy-paste compose

2026 OpenClaw Docker on a VPS troubleshooting

Developers who already brought up docker compose from the guide on small-memory VPSes most often see three symptoms: containers exiting immediately with 137, port 18789 appearing hung for a long time, and Control UI errors about non-loopback or Host headers. This article starts with an actionable checklist for free -h versus mem_limit and a 3–7 minute first-run WASM compile window, then uses a symptom → docker logs evidence → fix table for Exit 137, volume permissions, and mount mismatches; next it narrows UI errors with a 127.0.0.1 binding, allowedOrigins, and reverse proxy decision table; finally it gives a six-step in-container device pairing runbook and ten pre-launch checks. Read alongside the OpenClaw v2026.4 install and Docker hardening guide, the Gateway install and doctor troubleshooting checklist, and the three-part runtime troubleshooting article to move from “the container starts” to “stable without babysitting.”

01

Prerequisites: free -h, mem_limit, and telling first-run WASM compile from a “hard hang”

When the OpenClaw Gateway starts in a container for the first time, CPU pegged while the port stays closed is often the WASM sandbox compile phase, not a deadlock. Align with the resource guidance in the v2026.4 install guide: when both host free memory and mem_limit are too tight, Linux OOM yields Exit 137 and logs may not print a friendly error in time.

  1. 01

    Host: run free -h on the host and confirm headroom is not chronically below about 1.5–2 GiB; Exit 137 is more common when swap is 0.

  2. 02

    Compose: set mem_limit: 2g or higher and avoid competing with other heavy services on the same machine.

  3. 03

    First-run window: allow 3–7 minutes on a cold start before calling it failed; use docker logs -f to see whether the compile chain is still running.

  4. 04

    Health checks: set healthcheck.start_period to at least 360s so compose does not kill the process before WASM finishes.

  5. 05

    Avoid false positives: do not repeatedly docker compose restart inside the first-run window or each restart retriggers the cold compile spike.

Put these five lines on page one of your “OpenClaw on a VPS” runbook to cut tickets that say “I followed the tutorial but it still won’t start.” For fuller Gateway layering, see the three-part runtime guide.

02

Exit 137, volume permissions, and mount skew: symptoms, docker logs evidence, and fixes

The table below keeps an “evidence first, then action” order so tickets move from “the gateway feels broken” to reproducible fields. Used with the doctor install checklist, you can paste row numbers into ticket templates.

Symptomdocker logs / host evidenceFix first
Immediate exit 137dmesg shows OOM; or logs stop abruptlyRaise mem_limit / upgrade size; reduce contention
Permission denied reading workspaceMount owned by root; node user in the container cannot writechown to the container UID or align user: with the volume
Config changes do not applyHost path and compose volume point at two different .openclaw treesUnify on one bind path; run docker compose config before restart
Intermittent DNS failurecurl to model endpoints times out in the containerCheck Docker dns and host resolution per the install guide
Restart loop with no new logsHealth check too aggressive kills the processWiden start_period and retries

Efficient Docker triage hinges on proving 137 is OOM before guessing it is an application bug.

If you pair the Gateway with an always-on remote Mac node, treat “container resources” and “node SLA” as two acceptance lines: the former is compose and logs; the latter is provider region and maintenance windows.

03

Control UI, 127.0.0.1 binding, and reverse proxies: choosing allowedOrigins and Host options

Publishing 18789 to the public internet on a VPS is a common misconfiguration. The install guide recommends binding the container to loopback only and terminating TLS with Caddy or Nginx on 443. When Control UI reports non-loopback errors, the root cause is usually a mismatch between browser origin and what the Gateway allows, not “Docker is broken.”

ScenarioListen and proxyConfiguration bias
Local SSH tunnel debugging only127.0.0.1:18789allowedOrigins includes http://127.0.0.1:18789
Production HTTPS by domainReverse proxy to loopback upstreamallowedOrigins lists https://your-domain.example; avoid Host fallback when you can
Temporary labHTTP on a private IPList IP origins explicitly; shrink CIDR; retire after the maintenance window
Triage “just show me the UI”Still prefer an outer TLS layerUse official Host-header fallback switches only with understood risk; roll back afterward
json
{
  "gateway": {
    "mode": "local",
    "controlUi": {
      "allowedOrigins": ["https://openclaw.example.com"]
    }
  }
}

Note: after editing openclaw.json, check whether docker compose restart lands inside the first-run WASM window so it does not stack with the false positives in section 2.

04

Six-step runbook: docker compose exec, devices list, approve, and path skew

When you run openclaw inside the container, HOME and the config volume must match the running Gateway process or you get “approved on the host, still pending in the container.” The steps below assume the service name openclaw; replace it with your compose service name.

  1. 01

    Confirm service name: docker compose ps and pick the container that actually runs the Gateway.

  2. 02

    Enter the same environment: docker compose exec openclaw sh -lc 'pwd; echo $HOME; ls -la ~/.openclaw | head'

  3. 03

    List pending pairing: docker compose exec openclaw openclaw devices list

  4. 04

    Copy Request ID: from the UI or logs, then run openclaw devices approve <id>.

  5. 05

    Check API key visibility: if you see No API key found for provider, verify .env is passed into the container by compose, not only in a host shell profile.

  6. 06

    Write back ticket fields: paste compose path, image tag, openclaw.json summary, and the approve command for the next run.

Warning: running openclaw devices approve on the host while the config volume lives only in the container yields a false negative: the command succeeds but the Gateway still does not see it.

05

Copy-paste compose skeleton, ten launch checks, and the “laptop always on” alternative

The three bullets below are common review bands from community and production; replace them with real monitoring from your hosts and add them to README so new hires do not repeat the same pits.

  • First-start budget: allow at least 3–7 minutes on a cold start before opening a ticket; restarting before 3 minutes often amplifies 137.
  • Memory headroom: for a single instance, keep host free memory chronically above about 2 GiB of margin; below that band, prefer a resize before stacking features.
  • Log rotation: cap Docker json-file at ≤10 MiB per file, ≤3 files so a full disk does not cause secondary failures.
#Pre-launch checkPass criteria
01ports bind only 127.0.0.1Public direct access to 18789 is closed
02env_file matches secret injection pathsModel provider keys are readable in the container
03mem_limit and swap policy documentedOne stress round with no 137
04healthcheck.start_period ≥ 360sNo restart storm inside the first-run window
05openclaw.json has gateway.mode localIllegal keys removed
06Reverse proxy TLS and HSTS policyNo mixed-content warnings in the browser
07allowedOrigins covers real visitor originsControl UI shows no non-loopback errors
08Device pairing verified inside the containerdevices list empty or all approved
09Backup .openclaw path and versionRecoverable from a one-page runbook
10Aligned with channel docsIM or webhook callbacks reachable
yaml
services:
  openclaw:
    image: ghcr.io/openclaw/openclaw:latest
    restart: unless-stopped
    mem_limit: 2g
    ports:
      - "127.0.0.1:18789:18789"
    volumes:
      - ${HOME}/.openclaw:/home/node/.openclaw
    env_file:
      - .env
    healthcheck:
      test: ["CMD", "curl", "-f", "http://127.0.0.1:18789/health"]
      interval: 60s
      timeout: 15s
      retries: 5
      start_period: 360s

Running the Gateway on a laptop long term is often dragged down by sleep, lid close, and flaky uplink; home broadband alone rarely yields an enforceable SLA. By contrast, a cloud Mac Mini billed by period fits hybrid flows that pair OpenClaw on a VPS with macOS or Xcode-side work.

Common mistake: treating 0.0.0.0:18789 as “easier debugging”; on a public VPS that exposes the control plane to scanners.

If you want a stable Docker gateway online while moving heavy compiles or device work into a contract-grade macOS environment, self-owned capex is often weaker on procurement and multi-site sync. For 7×24 nodes with enforceable specs, VpsMesh cloud Mac Mini rental is usually the better fit: draw the split between VPS OpenClaw and dedicated remote Mac in your architecture, then use the pricing page and order page for capacity review instead of relying on verbal promises alone.

FAQ

Frequently asked questions

Start by checking host dmesg and whether mem_limit triggered OOM, and reserve the first-run WASM window. Review resource baselines together with the OpenClaw v2026.4 install guide.

First list real HTTPS origins under gateway.controlUi.allowedOrigins in openclaw.json and confirm the reverse proxy is not forwarding a wrong Host upstream. For the full install and doctor flow, see the Gateway install troubleshooting checklist.

Use docker compose exec with the same user and volume mounts as the Gateway, then run openclaw devices list; if it still misbehaves, follow the three-part runtime troubleshooting article. For sizing review, open the pricing page and order page; connectivity topics live in the help center.