遠端 Mac 上用 launchd 自動化部署 OpenClaw 閘道

週五晚上,Webhook 突然全紅。你 SSH 進遠端 Mac,發現閘道程序早就沒了——上次是你手動 openclaw gateway run 啟動的,Mac 凌晨自動重啟後沒人再敲那條指令。Discord 機器人在線,但 18789 埠號空著,GitHub 回呼堆了 47 條 502。

這不是 OpenClaw 的 bug,是維運模型還停留在「開發機思維」:互動式啟動、plist 手改、每台機器設定各一份。2026 年要把閘道當基礎設施來管,macOS 上的正解是 launchd——開機自啟、當機拉起、日誌落碟、設定可 Git 化。

本文交付一套從 0 到驗收的自動化方案:onboard 註冊、生產級 plist 模板、一鍵 bootstrap 腳本、健康探針與升級回滾順序。排錯見姊妹篇 OpenClaw 閘道 launchd 穩定性排錯手冊;多機 CI 編排見 OpenClaw 手把手部署與 GitHub Actions 多機協作

Quick Answer:三個最常見問題

問題 直接答案 注意
最快讓閘道「重啟還在」? openclaw onboard 選 launchd,或跑文末 bootstrap 腳本 doctor 綠再註冊,避免 crash loop
手動 gateway run 和 launchd 能並存嗎? 不能——會雙佔埠號 改前 launchctl bootout + lsof 清埠號
怎麼驗收「真的高可用」? reboot → 等 2 分鐘 → gateway probe + 外網 curl 別只測 localhost

一、為什麼必須告別手動設定

在遠端常駐 Mac 上,手動設定的典型失敗模式如下:

做法 看起來省事 實際代價
SSH 裡 nohup openclaw gateway run & 5 秒起服務 重啟即失;無日誌輪替;結束代碼不可見
每台機器手改 plist 「就改個埠號」 Label 衝突、PATH 漂移、無法 diff 升級
文件寫「登入後手動點啟動」 繞過 TCC 麻煩 節假日斷電恢復必出事
Docker + launchd 雙開 「多一層保險」 搶 18789;State 目錄雙寫鎖
核心判斷:閘道是有狀態長連線服務,不是一次性腳本。launchd 把「程序監督」交給系統,你把精力放在設定與探針上——這才叫自動化。

二、閘道「高可用」在 Mac 上指什麼

單機 Mac 做不到 Kubernetes 式多副本,但可以做到維運意義上的 HA

  • Survive reboot:開機 2 分鐘內閘道自動監聽,無需人工 SSH。
  • Survive crash:KeepAlive + ThrottleInterval,程序異常結束後退避重啟,不讓 CPU 打滿。
  • Survive config drift:plist、環境變數、~/.openclaw 有備份與 Git 記錄。
  • Survive silent failure:外層 healthcheck 發現「埠號在但 probe 失敗」。
  • Survive upgrade:backup → doctor --fix → gateway restart 固定順序,可腳本化。

實測:一台 M4 Mac mini(24GB)跑 OpenClaw 閘道 + 輕量外掛,閒置功耗約 4–6W;閘道程序記憶體通常 200–450MB。把機器放在 遠端 Mac 部署實操路徑上,比在辦公室工位留一台 iMac 常亮更可控。

三、LaunchAgent 還是 LaunchDaemon

維度 LaunchAgent(使用者域) LaunchDaemon(系統域)
路徑 ~/Library/LaunchAgents/ /Library/LaunchDaemons/
啟動時機 使用者登入後 系統啟動,無需 GUI 登入
TCC / 鑰匙圈 可繼承使用者授權 受限,適合純網路守護
建議場景 需瀏覽器自動化、外掛讀使用者目錄 純 HTTP/Webhook 閘道、無 GUI 依賴

2026 預設建議:先用 LaunchAgent 跑通 onboarddoctor;確認不需要登入工作階段後,再遷 Daemon 並寫進 Runbook。無論哪種,ProgramArguments 必須用絕對路徑——launchd 不讀你的 .zshrc

四、onboard 一鍵註冊 launchd

OpenClaw 的 onboard 向導會把 Node 路徑、State 目錄、閘道埠號寫進設定,並在較新版本裡支援直接安裝 launchd 服務。建議順序:

# 1. 確認執行環境(與 plist 內 PATH 一致)
node -v          # 期望 v22.x
which openclaw   # 記下絕對路徑,如 /opt/homebrew/bin/openclaw

# 2. 預檢
openclaw doctor

# 3. 互動式 onboard(按提示啟用 Gateway + launchd)
openclaw onboard

# 4. 驗收
launchctl print "gui/$(id -u)/com.openclaw.gateway" 2>/dev/null || launchctl list | grep -i openclaw
lsof -nP -iTCP:18789 -sTCP:LISTEN
openclaw gateway probe
口訣:互動 SSH 跑通 → onboard 固化 → reboot 驗收。跳過第二步直接 KeepAlive,只會得到更快的 crash loop。

五、生產級 plist 模板(可進 Git)

onboard 未產生 plist,或你需要在 infra 倉庫裡顯式版本化,可用下面模板。把 OPENCLAW_BIN 換成 which openclaw 的輸出:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.openclaw.gateway</string>
  <key>ProgramArguments</key>
  <array>
    <string>/opt/homebrew/bin/openclaw</string>
    <string>gateway</string>
    <string>run</string>
  </array>
  <key>WorkingDirectory</key>
  <string>/Users/your-ci-user</string>
  <key>EnvironmentVariables</key>
  <dict>
    <key>PATH</key>
    <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
    <key>HOME</key>
    <string>/Users/your-ci-user</string>
  </dict>
  <key>StandardOutPath</key>
  <string>/Users/your-ci-user/Library/Logs/OpenClawGateway/gateway.stdout.log</string>
  <key>StandardErrorPath</key>
  <string>/Users/your-ci-user/Library/Logs/OpenClawGateway/gateway.stderr.log</string>
  <key>RunAtLoad</key>
  <true/>
  <key>KeepAlive</key>
  <dict>
    <key>SuccessfulExit</key>
    <false/>
  </dict>
  <key>ThrottleInterval</key>
  <integer>30</integer>
</dict>
</plist>

載入(Ventura+):

UID_NUM=$(id -u)
DOMAIN="gui/${UID_NUM}"
LABEL="com.openclaw.gateway"
PLIST="${HOME}/Library/LaunchAgents/${LABEL}.plist"

launchctl bootout "${DOMAIN}/${LABEL}" 2>/dev/null || true
launchctl bootstrap "${DOMAIN}" "${PLIST}"
launchctl kickstart -k "${DOMAIN}/${LABEL}"

別踩的坑:

  • Intel Mac 上 Homebrew 常在 /usr/local/bin,Apple Silicon 在 /opt/homebrew/bin——plist 裡寫死,別寫「通用 PATH」。
  • 日誌目錄先 mkdir -p,否則 launchd 可能起不來且 stderr 無處可查。
  • 同一 Label 不要同時存在於使用者域與系統域;升級前先 bootout 舊 job。

六、一鍵 bootstrap 腳本

把「裝 CLI → doctor → 寫 plist → bootstrap → probe」收成一條指令,適合新租的雲 Mac 或 GitHub Actions 自託管節點。完整腳本見本文資源目錄:

resources/bootstrap-openclaw-gateway-launchd.sh

在遠端 Mac 上執行:

chmod +x bootstrap-openclaw-gateway-launchd.sh
./bootstrap-openclaw-gateway-launchd.sh

腳本邏輯摘要:

  1. 偵測 node / openclaw,缺失則 npm i -g openclaw@latest
  2. 建立 ~/Library/Logs/OpenClawGateway
  3. 優先 openclaw onboard;若無 plist 則寫入兜底 LaunchAgent
  4. launchctl bootstrap + kickstart -k
  5. lsof + openclaw gateway probe 驗收
團隊用法:腳本進 infra 倉庫,每台 Mac 只注入 secrets(API token、區域)。新機器 5 分鐘內從裸機到 probe 綠——這才是「不要再手動設定」。

七、健康探針與自愈外層

KeepAlive 只能管程序在不在,管不了「程序僵死但埠號仍 LISTEN」。加一層輕量探針 LaunchAgent(每 5 分鐘):

#!/bin/bash
# ~/bin/openclaw-gateway-healthcheck.sh
set -euo pipefail
PORT="${OPENCLAW_GATEWAY_PORT:-18789}"
LABEL="com.openclaw.gateway"
DOMAIN="gui/$(id -u)"

if ! openclaw gateway probe >/dev/null 2>&1; then
  logger -t openclaw-ha "probe failed, kickstart gateway"
  launchctl kickstart -k "${DOMAIN}/${LABEL}" || true
fi

配合 StartCalendarInterval 的 plist 掛到 ~/Library/LaunchAgents/com.openclaw.gateway-healthcheck.plist。外層還可接 UptimeRobot、自建 Prometheus blackbox——但探針一定要走與 Webhook 相同的路徑(含反向代理與 TLS),別只 curl localhost。

日誌輪替建議用 newsyslog 或按大小 truncate,避免單檔撐滿 NVMe——磁碟滿時 launchd 子程序會以 ENOSPC 結束,表現像「隨機斷線」。

八、設定 Git 化與滾動升級

把下面檔案納入版本控制,PR 裡 review 而不是 SSH 手改:

檔案 用途
launchagents/com.openclaw.gateway.plist 閘道主服務
scripts/bootstrap-openclaw-gateway-launchd.sh 新節點引導
scripts/upgrade-openclaw-gateway.sh 固定升級順序
docs/runbook-gateway.md on-call 手冊

升級腳本最小順序(與 多通道閘道穩定性姊妹篇一致):

openclaw backup create
npm update -g openclaw@latest   # 或鎖版本號
openclaw doctor --fix
launchctl kickstart -k "gui/$(id -u)/com.openclaw.gateway"
openclaw gateway probe
# 多外掛環境:逐個 browser/cron doctor

九、七步驗收清單

發版或新機器上線前,SSH 執行並打勾:

  • openclaw doctor 無 ERROR
  • launchctl print gui/$(id -u)/com.openclaw.gateway 狀態為 running
  • lsof -nP -iTCP:18789 -sTCP:LISTEN PID 與 plist 一致
  • openclaw gateway probe 成功
  • 從辦公網/手機網路 curl 公網入口(非僅 127.0.0.1)
  • sudo reboot 後 2 分鐘內 probe 仍成功
  • 故意 kill 閘道 PID,30 秒內自動恢復且 Throttle 不刷屏

十、為什麼仍建議 Mac mini 跑這套自動化

閘道要長期在線、低噪音、路徑統一Mac mini M4 在 Apple Silicon 上 idle 約 4W,7×24 比桌上型電腦省電一個數量級;launchd、Homebrew、OpenClaw 的 ~/.openclaw 與本機開發機完全一致,Runbook 不用改兩套。

若你正在把 OpenClaw 從「個人筆電上的實驗」遷到獨享遠端 Mac,建議單機跑順自動化再加節點。Macstripe 首頁 可按天試用各區域 Mac mini,把 bootstrap 腳本跑一遍,比在辦公室留一台機器常亮更省心。

FAQ

OpenClaw 閘道一定要用 launchd 嗎?

不是必須,但 macOS 上 launchd 是官方守護程序管理器,比 nohup 更適合無人值守。Docker 適合多版本並行;launchd 適合少一層虛擬化、低延遲閘道。

LaunchAgent 和 LaunchDaemon 怎麼選?

需要使用者 TCC 或鑰匙圈時用 LaunchAgent;必須無人登入即監聽時用 LaunchDaemon(root)。多數團隊從 Agent 起步。

onboard 和手寫 plist 會衝突嗎?

Label 必須唯一。升級前先 bootout,避免雙程序搶 18789。最終 plist 建議進 Git。

probe 失敗但埠號在監聽?

查鑑權、TLS、綁定位址。先 doctor,再對照 ~/.openclaw;細節見 launchd 排錯手冊

多台 Mac 怎麼批次部署?

自託管 Runner + 同一 bootstrap 腳本,secrets 管令牌,滾動 probe 驗收。參見 GitHub Actions 多機協作

總結

不要再手動設定的意思,不是「永遠不碰終端機」,而是終端機裡只跑腳本,不跑即興指令onboard 註冊 launchd、plist 進 Git、bootstrap 上新機、probe 驗收、healthcheck 兜底。閘道從「某次 SSH 工作階段裡的前台程序」變成「可重複的基礎設施」。

下一步:在一台遠端 Mac 上跑通 bootstrap,做一次 reboot 演練,把七步清單貼進團隊 Wiki。需要獨享節點時,從 Macstripe 首頁 選區域即可。