Teams piloting OpenClaw in 2026 often want a staging gateway beside a production gateway on the same physical Mac mini to save procurement cycles—then they watch both profiles overwrite the same token cache, fight for TCP 8787, or inherit each other’s PATH because launchd reused one plist template. This article gives an operator-first split: separate home directories for configuration state, non-overlapping listener ports, distinct LaunchAgent labels, per-profile log files, and a doctor-first smoke path aligned with EADDRINUSE triage, first-run PATH and Node checks, and doctor diagnostics.
You will leave with a port matrix, a checklist you can paste into tickets, and hard numbers—$16.9 per day rental baseline, 8787/8788 port pairing, 700 directory permissions, and a five-minute smoke window before you accept traffic.
Why two profiles on one Mac
Apple Silicon Mac mini nodes stay quiet under parallel gateways, give you native launchd semantics, and mirror what finance teams expect from CapEx-light pilots. Renting through MacHTML lands near $16.9/day on published pricing pages—cheap compared to shipping the wrong profile into production because staging rotated an API key file both instances read. Splitting profiles also keeps experimental tool allowlists away from customer-facing automation while still letting you diff plist changes on real hardware instead of Linux CI containers that lack Keychain prompts.
Keep the mental model explicit: profiles are isolation boundaries, not feature flags. Each profile owns its own configuration root, log directory, listening port, LaunchAgent label, and rotation calendar for secrets.
Directory layout and secrets hygiene
Create two roots such as ~/.openclaw-staging and ~/.openclaw-prod with chmod 700 so other console users on a shared mini cannot traverse caches. Store provider tokens, sqlite state, and downloaded skills under each root—never symlink staging into production “to save disk.” Disk is cheaper than incident response: a 512 GB mini still costs less than one misrouted production conversation when staging credentials leaked through a shared cache path.
Document which automation user owns each tree. If both agents run as the same macOS user, separation depends entirely on directories and plist arguments—if you later move to separate users, keep the directory names so migration stays mechanical.
LaunchAgent labels, logs, and environment blocks
Use distinct labels such as com.example.openclaw.gateway.staging and com.example.openclaw.gateway.prod; duplicate labels make launchctl kickstart -k restart the wrong world. Point StandardOutPath and StandardErrorPath to per-profile files under ~/Library/Logs/OpenClaw/ so operators can tail -F without merging streams.
Inside each plist, set LaunchEnvironmentVariables with the absolute Node binary you validated via which node, a trimmed PATH that lists Homebrew or volta shims before system paths, and a variable such as OPENCLAW_PROFILE_DIR pointing at the profile root. Rehearse the plist with a manual open session first; only then rely on launchctl bootstrap gui/$(id -u) as described in the first-run guide.
Throttle restarts: set ThrottleInterval to at least 10 seconds while debugging crash loops so launchd does not burn CPU filing the same stack trace thousands of times per hour.
Port and ownership matrix
| Dimension | Staging profile | Production profile |
|---|---|---|
| Listener port | 8787 (document in runbook) | 8788 (default alternate) |
| Config root | ~/.openclaw-staging | ~/.openclaw-prod |
| LaunchAgent label | …gateway.staging | …gateway.prod |
| API key rotation | Weekly during active dev | Monthly or per change window |
| Doctor cadence | Before every merge preview | After each deploy tag |
Reverse proxies, loopback binds, and operator traps
Most teams terminate TLS on nginx or Caddy and forward to loopback. Keep both gateways listening on 127.0.0.1 only unless you have explicit firewall rules—binding 0.0.0.0 on a shared mini accidentally exposes automation to the LAN café Wi-Fi segment. When you add HTTP/2 upstreams, remember 100 continue responses and idle timeouts: staging should mirror production timeouts within ±5% so reproducers do not hide behind artificially short idle windows.
Keychain prompts are another silent coupling: if both profiles import the same signing identity or API client certificate, macOS may cache unlocks per user session. Run security find-identity -v -p codesigning per profile documentation package and attach screenshots to the ticket so auditors see which identity backs which plist.
For incident response, keep a one-page “profile switch” runbook: which label to bootout first, which port to drain, which backup tarball of ~/.openclaw-prod to restore, and the exact doctor flags you used last green build. Teams that skip this end up running killall node, which ignores launchd’s restart policy and guarantees a surprise third process.
Reproducible rollout checklist
- Create both directories with
chmod 700and verify ownership withls -le. - Reserve ports using
lsof -nP -iTCP:8787 -sTCP:LISTENand8788; free zombies before binding. - Copy plist templates, then diff—ensure only label, paths, ports, and environment blocks differ.
- Run
openclaw doctor(or your packaged doctor entrypoint) from each profile directory with the intended environment exported. - Start staging first; run a synthetic curl that hits
127.0.0.1:8787/health(adjust path to your gateway) for 200 responses across three retries spaced two seconds apart. - Only then bootstrap production, repeating the health probe on 8788.
- Archive plist checksums in your ticket so drift reviews compare SHA-256 digests, not eyeballs.
- Document rollback:
launchctl bootoutthe prod label, revert plist, re-bootstrap staging alone if needed.
If probes fail while doctor passes, revisit interface binding: mixing 127.0.0.1 with 0.0.0.0 across profiles causes health checks to lie even when ports differ—keep each profile’s probe URL identical to the bind address recorded in its plist ProgramArguments.
FAQ
Can two gateways share one config directory?
No—token caches, sqlite locks, and downloaded skills will race; always split trees.
What if I only have one public hostname?
Terminate TLS on a reverse proxy and route by SNI or path to the two loopback ports; keep gateways bound locally.
How do I prove isolation to security?
Show separate plist labels, distinct log paths, independent API keys, and doctor outputs captured per profile with timestamps.
Why not run both in Docker on Linux?
You lose macOS launchd, Keychain, and Apple Silicon GPU paths that many OpenClaw toolchains assume for desktop-class automation.
Apple Silicon Mac mini rentals combine low idle power—often under 12 W at desktop idle—with enough headroom to run two Node gateways, Safari-based smoke clients, and log stream tails concurrently. MacHTML’s cloud minis expose SSH and optional VNC so you can pair-debug plist XML with a colleague without shipping laptops across borders. When the pilot ends, stop the instance: you pay for the calendar days you rehearsed, not a three-year depreciation schedule.
That elasticity matters for OpenClaw because profiles are temporary by nature: staging should churn weekly while production stays boring. Renting keeps both worlds physically possible on one quiet desk without convincing procurement to buy a second metal box you will idle after the feature ships.
Rehearse dual OpenClaw profiles on real macOS hardware
Rent a cloud Mac mini to validate plist isolation, separate ports, and doctor runs before you merge automation changes into production.