Deployment Guide 2026-04-23 13 min

2026 OpenClaw Gateway Built-in Health Probes (/health, /ready) and Load Balancing: Remote Physical Mac, Docker Compose, and Kubernetes Alignment—Path Shadowing and False-NotReady Runbook

Operators running OpenClaw Gateway on remote physical Mac nodes hit the same class of incidents: probes succeed locally but fail through nginx, or Kubernetes marks Pods NotReady while Compose looks green. This runbook aligns /health versus /ready across bare metal, Docker Compose, and Kubernetes, explains path shadowing, and gives copy-paste snippets plus an FAQ for false readiness.

2026 OpenClaw Gateway health probes load balancing Compose Kubernetes remote Mac

Introduction: three audiences, one contract

Bare-metal launchd, Compose healthcheck, and kube livenessProbe/readinessProbe all need the same semantic contract: /health means “restart me if I am wedged,” /ready means “send user traffic only if downstreams I declare are usable.” When those paths are shadowed by a reverse proxy or answered by the wrong upstream, you get irreproducible paging and flaky rollouts.

If you are hardening the production listener surface first, read OpenClaw Gateway production attack surface: 127.0.0.1 binding, reverse proxy, and tunnel on a remote physical Mac. For client-side path parity through SSH or Tailscale, pair this with SSH local forward vs Tailscale Serve to a physical macOS gateway node.

1. Pain points: shadowing, drift, and load-balancer lies

  1. Path shadowing. A static location /, SPA fallback, or aggressive try_files can return 200 OK HTML for /ready without ever hitting OpenClaw. Your LB thinks the pool is warm; the gateway never received the probe.
  2. Semantic drift between platforms. Compose marks a service healthy when the engine-level check passes; Kubernetes can still route to a different revision behind a Service if selectors overlap, or if an Ingress sends probes to a canary backend you did not intend to test.
  3. Hidden audit and stability cost. Reusing /ready for liveness couples dependency outages to Pod restarts. On a remote Mac fleet, that shows up as flapping Screen Sharing sessions, half-written agent state, and noisy on-call—not “just Kubernetes.”

2. Decision matrix: where each probe should run

Use this table during design review before you paste YAML into production. “Who must observe what?” is the whole game.

Signal Bare Mac + reverse proxy Docker Compose Kubernetes
/health (cheap) LB → nginx → gateway; bypass CDN cache healthcheck against published port livenessProbe.httpGet.path=/health
/ready (strict) Same chain as user Host + TLS; no static shadow depends_on: condition service_healthy readinessProbe + startupProbe for cold start
Primary failure mode Prefix location wins over proxy_pass Published port ≠ host LB port RBAC / NetworkPolicy blocks probe from kubelet subnet

3. Seven-step alignment runbook

  1. Enumerate callers. Export every health URL from the cloud LB, nginx server_name block, Compose file, Helm values, and ad-hoc monitoring. If any row is blank, that is your blind spot.
  2. Prove shadowing. From the proxy host, curl -svH 'Host: your.api' https://127.0.0.1/ready and diff the body against curl straight to the gateway port on loopback.
  3. Pin locations ahead of catch-alls. Dedicated location = /health and location = /ready with proxy_pass to the gateway upstream, proxy_buffering off; and add_header Cache-Control no-store;.
  4. Compose: match LB timeouts. Set interval, timeout, and retries within 80% of what the external LB uses so you do not optimistically mark healthy first.
  5. Kubernetes: split probes. Wire liveness to /health, readiness to /ready, and add startupProbe with longer failureThreshold for model-router warm-up.
  6. Rollout rehearsal. Blue/green or rolling: watch kubectl get endpoints while tailing gateway logs; confirm traffic shifts only after /ready flips for the new revision.
  7. Archive diffs. Store redacted nginx -T, Compose YAML, and kubectl describe pod snippets with timestamps—your future self thanks you during the next false NotReady.

4. Configuration snippets

4.1 nginx: explicit probe locations (no shadowing)

location = /health { proxy_pass http://openclaw_gateway; proxy_http_version 1.1;
  proxy_set_header Host $host; proxy_buffering off; add_header Cache-Control "no-store"; }
location = /ready  { proxy_pass http://openclaw_gateway; proxy_http_version 1.1;
  proxy_set_header Host $host; proxy_buffering off; add_header Cache-Control "no-store"; }

4.2 Docker Compose: healthcheck + dependency gate

services:
  openclaw-gateway:
    image: your.registry/openclaw-gateway@sha256:…
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://127.0.0.1:18789/health"]
      interval: 15s
      timeout: 3s
      retries: 5
      start_period: 120s
  edge-proxy:
    depends_on:
      openclaw-gateway:
        condition: service_healthy

4.3 Kubernetes: startup + readiness + liveness

startupProbe:
  httpGet: { path: /ready, port: http }
  periodSeconds: 5
  failureThreshold: 30
readinessProbe:
  httpGet: { path: /ready, port: http }
  periodSeconds: 10
  timeoutSeconds: 3
livenessProbe:
  httpGet: { path: /health, port: http }
  periodSeconds: 20
  timeoutSeconds: 2

Adjust port: http to match your containerPort name. If you terminate TLS at the Ingress, keep probes on the plain container port unless your mesh injects sidecar TLS.

5. Cite-ready parameters

  • 18789 — common OpenClaw gateway HTTP surface on Mac nodes; always confirm with your openclaw.json or release notes before baking into LB templates.
  • 120s start_period — practical first guess for cold model cache and Secret mount latency on remote Mac hosts; trim with measured P95 after two weeks of metrics.
  • 3s readiness timeout — balances slow upstreams against kubelet aggressiveness; pair with failureThreshold instead of unbounded timeouts that hide real stalls.

6. FAQ: reproducible false positives

What is path shadowing for /health and /ready behind nginx?

A broad prefix location or SPA fallback answers probe paths before traffic reaches the OpenClaw upstream. You see HTML 200s while direct Pod curls return JSON—fix ordering, disable cache on probe paths, and verify proxy_pass targets.

Should liveness and readiness both call /ready?

No. Liveness should stay cheap on /health; readiness on /ready gates traffic on dependencies you accept as hard requirements.

Why does Compose look healthy while the LB drains the task?

Different network namespaces and different Host/TLS paths. Run the LB’s exact curl, including SNI and URL path, from the LB subnet or bastion—not only from inside the container.

What causes false NotReady right after deploy on a remote Mac?

Cold caches and dependency handshakes exceed your initial timeouts. Use startupProbe or Compose start_period, log per-dependency latency, then tighten thresholds with evidence.

7. Why Mac mini is the right place to terminate this complexity

Gateway health semantics only matter when the host stays up: Apple Silicon Mac mini nodes combine low idle power (often on the order of a few watts at rest), silent operation suitable for racks and desks, and a Unix-first toolchain—curl, launchctl, Docker Desktop or Colima, and SSH—without the driver friction common on Windows fleets.

macOS Gatekeeper, SIP, and FileVault also reduce tampering risk for long-lived agent tokens sitting beside your gateway. That security posture matters when /ready is the signal your load balancer uses to expose automation to the internet.

If you want this probe and load-balancer story on hardware you can leave unattended, Mac mini M4 is a strong 2026 baseline—then use the CTA below to compare ZoneMac gateway-ready nodes and roll out with the same acceptance curls you just documented.

Limited Time Offer

Ready to run OpenClaw on dedicated Mac gateways?

Rent a remote Mac mini with the networking and uptime patterns this runbook assumes—health-checked, SSH-ready, and built for CI and agents.

Pay-as-you-go Instant activation Multi-region options
macOS Cloud Rental Ultra-low price limited time offer
Buy Now