租用 Mac mini 上 OpenClaw 网关 launchd 启动:node 绝对路径、ProcessType 与退出码 78 修复(2026-05-21)
在 ProxyMac 租用的 Mac mini M4(香港、日本、韩国、新加坡、美国节点)上,重启后 OpenClaw 网关 LaunchAgent 可能出现:管理端口始终不监听、launchctl list 显示退出码 78、或冷启动后 约三分钟 内 WebSocket 客户端持续收到 1006 异常关闭。本篇 2026 年 5 月 21 日现场手册聚焦 launchd plist 配置错误——ProgramArguments 里裸写 node、缺少 ProcessType 的 Interactive——而非 MCP 子进程残留。可与 网关 launchctl 重启恢复、无头 SSH 首次开机清单、Node 运行时与 nvm 对齐 对照阅读。
冷启动:退出码 78、慢监听与 WebSocket 1006
Apple Silicon 现场反馈里常见两类 launchd 故障形态。立刻退出 78 表示 launchd 未能成功 exec 网关——多见于 ProgramArguments 以 node 开头,而 launchd 环境下 PATH 为空或极短。延迟就绪 则表现为 launchctl list 显示任务在跑,但 lsof 数分钟内看不到监听;控制台 WebSocket 持续 1006 直到进程终于被调度。二者均不同于 ThrottleInterval 崩溃循环 那种 CPU 飙高、秒级反复拉起。
- 退出状态 78:出现在
launchctl bootstrap或登录后不久——检查~/Library/LaunchAgents/*.plist是否裸写node。 - 180 秒以上:空闲 mini 从开机到首次健康检查成功耗时过长。
- 控制通道 1006:SSH 与磁盘正常却无监听——多半是端口未起来,而非 TLS 配错。
- SSH 里手动
node gateway.js正常、LaunchAgent 失败——典型 PATH 与绝对路径分裂。
node -v 不一致,先读 运行时对齐。78 是「找不到二进制」;版本错配是「找到了但 ABI 不对」。
launchd 为何不吃 shell PATH,还会压低后台 Agent
LaunchAgent 继承的环境比 Terminal 交互会话瘦得多。文档与社区帖均强调:plist 里的 EnvironmentVariables 无法帮助解析 ProgramArguments 中的解释器名——launchd 先解析可执行文件,再应用环境变量键。因此把笔记本上 argv[0]=node 的 plist 原样拷到无头 ProxyMac mini,即便 XML 里写了 PATH 仍会失败。
另一方面,缺少 ProcessType 时,macOS 可能把网关当作后台任务,在重启后受电源与调度启发式影响。不少运维反馈:在 Label 旁加入 <key>ProcessType</key><string>Interactive</string> 后,冷启动到监听可从 约三分钟 缩到数秒。这是调度卫生,不是长期无人值守开 GUI——一次性 Keychain/TCC 请按 首次开机清单 用 VNC,日常仍走 SSH。
现场处置矩阵(信号 → 首选动作)
| 主要信号 | 首选响应(顺序重要) | 应留存证据 | 误操作回滚 | 负责人 |
|---|---|---|---|---|
| OpenClaw 标签最近退出码 78 | 将 argv[0] 改为 $(command -v node) 绝对路径;bootout → bootstrap | launchctl print gui/$UID/<label> + plist 原文 | 从 git 恢复旧 plist | 平台 SRE |
| 任务在跑,重启后 >60 秒仍无监听 | 添加 ProcessType Interactive;确认仅一个 label | 带时间戳的 lsof -nP -iTCP:<port> -sTCP:LISTEN | 若桌面策略禁止则移除 ProcessType | 自动化负责人 |
| 管理端口双监听 | 按 单监听恢复 操作 | lsof 中出现两个 PID | bootout 重复 label | 值班工程师 |
| <30 秒周期崩溃、CPU 高 | 调 ThrottleInterval / KeepAlive——非本文范围 | log show --predicate 'process == "launchd"' --last 5m | 还原 throttle 键 | SRE |
九步 plist 修复(ProxyMac mini SSH)
- 确认 label:
launchctl list | grep -i openclaw,记下完整反向 DNS 名称。 - 打印现场状态:
launchctl print gui/$(id -u)/<label>,截图最近退出码。 - 解析 Node: 同一用户下执行
command -v node,记录绝对路径(常见于/opt/homebrew或~/.nvm)。 - 改 plist:
ProgramArguments的 argv[0] 用该路径;网关入口脚本路径亦用绝对路径。 - 加 ProcessType: 若冷启动延迟符合现场描述,在根字典加入 Interactive。
- 校验 XML: 重载前
plutil -lint ~/Library/LaunchAgents/<file>.plist。 - 回收任务:
launchctl bootout gui/$(id -u) <label>再bootstrap同路径(或厂商 kickstart)。 - 测到监听时间: 每 5 秒跑一次
lsof,持续 120 秒;M4 上目标 <15 秒。 - 归档: plist 入基础设施仓库;在内部 runbook 链到本文。
/opt/homebrew/bin/node + openclaw-gateway 入口脚本的绝对路径 + --config + 配置 JSON 绝对路径——除非设置 WorkingDirectory,勿在包装脚本里依赖 cd。
验证监听、健康检查与 WebSocket 稳定
bootstrap 后确认配置的管理端口(运维文档常举 18999,以你的 config.json 为准)仅一个 PID 在 LISTEN。若启用 HTTP 健康路由则 curl 探测;再连桌面客户端,重启后 30 秒内不应再出现 1006。健康正常但 MCP 工具异常时,转读 MCP 残留卫生,勿反复改网关 plist。
自动化主机建议每季度做一次真重启:launchd 回归常出现在 macOS 安全更新之后,而非当日 SSH 改 plist 时。工单里请同时记录 uname -r 与到监听耗时。
预防:plist 基础设施化与 staging 标签隔离
- plist 进 git,Node 绝对路径由镜像构建模板注入(Homebrew 前缀或 nvm 默认)。
- dev/staging/prod 使用不同 LaunchAgent label,避免端口冲突——见重启恢复文。
- CI 冒烟: 部署后用 SSH 脚本断言 <20 秒出现监听再标健康。
- 在 HK/JP/KR/SG/US 备 disposable 实验机 调 plist,比在产线编排器上试错便宜。
常见问题
为什么 LaunchAgent 一启动就退出码 78? launchd 先解析 ProgramArguments 再应用 EnvironmentVariables;裸写 node 在空 PATH 下会失败。请改为 command -v node 的绝对路径,再 bootout 并 bootstrap。
为什么重启后要几分钟才监听? 默认 plist 常缺 ProcessType Interactive,系统会把后台启动降优先级。在根字典加入 Interactive 后,许多 Apple Silicon mini 可从约三分钟降到数秒。
与 ThrottleInterval 崩溃循环有何不同? 后者是 CPU 高、秒级反复拉起。78 是网关未运行前的配置错误。无崩溃风暴却长时间无监听,应查 ProcessType 或调度,而非 KeepAlive 与错误二进制死循环。
为何在租用 Mac mini 上夯实 OpenClaw launchd
网关 plist 属于基础设施:必须扛住重启、系统升级,以及只熟悉笔记本 Homebrew 路径的同事。Apple Silicon M4 冷启动时序可预期,macOS launchd 与 OpenClaw 官方 LaunchAgent 流程一致,HK / JP / KR / SG / US 节点让控制面更贴近你已对接的 API 区域。ProxyMac 支持在 staging mini 克隆已验证 plist,SSH 证明亚分钟级监听后再推广到生产——区域与套餐见 定价,接入方式见 帮助中心。