Who this helps: teams running OpenClaw on a remote Mac with several OpenAI-compatible APIs behind one ingress—without model drift when CI or R&D pulls change. You get: Node 24 baseline, install checkpoints, a routing step table, /health probes, and CI step-summary or webhook snippets so people see which backend served traffic—often without SSH. Pair with LaunchAgent gateway health and Telegram/Slack FAQ. Public read—no login.

Prerequisites (Node 24 & gateway host)

Use one automation UNIX user for OpenClaw, TLS material, and CI jobs so launchd and shells share PATH and secrets—otherwise you chase “works in Terminal, fails in CI.”

  • Node 24 LTS for that user; verify node -v in a non-login shell and pin the major in images.
  • Egress: HTTPS to every upstream; set HTTPS_PROXY consistently for daemons and shells if required.
  • Secrets: mode 600 env files or a secret manager; rotate after any log leak.
  • RAM: leave headroom for TLS and JSON spikes if workers colocate on the same Mac.
  • Logs: fix stdout/log paths once so CI summaries always tail the same file.

Colocating gateway and dependency pulls? Keep one automation “plane” (Node, PATH, DNS). For CI log surfacing patterns, see GOPROXY fallback & CI logs.

Installation and key points

Pick one install channel per fleet (global npm, installer, or pinned tarball), then bake openclaw onboard into the golden image so config dirs and ports exist before first boot.

  • Doctor clean before registering upstreams—PATH and permission warnings often precede opaque 502s.
  • Reverse proxy: forward Host and X-Forwarded-Proto so webhook URLs are correct.
  • Reload via documented signal; avoid duplicate listeners from kill -9 loops.
  • Pin semver in IaC so CI can echo it next to routing decisions.

Tip: Check in a short gateway profile (bind URL, public base, log path) beside CI YAML.

Multi-compatible endpoints & routing configuration (step table)

Compatible servers share chat/completions JSON; they differ in auth, paths, quotas, and model ids. Copy the table into your runbook and map column three to real env keys.

Step Action Record in runbook Done when
1 Inventory upstreams (cloud vendor A, self-hosted B, DR region C). Table of base URLs, owner on-call, and monthly spend cap. Every URL answers curl -sS -o /dev/null -w "%{http_code}" with a non-zero handshake within eight seconds.
2 Define logical aliases (fast, cheap, local) independent of vendor marketing names. Alias → concrete model id map checked into Git (redact secrets). Two engineers resolve the same alias to identical ids in a blind test.
3 Register each endpoint with its auth scheme (Authorization: Bearer, custom header, mTLS). Env file path per upstream; rotation date field. Gateway logs show successful test call per upstream after reload.
4 Author routing rules: prefix match on model name, tenant tag, or CI job label. Ordered rule list with explicit fallback to a safe default. Deliberate mis-route test returns the expected fallback model within one hop.
5 Add circuit breaker thresholds (429 burst, 5xx streak). Numeric thresholds and cool-down minutes. Simulated 503 flips traffic to secondary without manual restart.
6 Document escalation: who approves adding a new vendor endpoint. Change ticket template with security review checkbox. Last three changes have ticket ids in Git commit messages.

Illustrative environment layout—replace names with your secrets backend:

# /etc/openclaw/endpoints.env (mode 600, not in Git)
UPSTREAM_OPENAI_BASE=https://api.openai.com/v1
UPSTREAM_OPENAI_KEY=sk-...
UPSTREAM_LOCAL_BASE=http://127.0.0.1:8080/v1
UPSTREAM_LOCAL_KEY=local-dev-token

# Routing: logical model -> upstream id (gateway-specific config file)
# fast -> openai/gpt-4.1
# cheap -> local/qwen2.5-7b
# default -> cheap

Prefer small ordered rules or generated JSON from a typed template—avoid one-line blobs.

/health checks

Use a fast route such as /health, /healthz, or /ready; avoid billing upstreams on every shallow probe. Optional “deep” checks can run on a slower cadence.

# Local sanity (same user as the daemon)
curl -fsS "http://127.0.0.1:PORT/health" | jq .

# Through the public hostname (validates TLS + DNS + proxy)
curl -fsS "https://gw.example.com/health" | jq .

Schedule shallow probes with launchd ThrottleInterval, log under ~/Library/Logs, alert after consecutive misses—see the health runbook linked above. Export per-upstream fields to metrics when present.

CI webhook & log summary integration examples

After infra or dependency changes, surface green/red plus which lane served—without SSH.

Pattern A — GitHub Actions step summary. After a job that touches gateway config or model pins, append a short markdown section to GITHUB_STEP_SUMMARY when the variable exists:

SUMMARY_FILE="${GITHUB_STEP_SUMMARY:-}"
if [[ -n "$SUMMARY_FILE" ]]; then
  {
    echo "### OpenClaw routing snapshot"
    echo "- Gateway profile: ${OPENCLAW_PROFILE:-default}"
    echo "- Health (truncated):"
    curl -fsS "https://gw.example.com/health" | head -c 1200
    echo ""
    echo "- Last 30 lines of gateway log:"
    tail -n 30 "${OPENCLAW_LOG_PATH:-/tmp/openclaw.log}"
  } >> "$SUMMARY_FILE"
fi

Scrub secrets; log endpoint aliases, not raw keys.

Pattern B — inbound webhook to the gateway. When CI finishes, POST a signed JSON payload to your gateway’s automation route (if enabled) so bots can announce new lockfiles or model cache versions to Slack or Telegram—reuse channel setup from the message-channel FAQ linked in the introduction. Validate signatures the same way you would for vendor webhooks.

Remote Mac value: persistent caches and runners make the Mac the natural home for heavy pulls; healthy gateways plus CI summaries that name the active endpoint keep R&D focused on code instead of guessing which route failed.

Common errors FAQ

401 Unauthorized from upstream even though the key works in Postman

Check for double-prefix headers, stale env in launchd, or a different UNIX user between your shell test and the daemon. Print effective env inside the minimal reproduction script, not only in interactive zsh.

Routing table changes never take effect

Confirm you reloaded the correct process, not an orphaned binary. Use lsof -i :PORT to ensure a single listener, then re-run doctor after reload.

/health is green but chat requests time out

Health may be shallow. Run a bounded test completion against each upstream with a tiny max token setting, and inspect TLS MITM or HTTP/2 issues on the path between gateway and vendor.

CI summary shows binary garbage

You probably piped non-UTF8 logs. Filter with strings or copy only JSON health fields, and never paste raw API keys into GITHUB_STEP_SUMMARY.

Summary

Treat extra endpoints like production deps: Node 24, clean doctor, versioned routes, scheduled health, CI-visible evidence. That keeps the gateway boring while R&D and automation stay aligned.

Browse the technical blog index for more OpenClaw and remote Mac playbooks. Product and support links below require no account to read.

Remote Mac for stable gateways & CI

Visit the homepage, purchase flow, help center, or keep reading—no login wall on these pages.