Audience: developers and CI integrators running OpenClaw on hosted Apple Silicon who need a stable public IP for model vendors, a tight outbound allowlist, and predictable gateway reconnect after VPN blips. This playbook follows the 2026 install story: curl bootstrap, Node 22+ or 24, openclaw onboard --install-daemon, default gateway port 18789, and optional OPENCLAW_HOME trees for multiple instances. Cross-links stay on MacPull without a login wall: gateway security hardening, config validate CI gate, Argo CD webhook summaries. Prefer Console for a no-paywall peek at nodes before you buy.

① Topology and least-privilege principles

Run the OpenClaw daemon under a dedicated macOS user or role account with its own home. Keep SSH administration on the primary interface while model traffic exits only through WireGuard so firewall rules stay small.

  1. Split control plane: CI webhooks hit a reverse proxy or SSH tunnel terminating on 127.0.0.1, not the raw LAN.
  2. Default deny egress: allow DNS resolver, NTP, your model hostnames, and any registry your tools require—nothing else.
  3. Audit path: store openclaw.json and env files mode 600; rotate tokens when staff rotates.

② Official install and doctor verification

Install a supported runtime first. OpenClaw upstream expects Node 22 LTS or Node 24; older majors fail subtle parser paths. Use the official curl installer from OpenClaw docs, then register the daemon.

node -v   # expect v22.x or v24.x

# Run the curl one-liner from the official OpenClaw install page (URL changes by release)

openclaw onboard --install-daemon
openclaw doctor
openclaw gateway status --deep || true

For multiple gateways, export OPENCLAW_HOME or OPENCLAW_CONFIG_HOME per instance before onboard so staging JSON never overwrites production plists. Document the mapping in your runbook.

  • Global openclaw binary matches the user that owns launchd job labels.
  • openclaw doctor reports clean DNS, disk, and provider reachability from the same environment as the daemon.
  • Port 18789 is free or intentionally forwarded; no duplicate listeners after upgrades.

③ WireGuard routing and DNS split

Narrow AllowedIPs to provider CIDR blocks instead of 0.0.0.0/0 unless you truly need a full tunnel. Point only model-related FQDNs at the resolver advertised inside the tunnel; keep corporate Git on the default resolver to avoid surprise latency.

wg-quick up wg0
wg show
scutil --dns | head -n 80

curl -4sv --max-time 15 https://api.openai.com/v1/models \
  -H "Authorization: Bearer $OPENAI_API_KEY" -o /dev/null
Pattern When to use Risk if skipped
Split tunnel + split DNS Vendors need fixed egress; Git and artifact CDN stay local CI pulls crawl through the VPN hop
Full tunnel Strict compliance enclaves Single point of failure; higher reconnect sensitivity
Static egress IP only on WG peer Vendor IP allowlists NAT drift breaks API keys mid-run

④ Gateway bind, bearer token, and domain whitelist

Bind the HTTP gateway to 127.0.0.1:18789 and terminate TLS at the edge. Store the inbound webhook bearer in Keychain or a root-only env file referenced from launchd. Mirror the outbound table from hardening notes: model APIs, optional embeddings hosts, npm registry if the skill pipeline needs it.

export OPENCLAW_GATEWAY_TOKEN="$(openssl rand -hex 32)"
launchctl print gui/$(id -u)/com.openclaw.gateway 2>/dev/null | head

curl -sS -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  http://127.0.0.1:18789/health || curl -sS http://127.0.0.1:18789/

⑤ Disconnect recovery and health probes

Treat WireGuard flap as normal. After wg-quick restarts, restart the OpenClaw daemon so in-memory DNS caches align. Use a lightweight probe every sixty seconds from launchd or a sidecar container; alert if two consecutive probes fail.

  • Log wg handshake age and last successful model HEAD request in the same line for triage.
  • Apply ThrottleInterval on rapid restart loops to avoid tight crash spirals.
  • Keep a tarball of last-known-good openclaw.json before touching routes; pair with rollback flows in skills rollback doctor.

⑥ CI webhook example: merge failure summaries

CI should not spam twenty messages per matrix cell. Collect stderr tails from failed steps, cap payload size near four kilobytes, sort unique, and POST one JSON object with fields such as job_id, commit_sha, and summary_text. Reuse the same exponential backoff ladder documented for GitOps hooks so the gateway stays responsive when the VPN is warming up.

FAIL_LINES=$(grep -hE 'error|fatal' "$CI_LOG_DIR"/*.log | tail -n 40 | sort -u)
curl -fsS -X POST "https://edge.example/v1/webhooks/ci" \
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg t "$FAIL_LINES" --arg j "$CI_JOB_ID" --arg c "${CI_COMMIT_SHA:-}" \
      '{summary_text:$t,job_id:$j,commit_sha:$c}')"

FAQ: common errors

Handshake ok but TLS to vendor fails: clock skew or missing intermediate trust store for the daemon user—run openclaw doctor as that user.

Works in Terminal, fails under launchd: compare printenv versus plist EnvironmentVariables; missing OPENCLAW_HOME is the usual culprit.

Webhook 401 bursts after rotation: update both proxy header injection and gateway secret atomically, then bounce the daemon once.

Closing checklist

Ship the smallest surface: WireGuard for predictable egress, split DNS, loopback 18789, bearer-gated webhooks, and merged CI text. When you outgrow DIY hosts, pricing and purchase stay one click away—Apple Silicon remote Mac pools cut VPN flapping costs because NIC queues stay local to the runner. Open help or the blog index anytime; this page stays readable without signing in.

Remote Mac for OpenClaw + WireGuard labs

Dedicated Apple Silicon with clean APFS, fast reinstalls, and static networking options for gateway proofs. Browse pricing and checkout freely; Console opens for a limited free look at inventory.