게이트웨이 아키텍처
최종 수정: 2026-01-22
개요
- 하나의 장기 실행 게이트웨이가 모든 메시징 채널(Baileys 기반 WhatsApp, grammY 기반 Telegram, Slack, Discord, Signal, iMessage, WebChat)을 관리합니다.
- 컨트롤 플레인 클라이언트(macOS 앱, CLI, 웹 UI, 자동화)는 설정된 바인드 호스트(기본값
127.0.0.1:18789)의 WebSocket으로 게이트웨이에 연결됩니다. - 노드(macOS/iOS/Android/헤드리스)도 WebSocket으로 연결되지만, 명시적 기능/명령어와 함께
role: node를 선언합니다. - 호스트당 하나의 게이트웨이. WhatsApp 세션을 여는 유일한 곳입니다.
- 캔버스 호스트는 게이트웨이 HTTP 서버가 다음 경로로 제공합니다:
/__openclaw__/canvas/(에이전트가 편집 가능한 HTML/CSS/JS)/__openclaw__/a2ui/(A2UI 호스트) 게이트웨이와 동일한 포트를 사용합니다 (기본값18789).
구성요소와 흐름
게이트웨이 (데몬)
- 프로바이더 연결을 유지합니다.
- 타입이 지정된 WS API를 노출합니다 (요청, 응답, 서버 푸시 이벤트).
- 인바운드 프레임을 JSON Schema로 검증합니다.
agent,chat,presence,health,heartbeat,cron등의 이벤트를 발생시킵니다.
클라이언트 (mac 앱 / CLI / 웹 관리자)
- 클라이언트당 하나의 WS 연결.
- 요청 전송 (
health,status,send,agent,system-presence). - 이벤트 구독 (
tick,agent,presence,shutdown).
노드 (macOS / iOS / Android / 헤드리스)
role: node로 동일한 WS 서버에 연결됩니다.connect시 디바이스 ID를 제공합니다. 페어링은 디바이스 기반(rolenode)이며, 승인은 디바이스 페어링 스토어에 저장됩니다.canvas.*,camera.*,screen.record,location.get등의 명령어를 노출합니다.
프로토콜 세부사항:
WebChat
- 게이트웨이 WS API를 사용하여 채팅 기록과 전송을 처리하는 정적 UI.
- 원격 환경에서는 다른 클라이언트와 동일한 SSH/Tailscale 터널을 통해 연결됩니다.
연결 생명주기 (단일 클라이언트)
sequenceDiagram
participant Client
participant Gateway
Client->>Gateway: req:connect
Gateway-->>Client: res (ok)
Note right of Gateway: or res error + close
Note left of Client: payload=hello-ok<br>snapshot: presence + health
Gateway-->>Client: event:presence
Gateway-->>Client: event:tick
Client->>Gateway: req:agent
Gateway-->>Client: res:agent<br>ack {runId, status:"accepted"}
Gateway-->>Client: event:agent<br>(streaming)
Gateway-->>Client: res:agent<br>final {runId, status, summary}
와이어 프로토콜 (요약)
- 전송: WebSocket, JSON 페이로드가 담긴 텍스트 프레임.
- 첫 번째 프레임은 반드시
connect여야 합니다. - 핸드셰이크 이후:
- 요청:
{type:"req", id, method, params}→{type:"res", id, ok, payload|error} - 이벤트:
{type:"event", event, payload, seq?, stateVersion?}
- 요청:
OPENCLAW_GATEWAY_TOKEN(또는--token)이 설정된 경우,connect.params.auth.token이 일치해야 하며 그렇지 않으면 소켓이 닫힙니다.- 부작용이 있는 메서드(
send,agent)에는 안전한 재시도를 위해 멱등성 키가 필요합니다. 서버는 짧은 수명의 중복 제거 캐시를 유지합니다. - 노드는
connect시role: "node"와 함께 기능/명령어/권한을 포함해야 합니다.
페어링 + 로컬 신뢰
- 모든 WS 클라이언트(운영자 + 노드)는
connect시 디바이스 ID를 포함합니다. - 새 디바이스 ID는 페어링 승인이 필요하며, 게이트웨이가 이후 연결을 위한 디바이스 토큰을 발급합니다.
- 로컬 연결(루프백 또는 게이트웨이 호스트 자체의 tailnet 주소)은 동일 호스트 UX를 원활하게 하기 위해 자동 승인될 수 있습니다.
- 모든 연결은
connect.challenge논스에 서명해야 합니다. - 서명 페이로드
v3는platform+deviceFamily도 바인딩합니다. 게이트웨이는 재연결 시 페어링된 메타데이터를 고정하며, 메타데이터 변경 시 재페어링을 요구합니다. - 비로컬 연결은 여전히 명시적 승인이 필요합니다.
- 게이트웨이 인증(
gateway.auth.*)은 로컬이든 원격이든 모든 연결에 적용됩니다.
자세한 내용: 게이트웨이 프로토콜, 페어링, 보안.
프로토콜 타이핑과 코드 생성
- TypeBox 스키마로 프로토콜을 정의합니다.
- JSON Schema가 이 스키마에서 생성됩니다.
- Swift 모델이 JSON Schema에서 생성됩니다.
원격 접속
-
권장: Tailscale 또는 VPN.
-
대안: SSH 터널
ssh -N -L 18789:127.0.0.1:18789 user@host -
터널을 통해서도 동일한 핸드셰이크 + 인증 토큰이 적용됩니다.
-
원격 환경에서 WS에 TLS + 선택적 핀닝을 활성화할 수 있습니다.
운영 스냅샷
- 시작:
openclaw gateway(포그라운드, stdout으로 로깅). - 상태 확인: WS를 통한
health(hello-ok에도 포함). - 감독: launchd/systemd로 자동 재시작.
불변 규칙
- 정확히 하나의 게이트웨이가 호스트당 단일 Baileys 세션을 관리합니다.
- 핸드셰이크는 필수입니다. JSON이 아니거나 connect가 아닌 첫 프레임은 즉시 연결을 종료합니다.
- 이벤트는 재전송되지 않습니다. 클라이언트는 누락된 부분을 새로고침해야 합니다.