リモート Mac で launchd により OpenClaw ゲートウェイを自動デプロイ

金曜の夜、Webhook が一斉に赤になる。SSH でリモート Mac に入ると、ゲートウェイプロセスはとっくに消えている——前回は手動で openclaw gateway run しただけ。Mac が深夜に自動再起動してから、誰もそのコマンドを打っていない。Discord ボットはオンラインだが、ポート 18789 は空。GitHub コールバックが 47 件の 502 を積んでいる。

これは OpenClaw のバグではなく、運用モデルが「開発機思考」のままだからです。対話的起動、plist の手編集、マシンごとにバラバラな設定。2026 年、ゲートウェイはインフラとして扱い、macOS では launchd が正解——起動時自動起動、クラッシュ復旧、ログ永続化、設定の Git 化。

本文はゼロから検収までの自動化一式です。onboard 登録、本番 plist テンプレート、一括 bootstrap スクリプト、ヘルスプローブとアップグレード・ロールバック順序。排錯は姊妹記事 OpenClaw ゲートウェイ launchd 安定性トラブルシューティング手順書、複数機 CI は OpenClaw 手取り足取りデプロイと GitHub Actions 自動化 を参照。

Quick Answer:よくある 3 つの質問

質問 答え 注意
再起動後もゲートウェイを残す最短手順は? openclaw onboard で launchd を選ぶ、または文末の bootstrap スクリプト 登録前に doctor を緑に。crash loop を避ける
手動 gateway run と launchd は併用できる? 不可——ポート二重占有 変更前に launchctl bootoutlsof でポート解放
「本当に高可用」と検収するには? 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 年のデフォルト:まず LaunchAgentonboarddoctor を通す。ログインセッションが不要と確認できてから 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 で検収。2 番目を飛ばして KeepAlive だけ入れると、より速い crash loop だけが得られます。

五、本番 plist テンプレート(Git 可)

onboard が plist を生成しない場合、または infra リポジトリで明示的にバージョン管理する場合は以下のテンプレート。OPENCLAW_BINwhich 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 をユーザードメインとシステムドメインに置かない。アップグレード前に古い job を bootout

六、一括 bootstrap スクリプト

「CLI インストール → doctor → plist 作成 → bootstrap → probe」を 1 コマンドにまとめ、新規のクラウド 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 トークン、リージョン)だけ注入。新マシンを裸機から probe 緑まで 5 分——それが「手動設定はもう終わり」です。

七、ヘルスプローブと外層の自己回復

KeepAliveプロセスの有無しか見られず、「プロセスは僵死しているがポートは LISTEN」の状態は検知できません。5 分ごとの軽量プローブ LaunchAgent を追加:

#!/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 含む)を通すこと。localhost だけ curl しない。

ログローテは newsyslog またはサイズベース truncate。単一ファイルが NVMe を埋めると、ディスク満杯で launchd 子プロセスが ENOSPC 終了し「ランダム切断」に見える。

八、設定の Git 化とローリングアップグレード

以下をバージョン管理に入れ、SSH 手編集ではなく PR でレビュー:

ファイル 用途
launchagents/com.openclaw.gateway.plist ゲートウェイ本体
scripts/bootstrap-openclaw-gateway-launchd.sh 新ノードブートストラップ
scripts/upgrade-openclaw-gateway.sh 固定アップグレード順序
docs/runbook-gateway.md オンコール手順書

最小アップグレード順序(マルチチャネルゲートウェイ安定性姊妹記事と同じ):

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 を個別に

九、7 ステップ検収チェックリスト

リリースまたは新マシン投入前に 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 成功
  • 意図的にゲートウェイ PID を kill、30 秒以内に自動復旧し Throttle がログを埋めない

十、Mac mini でこの自動化を回す理由

ゲートウェイは長期オンライン・低騒音・パス統一が必要。Mac mini M4 は Apple Silicon でアイドル約 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 失敗だがポートは LISTEN?

認証、TLS、バインドアドレスを確認。まず doctor、次に ~/.openclaw。詳細は launchd トラブルシューティング手順書

複数 Mac を一括デプロイするには?

セルフホスト Runner + 同一 bootstrap、secrets でトークン管理、ローリング probe 検収。GitHub Actions マルチランナー協業 を参照。

まとめ

手動設定はもう終わりとは「ターミナルを触らない」ではなく、ターミナルではスクリプトだけを走らせ、即興コマンドは打たないことです。onboard で launchd 登録、plist を Git に、bootstrap で新機投入、probe で検収、healthcheck で兜底。ゲートウェイは「ある SSH セッションのフォアグラウンドプロセス」から「再現可能なインフラ」になります。

次の一歩:リモート Mac 1 台で bootstrap を通し、reboot 演習を行い、7 ステップチェックリストをチーム Wiki に貼る。専用ノードが必要なら Macstripe ホーム からリージョンを選んでください。