Gateway 서비스 runbook

마지막 업데이트: 2025-12-09

무엇인가

  • 단일 Baileys/Telegram 연결 및 제어/이벤트 플레인을 소유하는 항상 실행 중인 프로세스.
  • 레거시 gateway 명령을 대체합니다. CLI 진입점: openclaw gateway.
  • 중지될 때까지 실행됩니다. 치명적인 오류 시 0이 아닌 값으로 종료하여 supervisor가 재시작합니다.

실행 방법 (로컬)

openclaw gateway --port 18789
# stdio의 전체 debug/trace 로그:
openclaw gateway --port 18789 --verbose
# 포트가 busy인 경우 리스너를 종료한 다음 시작:
openclaw gateway --force
# dev 루프 (TS 변경 시 자동 재로드):
pnpm gateway:watch
  • Config hot reload는 ~/.openclaw/openclaw.json(또는 OPENCLAW_CONFIG_PATH)을 watch합니다.
    • 기본 모드: gateway.reload.mode="hybrid" (안전한 변경 사항을 hot-apply, 중요한 것에 대해 재시작).
    • Hot reload는 필요할 때 SIGUSR1을 통한 인프로세스 재시작을 사용합니다.
    • gateway.reload.mode="off"로 비활성화합니다.
  • WebSocket 제어 플레인을 127.0.0.1:<port>(기본값 18789)에 바인딩합니다.
  • 동일한 포트는 HTTP(제어 UI, hook, A2UI)도 제공합니다. 단일 포트 멀티플렉스.
  • 기본적으로 canvasHost.port(기본값 18793)에서 Canvas 파일 서버를 시작하여 ~/.openclaw/workspace/canvas에서 http://<gateway-host>:18793/__openclaw__/canvas/를 제공합니다. canvasHost.enabled=false 또는 OPENCLAW_SKIP_CANVAS_HOST=1로 비활성화합니다.
  • stdout에 로그를 기록합니다. launchd/systemd를 사용하여 살아있게 유지하고 로그를 회전합니다.
  • 문제 해결 시 로그 파일에서 stdio로 debug 로깅(핸드셰이크, req/res, 이벤트)을 미러링하려면 --verbose를 전달하세요.
  • --forcelsof를 사용하여 선택한 포트의 리스너를 찾고, SIGTERM을 보내고, 종료한 것을 로그하고, gateway를 시작합니다(lsof가 없으면 빠르게 실패).
  • supervisor(launchd/systemd/mac 앱 자식 프로세스 모드) 하에서 실행하는 경우 stop/restart는 일반적으로 SIGTERM을 보냅니다. 이전 빌드는 이것을 pnpm ELIFECYCLE 종료 코드 143(SIGTERM)로 표시할 수 있습니다. 이는 정상 종료이며 충돌이 아닙니다.
  • SIGUSR1은 승인된 경우 인프로세스 재시작을 트리거합니다(gateway tool/config apply/update, 또는 수동 재시작을 위해 commands.restart 활성화).
  • Gateway 인증은 기본적으로 필요합니다: gateway.auth.token(또는 OPENCLAW_GATEWAY_TOKEN) 또는 gateway.auth.password를 설정하세요. Tailscale Serve identity를 사용하지 않는 한 클라이언트는 connect.params.auth.token/password를 보내야 합니다.
  • 마법사는 loopback에서도 기본적으로 토큰을 생성합니다.
  • 포트 우선 순위: --port > OPENCLAW_GATEWAY_PORT > gateway.port > 기본값 18789.

원격 액세스

  • Tailscale/VPN 권장; 그렇지 않으면 SSH 터널:
    ssh -N -L 18789:127.0.0.1:18789 user@host
    
  • 클라이언트는 터널을 통해 ws://127.0.0.1:18789에 연결합니다.
  • 토큰이 구성된 경우 클라이언트는 터널을 통해서도 connect.params.auth.token에 토큰을 포함해야 합니다.

여러 Gateway (동일한 호스트)

일반적으로 불필요: 하나의 Gateway가 여러 메시징 channel 및 agent를 제공할 수 있습니다. 중복성 또는 엄격한 격리(예: rescue bot)를 위해서만 여러 Gateway를 사용하세요.

state + config를 격리하고 고유한 포트를 사용하는 경우 지원됩니다. 전체 가이드: Multiple gateways.

서비스 이름은 프로필 인식:

  • macOS: bot.molt.<profile> (레거시 com.openclaw.*가 여전히 존재할 수 있음)
  • Linux: openclaw-gateway-<profile>.service
  • Windows: OpenClaw Gateway (<profile>)

설치 메타데이터는 서비스 config에 포함됩니다:

  • OPENCLAW_SERVICE_MARKER=openclaw
  • OPENCLAW_SERVICE_KIND=gateway
  • OPENCLAW_SERVICE_VERSION=<version>

Rescue-Bot 패턴: 자체 프로필, state dir, workspace 및 기본 포트 간격으로 두 번째 Gateway를 격리하여 유지합니다. 전체 가이드: Rescue-bot guide.

Dev 프로필 (--dev)

빠른 경로: primary 설정을 건드리지 않고 완전히 격리된 dev 인스턴스(config/state/workspace)를 실행합니다.

openclaw --dev setup
openclaw --dev gateway --allow-unconfigured
# 그런 다음 dev 인스턴스를 대상으로:
openclaw --dev status
openclaw --dev health

기본값 (env/flag/config를 통해 재정의 가능):

  • OPENCLAW_STATE_DIR=~/.openclaw-dev
  • OPENCLAW_CONFIG_PATH=~/.openclaw-dev/openclaw.json
  • OPENCLAW_GATEWAY_PORT=19001 (Gateway WS + HTTP)
  • browser control service 포트 = 19003 (파생: gateway.port+2, loopback만)
  • canvasHost.port=19005 (파생: gateway.port+4)
  • agents.defaults.workspace 기본값은 --dev 하에서 setup/onboard를 실행할 때 ~/.openclaw/workspace-dev가 됩니다.

파생 포트 (경험 규칙):

  • 기본 포트 = gateway.port (또는 OPENCLAW_GATEWAY_PORT / --port)
  • browser control service 포트 = 기본 + 2 (loopback만)
  • canvasHost.port = 기본 + 4 (또는 OPENCLAW_CANVAS_HOST_PORT / config 재정의)
  • Browser 프로필 CDP 포트는 browser.controlPort + 9 .. + 108에서 자동 할당됩니다(프로필별로 유지됨).

인스턴스별 체크리스트:

  • 고유한 gateway.port
  • 고유한 OPENCLAW_CONFIG_PATH
  • 고유한 OPENCLAW_STATE_DIR
  • 고유한 agents.defaults.workspace
  • 별도 WhatsApp 번호 (WA 사용 시)

프로필별 서비스 설치:

openclaw --profile main gateway install
openclaw --profile rescue gateway install

예시:

OPENCLAW_CONFIG_PATH=~/.openclaw/a.json OPENCLAW_STATE_DIR=~/.openclaw-a openclaw gateway --port 19001
OPENCLAW_CONFIG_PATH=~/.openclaw/b.json OPENCLAW_STATE_DIR=~/.openclaw-b openclaw gateway --port 19002

프로토콜 (운영자 관점)

  • 전체 문서: Gateway protocolBridge protocol (legacy).
  • 클라이언트의 필수 첫 번째 프레임: req {type:"req", id, method:"connect", params:{minProtocol,maxProtocol,client:{id,displayName?,version,platform,deviceFamily?,modelIdentifier?,mode,instanceId?}, caps, auth?, locale?, userAgent? } }.
  • Gateway 응답 res {type:"res", id, ok:true, payload:hello-ok } (또는 오류와 함께 ok:false, 그런 다음 닫기).
  • 핸드셰이크 후:
    • 요청: {type:"req", id, method, params}{type:"res", id, ok, payload|error}
    • 이벤트: {type:"event", event, payload, seq?, stateVersion?}
  • 구조화된 presence 항목: {host, ip, version, platform?, deviceFamily?, modelIdentifier?, mode, lastInputSeconds?, ts, reason?, tags?[], instanceId? } (WS 클라이언트의 경우 instanceIdconnect.client.instanceId에서 가져옴).
  • agent 응답은 두 단계: 첫 번째 res ack {runId,status:"accepted"}, 그런 다음 실행이 완료된 후 최종 res {runId,status:"ok"|"error",summary}; streaming된 출력은 event:"agent"로 도착합니다.

메소드 (초기 세트)

  • health — 전체 health 스냅샷 (openclaw health --json과 동일한 형태).
  • status — 짧은 요약.
  • system-presence — 현재 presence 목록.
  • system-event — presence/system 노트 게시 (구조화됨).
  • send — 활성 channel을 통해 메시지 전송.
  • agent — agent 턴 실행 (동일한 연결에서 이벤트를 stream 백).
  • node.list — 페어링된 + 현재 연결된 node 나열 (caps, deviceFamily, modelIdentifier, paired, connected 및 알려진 commands 포함).
  • node.describe — node 설명 (기능 + 지원되는 node.invoke 명령; 페어링된 node 및 현재 연결된 페어링되지 않은 node에 대해 작동).
  • node.invoke — node에서 명령 호출 (예: canvas.*, camera.*).
  • node.pair.* — 페어링 수명 주기 (request, list, approve, reject, verify).

참조: Presence - presence가 생성/중복 제거되는 방식 및 안정적인 client.instanceId가 중요한 이유.

이벤트

  • agent — agent 실행의 streaming된 tool/output 이벤트 (seq-tagged).
  • presence — 모든 연결된 클라이언트에 푸시된 presence 업데이트 (stateVersion이 있는 델타).
  • tick — 활성 상태를 확인하기 위한 주기적 keepalive/no-op.
  • shutdown — Gateway가 종료 중입니다. Payload에는 reason 및 선택적 restartExpectedMs가 포함됩니다. 클라이언트는 재연결해야 합니다.

WebChat 통합

  • WebChat은 기록, 전송, 중단 및 이벤트에 대해 Gateway WebSocket과 직접 대화하는 네이티브 SwiftUI UI입니다.
  • 원격 사용은 동일한 SSH/Tailscale 터널을 통과합니다. Gateway 토큰이 구성된 경우 클라이언트는 connect 중에 토큰을 포함합니다.
  • macOS 앱은 단일 WS(공유 연결)를 통해 연결됩니다. 초기 스냅샷에서 presence를 수화하고 presence 이벤트를 수신하여 UI를 업데이트합니다.

타이핑 및 검증

  • 서버는 프로토콜 정의에서 emit된 JSON Schema에 대해 AJV로 모든 인바운드 프레임을 검증합니다.
  • 클라이언트(TS/Swift)는 생성된 타입을 사용합니다(TS 직접; Swift는 repo의 생성기를 통해).
  • 프로토콜 정의는 진실의 원천입니다. 다음을 통해 스키마/모델을 재생성하세요:
    • pnpm protocol:gen
    • pnpm protocol:gen:swift

연결 스냅샷

  • hello-ok에는 presence, health, stateVersionuptimeMs가 있는 snapshotpolicy {maxPayload,maxBufferedBytes,tickIntervalMs}가 포함되어 클라이언트가 추가 요청 없이 즉시 렌더링할 수 있습니다.
  • health/system-presence는 수동 새로 고침을 위해 계속 사용할 수 있지만 연결 시간에는 필요하지 않습니다.

오류 코드 (res.error 형태)

  • 오류는 { code, message, details?, retryable?, retryAfterMs? }를 사용합니다.
  • 표준 코드:
    • NOT_LINKED — WhatsApp이 인증되지 않음.
    • AGENT_TIMEOUT — agent가 구성된 기한 내에 응답하지 않음.
    • INVALID_REQUEST — 스키마/param 검증 실패.
    • UNAVAILABLE — Gateway가 종료 중이거나 종속성을 사용할 수 없음.

Keepalive 동작

  • tick 이벤트(또는 WS ping/pong)는 주기적으로 emit되어 트래픽이 없을 때도 클라이언트가 Gateway가 살아있음을 알 수 있습니다.
  • Send/agent 승인은 별도 응답으로 유지됩니다. Tick을 send에 오버로드하지 마세요.

재생 / 간격

  • 이벤트는 재생되지 않습니다. 클라이언트는 seq 간격을 감지하고 계속하기 전에 새로 고침(health + system-presence)해야 합니다. WebChat 및 macOS 클라이언트는 이제 간격에서 자동 새로 고침합니다.

Supervision (macOS 예시)

  • launchd를 사용하여 서비스를 살아있게 유지하세요:
    • Program: openclaw 경로
    • Arguments: gateway
    • KeepAlive: true
    • StandardOut/Err: 파일 경로 또는 syslog
  • 실패 시 launchd가 재시작합니다. 치명적인 잘못된 config는 운영자가 알아차릴 수 있도록 계속 종료되어야 합니다.
  • LaunchAgent는 사용자별이며 로그인된 세션이 필요합니다. headless 설정의 경우 custom LaunchDaemon을 사용하세요(제공되지 않음).
    • openclaw gateway install~/Library/LaunchAgents/bot.molt.gateway.plist를 작성합니다 (또는 bot.molt.<profile>.plist; 레거시 com.openclaw.*는 정리됨).
    • openclaw doctor는 LaunchAgent config를 감사하고 현재 기본값으로 업데이트할 수 있습니다.

Gateway 서비스 관리 (CLI)

Gateway CLI를 사용하여 install/start/stop/restart/status:

openclaw gateway status
openclaw gateway install
openclaw gateway stop
openclaw gateway restart
openclaw logs --follow

참고:

  • gateway status는 기본적으로 서비스의 해석된 포트/config를 사용하여 Gateway RPC를 프로브합니다(--url로 재정의).
  • gateway status --deep은 시스템 수준 스캔(LaunchDaemon/system unit)을 추가합니다.
  • gateway status --no-probe는 RPC 프로브를 건너뜁니다(네트워킹이 다운된 경우 유용).
  • gateway status --json은 스크립트에 안정적입니다.
  • gateway statussupervisor 런타임(launchd/systemd 실행)을 RPC 도달 가능성(WS 연결 + status RPC)과 별도로 보고합니다.
  • gateway status는 "localhost vs LAN 바인드" 혼란 및 프로필 불일치를 방지하기 위해 config 경로 + 프로브 대상을 출력합니다.
  • gateway status는 서비스가 실행 중으로 보이지만 포트가 닫혀 있을 때 마지막 gateway 오류 라인을 포함합니다.
  • logs는 RPC를 통해 Gateway 파일 로그를 테일합니다(수동 tail/grep 불필요).
  • 다른 gateway 유사 서비스가 감지되면 OpenClaw 프로필 서비스가 아닌 한 CLI가 경고합니다. 대부분의 설정에서는 여전히 머신당 하나의 gateway를 권장합니다. 중복성 또는 rescue bot을 위해 격리된 프로필/포트를 사용하세요. Multiple gateways를 참조하세요.
    • 정리: openclaw gateway uninstall (현재 서비스) 및 openclaw doctor (레거시 마이그레이션).
  • gateway install은 이미 설치된 경우 no-op입니다. openclaw gateway install --force를 사용하여 재설치하세요(프로필/env/path 변경).

번들된 mac 앱:

  • OpenClaw.app은 Node 기반 gateway relay를 번들하고 bot.molt.gateway(또는 bot.molt.<profile>; 레거시 com.openclaw.* 레이블은 여전히 깨끗하게 언로드됨)로 레이블이 지정된 사용자별 LaunchAgent를 설치할 수 있습니다.
  • 깨끗하게 중지하려면 openclaw gateway stop(또는 launchctl bootout gui/$UID/bot.molt.gateway)을 사용하세요.
  • 재시작하려면 openclaw gateway restart(또는 launchctl kickstart -k gui/$UID/bot.molt.gateway)를 사용하세요.
    • launchctl은 LaunchAgent가 설치된 경우에만 작동합니다. 그렇지 않으면 먼저 openclaw gateway install을 사용하세요.
    • 명명된 프로필을 실행할 때 레이블을 bot.molt.<profile>로 교체하세요.

Supervision (systemd user unit)

OpenClaw는 Linux/WSL2에서 기본적으로 systemd user service를 설치합니다. 단일 사용자 머신에는 user 서비스를 권장합니다(더 간단한 env, 사용자별 config). 다중 사용자 또는 항상 실행 중인 서버에는 system service를 사용하세요(lingering 불필요, 공유 supervision).

openclaw gateway install은 user unit을 작성합니다. openclaw doctor는 unit을 감사하고 현재 권장 기본값과 일치하도록 업데이트할 수 있습니다.

~/.config/systemd/user/openclaw-gateway[-<profile>].service를 생성하세요:

[Unit]
Description=OpenClaw Gateway (profile: <profile>, v<version>)
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=/usr/local/bin/openclaw gateway --port 18789
Restart=always
RestartSec=5
Environment=OPENCLAW_GATEWAY_TOKEN=
WorkingDirectory=/home/youruser

[Install]
WantedBy=default.target

Lingering 활성화 (user 서비스가 로그아웃/idle에서 생존하도록 필요):

sudo loginctl enable-linger youruser

Onboarding은 Linux/WSL2에서 이것을 실행합니다(sudo를 요청할 수 있음; /var/lib/systemd/linger를 작성). 그런 다음 서비스를 활성화하세요:

systemctl --user enable --now openclaw-gateway[-<profile>].service

대안 (system service) - 항상 실행 중이거나 다중 사용자 서버의 경우 user unit 대신 systemd system unit을 설치할 수 있습니다(lingering 불필요). /etc/systemd/system/openclaw-gateway[-<profile>].service를 생성하세요(위의 unit을 복사하고 WantedBy=multi-user.target로 전환하고 User= + WorkingDirectory=를 설정한 다음):

sudo systemctl daemon-reload
sudo systemctl enable --now openclaw-gateway[-<profile>].service

Windows (WSL2)

Windows 설치는 WSL2를 사용하고 위의 Linux systemd 섹션을 따라야 합니다.

운영 체크

  • 활성: WS를 열고 req:connectpayload.type="hello-ok"(스냅샷 포함)가 있는 res를 예상합니다.
  • 준비: health 호출 → ok: truelinkChannel에 연결된 channel(해당하는 경우)을 예상합니다.
  • Debug: tickpresence 이벤트를 구독합니다. status가 연결/인증 age를 표시하는지 확인합니다. Presence 항목은 Gateway 호스트 및 연결된 클라이언트를 표시합니다.

안전 보장

  • 기본적으로 호스트당 하나의 Gateway를 가정합니다. 여러 프로필을 실행하는 경우 포트/state를 격리하고 올바른 인스턴스를 대상으로 지정하세요.
  • 직접 Baileys 연결로의 폴백 없음; Gateway가 다운된 경우 전송이 빠르게 실패합니다.
  • 비connect 첫 번째 프레임 또는 잘못된 JSON이 거부되고 socket이 닫힙니다.
  • 우아한 종료: 닫기 전에 shutdown 이벤트를 emit합니다. 클라이언트는 닫기 + 재연결을 처리해야 합니다.

CLI helper

  • openclaw gateway health|status — Gateway WS를 통해 health/status 요청.
  • openclaw message send --target <num> --message "hi" [--media ...] — Gateway를 통해 전송(WhatsApp에 대해 멱등성).
  • openclaw agent --message "hi" --to <num> — agent 턴 실행(기본적으로 final을 기다림).
  • openclaw gateway call <method> --params '{"k":"v"}' — 디버깅을 위한 원시 메소드 invoker.
  • openclaw gateway stop|restart — supervised gateway 서비스 중지/재시작(launchd/systemd).
  • Gateway helper 하위 명령은 --url에서 실행 중인 gateway를 가정합니다. 더 이상 자동으로 생성하지 않습니다.

마이그레이션 지침

  • openclaw gateway 및 레거시 TCP 제어 포트 사용을 폐기하세요.
  • 필수 연결 및 구조화된 presence로 WS 프로토콜을 사용하도록 클라이언트를 업데이트하세요.