원격 Mac에서 launchd로 OpenClaw 게이트웨이 자동 배포

금요일 밤, Webhook이 한꺼번에 빨갛게 됩니다. SSH로 원격 Mac에 들어가 보니 게이트웨이 프로세스는 이미 사라졌습니다——지난번에 수동으로 openclaw gateway run만 띄워 둔 상태였죠. Mac이 새벽에 자동 재부팅된 뒤 아무도 그 명령을 다시 치지 않았습니다. Discord 봇은 온라인인데 18789 포트는 비어 있고, GitHub 콜백이 502를 47건 쌓아 두었습니다.

이건 OpenClaw 버그가 아니라 운영 모델이 아직 「개발기 사고」에 머물러 있기 때문입니다. 대화형 시작, plist 수동 편집, 머신마다 다른 설정. 2026년에는 게이트웨이를 인프라로 다루고, macOS에서는 launchd가 정답입니다——부팅 시 자동 시작, 크래시 복구, 로그 영구 저장, 설정 Git화.

이 글은 0에서 검수까지 자동화 한 세트를 제공합니다. onboard 등록, 프로덕션 plist 템플릿, 일괄 bootstrap 스크립트, 헬스 프로브와 업그레이드·롤백 순서. 장애 대응은 자매 글 OpenClaw 게이트웨이 launchd 안정성 핸드북, 다중 머신 CI는 OpenClaw 손에 익는 배포와 GitHub Actions 자동화를 참고하세요.

Quick Answer: 가장 흔한 3가지 질문

질문 바로 답 주의
재부팅 후에도 게이트웨이를 유지하는 가장 빠른 방법? openclaw onboard에서 launchd 선택, 또는 글 하단 bootstrap 스크립트 실행 등록 전 doctor를 녹색으로. crash loop 방지
수동 gateway run과 launchd를 같이 쓸 수 있나요? 불가——포트 이중 점유 변경 전 launchctl bootout + lsof로 포트 정리
「진짜 고가용」을 검수하려면? reboot → 2분 대기 → gateway probe + 외부망 curl localhost만 테스트하지 마세요

1. 수동 설정을 그만둬야 하는 이유

원격 상주 Mac에서 수동 설정이 실패하는 전형적 패턴:

방법 겉보기 이점 실제 비용
SSH에서 nohup openclaw gateway run & 5초 만에 기동 재부팅 시 소실. 로그 로테이션 없음. 종료 코드 불명
머신마다 plist 수동 편집 「포트만 바꾸면 됨」 Label 충돌, PATH 드리프트, diff 불가 업그레이드
문서에 「로그인 후 수동 시작」 TCC 회피 정전 복구 때마다 장애
Docker + launchd 동시 기동 「이중 안전망」 18789 경쟁. State 디렉터리 이중 잠금
핵심: 게이트웨이는 상태를 가진 장기 연결 서비스이지 일회성 스크립트가 아닙니다. launchd에 프로세스 감시를 맡기고, 당신은 설정과 프로브에 집중하는 것——그게 자동화입니다.

2. 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 상시 점등보다 통제하기 쉽습니다.

3. LaunchAgent vs LaunchDaemon

관점 LaunchAgent(사용자 도메인) LaunchDaemon(시스템 도메인)
경로 ~/Library/LaunchAgents/ /Library/LaunchDaemons/
시작 시점 사용자 로그인 후 시스템 부팅, GUI 로그인 불필요
TCC / 키체인 사용자 권한 상속 가능 제한적. 순수 네트워크 데몬에 적합
권장 시나리오 브라우저 자동화, 사용자 디렉터리 읽기 플러그인 순 HTTP/Webhook 게이트웨이, GUI 비의존

2026 기본 권장: 먼저 LaunchAgentonboarddoctor를 통과합니다. 로그인 세션이 불필요함을 확인한 뒤 Daemon으로 이전하고 Runbook에 기록하세요. 어느 쪽이든 ProgramArguments절대 경로——launchd.zshrc를 읽지 않습니다.

4. 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만 얻습니다.

5. 프로덕션 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.

6. 일괄 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 토큰, 리전)만 주입. 신규 머신을 베어메탈에서 probe 녹색까지 5분——그게 「더 이상 수동 설정하지 마세요」입니다.

7. 헬스 프로브와 외곽 자가 복구

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로 종료되어 「랜덤 끊김」처럼 보입니다.

8. 설정 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 개별 실행

9. 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 로그 폭주 없음

10. 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 한 대에서 bootstrap을 통과하고 reboot 연습을 한 뒤, 7단계 체크리스트를 팀 Wiki에 붙이세요. 전용 노드가 필요하면 Macstripe 홈에서 리전을 고르시면 됩니다.