2026‑04‑28 · OpenClaw, launchd KeepAlive, Exit‑Codes, ThrottleInterval und Respawn‑/Crash‑Loop‑Triage auf einem headless gemieteten Cloud‑Mac (HK / JP / KR / SG / US)
Die meisten OpenClaw‑Produktionsinstallationen auf einem Mac mini M4 stehen nur hinter SSH, mit Reverse‑Proxy auf 127.0.0.1 und JSON‑Logs über strukturiertes Logging. Wenn launchd den Gateway‑Prozess übernimmt, ist der Ausfallmodus, den Sie irgendwann sehen, kein mysteriöses LLM‑Verhalten: Es ist schneller Job‑Neustart nach Exit — mal harmlos (Sie wollten, dass launchd immer läuft), mal katastrophal (Config, fehlendes PATH, Crash vor dem ersten Bind). Dieser Deep‑Dive 2026‑04‑28 verbindet HTTP‑Druck beim Provider und Webhook‑Gegendruck mit dem lokalen Prozess‑Supervisor: wie KeepAlive und ThrottleInterval zusammenspielen, wie Sie bei lautem Respawn erste Fehlzeilen in StandardError lesen und wann Sie den LaunchAgent entladen, um interaktiv zu reproduzieren. Ergänzend: Umgebung + launchd und openclaw doctor + Allowlist.
Auf einem headless Cloud‑Mac ist launchd Ihr Init
Anders als am Laptop schaut niemand ins Terminal, wenn npm oder openclaw gateway endet. Das robuste Muster: eigener Service‑Account, Logs in rotierende Dateien, launchd besitzt den Lebenszyklus. Ein häufiger Fehler 2026: macOS und Linux‑systemd eins zu eins vergleichen — KeepAlive und RunAtLoad sind mächtig und brauchen explizite Drosselung, sonst wird aus einem 2‑Sekunden‑Tippfehler tausende execve‑Ereignisse pro Stunde, die ~/Library/Logs und den Remote‑Log‑Shipper füllen. Behandeln Sie Prozess‑Exit als Erstklass‑Signal, nicht als „schon wieder abgestürzt“.
- User LaunchAgents —
~/Library/LaunchAgentsfür langlebige Dienste pro Nutzer; die meisten OpenClaw‑Setups landen hier mit geringstem Privileg. - System LaunchDaemons — Admin‑Schreibzugriff, größerer Blast‑Radius; vermeiden, außer Sie brauchen wirklich Root.
KeepAlive: welche Variante haben Sie aktiviert?
Apples Property‑Liste für KeepAlive kann boolesch sein oder ein Dictionary mit bedingten Gründen (Netzwerk, Pfad …). Boolesch true ist der Vorschlaghammer: bei jedem Exit neu starten — richtig für einen 24/7‑Netz‑Daemon, falsch für eine Einmal‑Migration. Feiner: NetworkState oder Pfad, der existieren muss. Bei „warum startet das neu?“ zuerst klären: Habe ich launchd gebeten, am Leben zu halten, oder beendet sich die App und Exit ≠ Crash? Sauberer Exit 0 in einer KeepAlive true‑Welt löst trotzdem Neustart — wie bei einem Wrapper, der nach falsch getrenntem Kind beendet.
ThrottleInterval auf die Sekunde entspricht, ist der Supervisor der Hammer; flattert es ohne Rhythmus, eher unbehandelte Promise‑Rejections oder Bind‑Race — nicht das LLM.
StandardOut / StandardError: echte Dateien
Headless‑SSH ist kein TTY; stdio ins Nichts kostet die ersten 200 ms des Crashes. StandardOutPath und StandardErrorPath auf ein vom Dienstnutzer beschreibbares Verzeichnis, Rotation per newsyslog oder täglichem cron, niemals nur Scrollback der interaktiven Shell. Bei Egress/TLS‑Vorfällen ist ein zeitlich ausgerichteter Schnitt über stdout, nginx‑Access und Gateway‑JSON mehr wert als ein hübsches Grafana‑Dashboard.
ThrottleInterval: Bremse beim Neustart
ThrottleInterval ist die Mindest‑Wartezeit in Sekunden nach Exit, bevor launchd den Job neu starten darf. 10 für ruhige Logs beim Hochfahren, 1–2 im Betrieb, wenn transient Locks ohne wache Operator:innen überwunden werden sollen. Dazu: launchctl print gui/$(id -u)/com.example.openclaw (User‑Domain, Label anpassen) für State und letzten Exit. In der Bereitschaft dokumentieren: „Throttle=10 ⇒ schlimmstenfalls ein Neustart alle 10 s“ — Erwartung, wenn jemand MTTR < 1 min für Software, nicht Infrastruktur will.
openclaw doctor kann grün sein, während launchd noch in einer Crash‑Loop steckt — der Doctor ist interaktiv und kurzlebig mit vollem Login‑Environment; Ihre Plist könnte PATH für node oder ein globales npm‑Präfix vermissen. Immer env | sort gegen Doctor‑Ausgabe diffen.
Exit‑Codes, die Sie wirklich in Tickets lesen
| Exit / Symptom | Wahrscheinliche OpenClaw‑Ursache | Zuerst tun |
|---|---|---|
1 (generisch) + eine Stack‑Spur in stderr |
Config‑Parse, fehlende OPENCLAW_‑Variable, falsches cwd |
Gleiche ProgramArguments per SSH mit set -a; source your.env; set +a wie im Secrets‑Muster. |
2 (Misuse) vom Shell‑Wrapper |
Option‑Parsing oder Mac‑Pfad‑Quoting | Rohe argv im Wrapper loggen, Glob vermeiden, bei arm64 prüfen, ob Node nicht unter Rosetta läuft (SSH‑Profile). |
126 / 127 |
Nicht ausführbar oder node nicht in der Plist‑PATH |
Absoluter Pfad zum Binary, which -a node im Service‑Kontext. |
| Signal 9 / Exit 137 (Linux‑Jargon) — unter macOS oft harter Kill | OOM, manueller Kill oder (selten) Watchdog — auf M4 Speicher von LLM + Gateway gemeinsam prüfen | memory pressure in der Konsole oder Parallelität per Provider‑Shaping senken. |
Crash‑Loop‑Triage: sechs Fragen vor dem Modellwechsel
- Port belegt? Irrläufer‑Gateway oder Zombie‑Listener verhindern Bind — nginx Reverse Proxy und Portabgleich.
- Exit 0 in der Schleife? Wrapper mit Exit 0 kann
KeepAliveauslösen ohneexecins Kind. - stderr jedes Mal gleich? Gleiche Einzeile → deterministische Config; wechselnder Stack → Race oder Netz‑Flake.
- Was war zuletzt geändert? An Git‑Tag oder
npm‑Lock koppeln; Release‑Disziplin hilft auch ohne App Store. - Upstream 401 und Retry endet nie? eher Circuit Breaker als mehr
KeepAlive‑Druck — 429/503 bei LLM‑Limits. - Hammer gedrosselt? Sonst ist der erste „Fix“ oft nur
ThrottleIntervalzum Loglesen, dann echter Config/Code‑Fix.
log stream --style compact --predicate 'process == "openclaw"' erst nach gesunkener Restart‑Rate — sonst verschluckt Rauschen die erste Signalzeile.
Plist‑Checkliste (Confluence / Notion)
- Label — eindeutiger Reverse‑DNS; kein fremdes
com.‑Präfix unter derselbenUIDwiederverwenden. - ProgramArguments[0] — voller Pfad, keine Überraschungen durch Login‑Shells.
- WorkingDirectory — Repo‑Root für relative Config‑Pfade; passend zu
openclaw doctor. - EnvironmentVariables —
HOME,PATH, ggf.NODE_OPTIONS— mit Secrets‑Doku abstimmen. - KeepAlive + ThrottleInterval — aggressiven Restart nicht mit winzigem stderr‑Limit ohne Rotation kombinieren.
plutil -lint ~/Library/LaunchAgents/com.yourorg.openclaw.plist
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.yourorg.openclaw.plist
Sieben Ops‑Schritte bei „OpenClaw in SG down“
- Edge‑Gesundheit (nginx) — 502 vs. 504 trennt Upstream vs. Gateway; bei Ausfall nach außen DNS / TLS prüfen.
- launchd‑State —
launchctl printzum Label; letzter Exit und Throttle‑Fenster. - Logs stabilisieren — bei Flattern
ThrottleInterval. - Interaktive Repro unter derselben
UIDohnelaunchd. - Config‑Diff und Secret‑Rotation mit Vier‑Augen‑Review.
- Roll forward auf bekannte gute
npm‑Version, kein Geheim‑Patch in Prod. - Post‑Incident — ein Absatz im Ticket: Root Cause, Detection‑Lücke, Schutzmaßnahme (z. B. Alert bei Exit ≠ 0 in 1 Minute).
FAQ: launchd vs. OpenClaw‑Gateway
| Frage | Antwort 2026‑04‑28 |
|---|---|
ProcessType auf Interactive? |
Für Server‑Daemons meist nein; Interactive ändert Scheduling. Standard‑Background, außer Apple empfiehlt für Ihren macOS‑Build explizit anders. |
caffeinate nötig? |
Auf einem gemieteten 24/7‑Mac mini M4 im Rechenzentrum ist Sleep meist per Energierichtlinie aus; auf Laptop‑Hosts (nicht MacXCode) behebt caffeinate keinen Resume‑Crash. |
Warum der Apple‑Silicon Mac mini M4 in diesem Runbook vorkommt
launchd ist nur so zuverlässig wie das Metall darunter. Ein Bare‑Metal‑Mac mini M4 in Hongkong, Tokio, Seoul, Singapur oder den USA mit 1–2 TB und planbarem CPU‑Scheduling macht aus „Haben wir das Gateway mit zu vielen Tool‑Calls OOM gemacht?“ eine messbare Frage. Dieselben MPS‑freundlichen Kerne, die lokale ML‑Experimente tragen, lassen Platz für Log‑Forwarder, Reverse‑Proxy und OpenClaw auf einer Abrechnungseinheit — deshalb lesen Teams diese Artikel mit regionalen Preisen und Zugangsleitfaden, wenn der Laptop eines Einzelnen nicht mehr reicht.
OpenClaw dort betreiben, wo launchd, Logs und Netz passen
1–2 TB · Apple Silicon · SSH / optional VNC