Automatisation du déploiement d'une passerelle OpenClaw avec launchd sur un Mac distant

Vendredi soir, les webhooks passent au rouge. Vous vous connectez en SSH au Mac distant et constatez que le processus de la passerelle a disparu depuis longtemps — la dernière fois, vous l'aviez lancé manuellement avec openclaw gateway run, et personne n'a relancé cette commande après le redémarrage automatique du Mac à 3 h du matin. Le bot Discord affiche « en ligne », mais le port 18789 est vide, et les callbacks GitHub ont empilé 47 erreurs HTTP 502.

Ce n'est pas un bug d'OpenClaw. C'est un modèle d'exploitation encore ancré dans la logique « machine de dev » : démarrages interactifs, plists modifiés à la main, une configuration différente sur chaque hôte. En 2026, on traite la passerelle comme une infrastructure, et sur macOS l'outil adapté est launchd — démarrage au boot, reprise après crash, journaux sur disque, configuration dans Git.

Cet article livre un parcours d'automatisation de zéro à la validation : enregistrement onboard, modèle plist de production, script bootstrap en un clic, sondes de santé et ordre de mise à niveau avec retour arrière. Pour le dépannage, voir le manuel de stabilité launchd pour la passerelle OpenClaw ; pour l'orchestration CI multi-machines, voir OpenClaw : manuel pas à pas du déploiement et de l'automatisation GitHub Actions.

Quick Answer : les trois questions les plus fréquentes

Question Réponse directe Attention
Le moyen le plus rapide de survivre à un redémarrage ? openclaw onboard avec launchd, ou exécuter le script bootstrap en fin d'article Lancer doctor au vert avant l'enregistrement — sinon vous obtenez une boucle de crash
Un gateway run manuel peut-il coexister avec launchd ? Non — double liaison de port launchctl bootout + lsof pour libérer le port avant de basculer
Comment prouver que c'est vraiment haute disponibilité ? reboot → attendre 2 minutes → gateway probe + curl externe Ne testez pas uniquement localhost

1. Pourquoi il faut abandonner la configuration manuelle

Sur un Mac distant toujours allumé, la configuration manuelle échoue de façon prévisible :

Approche Paraît simple Coût réel
nohup openclaw gateway run & en SSH Service opérationnel en 5 secondes Disparaît après reboot ; pas de rotation des journaux ; code de sortie invisible
Modifier le plist à la main sur chaque machine « Juste changer le port » Collisions de Label, dérive du PATH, pas de diff à la mise à niveau
Documentation : « cliquer sur Démarrer après connexion » Contourne les tracas TCC Coupure de courant pendant les vacances → panne garantie
Docker + launchd en parallèle « Une couche de sécurité en plus » Conflit sur le port 18789 ; verrous d'écriture double sur le répertoire d'état
Idée centrale : La passerelle est un service longue durée avec état, pas un script ponctuel. launchd gère la supervision des processus ; vous vous concentrez sur la configuration et les sondes — c'est cela, l'automatisation.

2. Ce que signifie la « haute disponibilité » d'une passerelle sur Mac

Un Mac seul ne peut pas offrir une HA multi-réplicas à la Kubernetes, mais on peut atteindre une HA au sens exploitation :

  • Survivre au reboot : la passerelle écoute dans les 2 minutes suivant le démarrage, sans SSH manuel.
  • Survivre au crash : KeepAlive + ThrottleInterval — une sortie anormale déclenche un redémarrage avec backoff sans saturer le CPU.
  • Survivre à la dérive de configuration : plist, variables d'environnement et ~/.openclaw sauvegardés et tracés dans Git.
  • Survivre à la panne silencieuse : un healthcheck externe détecte « port en écoute mais sonde en échec ».
  • Survivre à la mise à niveau : ordre fixe backup → doctor --fix → gateway restart, scriptable à chaque fois.

En pratique : un Mac mini M4 (24 Go) faisant tourner la passerelle OpenClaw et des plugins légers consomme environ 4–6 W au repos ; la mémoire du processus passerelle se situe typiquement entre 200 et 450 Mo. Placer la machine sur le chemin de déploiement natif sur Mac distant est plus prévisible que de laisser un iMac allumé au bureau.

3. LaunchAgent ou LaunchDaemon

Dimension LaunchAgent (domaine utilisateur) LaunchDaemon (domaine système)
Chemin ~/Library/LaunchAgents/ /Library/LaunchDaemons/
Moment de démarrage Après connexion utilisateur Au boot système, sans connexion GUI
TCC / trousseau Hérite des autorisations utilisateur Restreint — convient aux démons réseau purs
Idéal pour Automatisation navigateur, plugins lisant les répertoires utilisateur Passerelle HTTP/Webhook pure, sans dépendance GUI

Recommandation 2026 : Commencez par un LaunchAgent — faites passer onboard et doctor par ce biais. Ne passez au Daemon qu'après avoir confirmé que vous n'avez pas besoin d'une session de connexion, et documentez-le dans votre runbook. Dans tous les cas, ProgramArguments doit utiliser des chemins absoluslaunchd ne lit pas votre .zshrc.

4. Enregistrement launchd en un clic via onboard

Le onboard d'OpenClaw écrit le chemin Node, le répertoire d'état et le port de la passerelle dans la configuration, et les versions récentes prennent en charge l'installation directe du service launchd. Ordre recommandé :

# 1. Confirm runtime (must match PATH in plist)
node -v          # expect v22.x
which openclaw   # note absolute path, e.g. /opt/homebrew/bin/openclaw

# 2. Pre-flight
openclaw doctor

# 3. Interactive onboard (enable Gateway + launchd when prompted)
openclaw onboard

# 4. Acceptance
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
Formule : SSH interactif OK → onboard verrouille → reboot pour valider. Sauter l'étape deux et passer directement à KeepAlive — vous n'obtenez qu'une boucle de crash plus rapide.

5. Modèle plist de production (prêt pour Git)

Si onboard n'a pas généré de plist, ou si vous devez le versionner explicitement dans un dépôt infra, utilisez le modèle ci-dessous. Remplacez OPENCLAW_BIN par la sortie de 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>

Chargement (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}"

Pièges courants :

  • Sur Mac Intel, Homebrew est souvent dans /usr/local/bin ; sur Apple Silicon dans /opt/homebrew/bin — écrivez-le en dur dans le plist, pas un « PATH universel ».
  • mkdir -p le répertoire de journaux d'abord — sinon launchd peut échouer au démarrage sans pouvoir écrire stderr.
  • Ne gardez jamais le même Label à la fois dans le domaine utilisateur et système ; bootout l'ancien job avant la mise à niveau.

6. Script bootstrap en un clic

Condensez « installer le CLI → doctor → écrire le plist → bootstrap → sonde » en une seule commande — idéal pour un Mac cloud fraîchement loué ou un runner auto-hébergé GitHub Actions. Script complet dans les ressources de cet article :

resources/bootstrap-openclaw-gateway-launchd.sh

Sur le Mac distant :

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

Résumé du flux du script :

  1. Détecter node / openclaw ; si absent, lancer npm i -g openclaw@latest
  2. Créer ~/Library/Logs/OpenClawGateway
  3. Privilégier openclaw onboard ; si aucun plist n'existe, écrire un LaunchAgent de secours
  4. launchctl bootstrap + kickstart -k
  5. Valider avec lsof + openclaw gateway probe
Modèle d'équipe : Le script vit dans le dépôt infra ; chaque Mac ne reçoit que les secrets injectés (jeton API, région). De la machine nue à la sonde verte en moins de 5 minutes — c'est « fini la configuration manuelle ».

7. Sondes de santé et couche de réparation externe

KeepAlive ne vérifie que si le processus existe — pas « processus zombie mais port toujours en LISTEN ». Ajoutez un LaunchAgent de sonde léger (toutes les 5 minutes) :

#!/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

Associez-le à un plist avec StartCalendarInterval dans ~/Library/LaunchAgents/com.openclaw.gateway-healthcheck.plist. Vous pouvez aussi brancher UptimeRobot ou un exporteur blackbox Prometheus — mais la sonde doit suivre le même chemin que les webhooks (reverse proxy et TLS inclus), pas seulement un curl localhost.

Faites tourner les journaux avec newsyslog ou une troncature par taille pour qu'un seul fichier ne remplisse pas le NVMe — quand le disque est plein, les processus enfants launchd quittent avec ENOSPC et cela ressemble à des déconnexions aléatoires.

8. Configuration versionnée dans Git et mises à niveau progressives

Placez ces fichiers sous contrôle de version et revoyez-les en PR plutôt que d'éditer en SSH :

Fichier Rôle
launchagents/com.openclaw.gateway.plist Service passerelle principal
scripts/bootstrap-openclaw-gateway-launchd.sh Provisionnement d'un nouveau nœud
scripts/upgrade-openclaw-gateway.sh Séquence de mise à niveau fixe
docs/runbook-gateway.md Manuel d'astreinte

Ordre minimal du script de mise à niveau (aligné avec l'article associé sur la stabilité multi-canaux de la passerelle) :

openclaw backup create
npm update -g openclaw@latest   # or pin a version
openclaw doctor --fix
launchctl kickstart -k "gui/$(id -u)/com.openclaw.gateway"
openclaw gateway probe
# multi-plugin setups: run browser/cron doctor per plugin

9. Checklist d'acceptation en sept étapes

Avant une mise en production ou la mise en service d'une nouvelle machine, connectez-vous en SSH et cochez :

  • openclaw doctor sans ERROR
  • launchctl print gui/$(id -u)/com.openclaw.gateway état running
  • lsof -nP -iTCP:18789 -sTCP:LISTEN PID cohérent avec le plist
  • openclaw gateway probe réussi
  • curl l'entrée publique depuis le réseau bureau / données mobiles (pas seulement 127.0.0.1)
  • Après sudo reboot, la sonde réussit toujours dans les 2 minutes
  • kill volontaire du PID passerelle — reprise automatique en 30 secondes sans spam Throttle

10. Pourquoi le Mac mini reste le meilleur hôte pour cette automatisation

Une passerelle doit rester toujours allumée, silencieuse et cohérente en chemins. Le Mac mini M4 sur Apple Silicon consomme environ 4 W au repos — le 7×24 coûte un ordre de grandeur de moins qu'une tour de bureau. launchd, Homebrew et le ~/.openclaw d'OpenClaw correspondent à votre machine de dev locale, donc vous ne maintenez pas deux runbooks.

Si vous migrez OpenClaw d'une « expérience sur portable » vers un Mac distant dédié, solidifiez d'abord l'automatisation sur un seul nœud avant d'en ajouter. La page d'accueil Macstripe propose des essais de Mac mini facturés à la journée dans plusieurs régions — exécutez le script bootstrap une fois, c'est plus simple que de laisser une machine allumée au bureau.

FAQ

Faut-il obligatoirement utiliser launchd pour une passerelle OpenClaw ?

Pas obligatoire — mais sur macOS launchd est le gestionnaire de démons officiel et convient mieux qu'un nohup pour une exploitation sans surveillance. Docker convient aux déploiements multi-versions en parallèle ; launchd convient à une passerelle à faible latence avec moins de surcharge de virtualisation.

LaunchAgent ou LaunchDaemon — que choisir ?

Utilisez LaunchAgent lorsque vous avez besoin du TCC utilisateur ou du trousseau ; utilisez LaunchDaemon (root) lorsque le service doit écouter sans personne connectée. La plupart des équipes commencent par Agent.

onboard entre-t-il en conflit avec un plist écrit à la main ?

Le Label doit être unique. bootout avant la mise à niveau pour éviter deux processus en conflit sur le port 18789. Commitez le plist final dans Git.

La sonde échoue mais le port écoute ?

Vérifiez l'authentification, le TLS et l'adresse de liaison. Lancez doctor, puis comparez ~/.openclaw ; détails dans le manuel de dépannage launchd.

Comment déployer sur plusieurs Mac ?

Runners auto-hébergés + le même script bootstrap, secrets pour les jetons, validation progressive par probe. Voir la collaboration multi-machines GitHub Actions.

Conclusion

Fini la configuration manuelle ne signifie pas « ne jamais ouvrir un terminal » — cela signifie n'exécuter que des scripts dans le terminal, jamais de commandes improvisées : onboard enregistre launchd, le plist va dans Git, bootstrap provisionne les nouvelles machines, la sonde valide, le healthcheck rattrape les cas limites. La passerelle passe de « processus au premier plan dans une session SSH » à une infrastructure reproductible.

Prochaine étape : exécutez bootstrap sur un Mac distant, faites un exercice de reboot, collez la checklist en sept étapes dans le wiki de l'équipe. Quand vous avez besoin d'un nœud dédié, choisissez une région sur la page d'accueil Macstripe.