Control UI (브라우저)

Control UI는 Gateway가 제공하는 소형 Vite + Lit 싱글 페이지 앱입니다:

  • 기본값: http://<host>:18789/
  • 선택적 접두사: gateway.controlUi.basePath 설정 (예: /openclaw)

동일한 포트의 Gateway WebSocket에 직접 통신합니다.

빠른 열기 (로컬)

Gateway가 같은 컴퓨터에서 실행 중이면:

페이지 로드에 실패하면 먼저 Gateway를 시작하세요: openclaw gateway.

인증은 WebSocket 핸드셰이크 시 다음을 통해 제공됩니다:

  • connect.params.auth.token
  • connect.params.auth.password 대시보드 설정 패널은 현재 브라우저 탭 세션 및 선택된 게이트웨이 URL에 대한 토큰을 유지합니다. 비밀번호는 저장되지 않습니다. 온보딩 마법사가 기본적으로 게이트웨이 토큰을 생성하므로, 첫 연결 시 여기에 붙여넣으세요.

디바이스 페어링 (첫 연결)

새 브라우저나 디바이스에서 Control UI에 연결할 때, 같은 Tailnet에서 gateway.auth.allowTailscale: true인 경우에도 Gateway는 일회성 페어링 승인을 요구합니다. 이는 무단 접근을 방지하기 위한 보안 조치입니다.

표시 내용: “disconnected (1008): pairing required”

디바이스 승인 방법:

# 대기 중인 요청 목록
openclaw devices list

# 요청 ID로 승인
openclaw devices approve <requestId>

승인되면, 해당 디바이스는 기억되며 openclaw devices revoke --device <id> --role <role>로 취소하지 않는 한 재승인이 필요하지 않습니다. 디바이스 CLI에서 토큰 교체 및 취소를 확인하세요.

참고:

  • 로컬 연결 (127.0.0.1)은 자동 승인됩니다.
  • 원격 연결 (LAN, Tailnet 등)은 명시적 승인이 필요합니다.
  • 각 브라우저 프로필은 고유한 디바이스 ID를 생성하므로, 브라우저를 변경하거나 브라우저 데이터를 삭제하면 재페어링이 필요합니다.

언어 지원

Control UI는 첫 로드 시 브라우저 로캘에 따라 자동으로 언어를 설정할 수 있으며, 이후 Access 카드의 언어 선택기에서 변경할 수 있습니다.

  • 지원 로캘: en, zh-CN, zh-TW, pt-BR, de, es
  • 영어 외 번역은 브라우저에서 지연 로드됩니다.
  • 선택된 로캘은 브라우저 저장소에 저장되어 다음 방문 시 재사용됩니다.
  • 누락된 번역 키는 영어로 폴백합니다.

현재 지원 기능

  • Gateway WS를 통한 모델과의 채팅 (chat.history, chat.send, chat.abort, chat.inject)
  • 채팅에서의 도구 호출 스트리밍 + 실시간 도구 출력 카드 (에이전트 이벤트)
  • 채널: WhatsApp/Telegram/Discord/Slack + 플러그인 채널 (Mattermost 등) 상태 + QR 로그인 + 채널별 설정 (channels.status, web.login.*, config.patch)
  • 인스턴스: 현재 상태 목록 + 새로고침 (system-presence)
  • 세션: 목록 + 세션별 thinking/fast/verbose/reasoning 재정의 (sessions.list, sessions.patch)
  • 크론 작업: 목록/추가/편집/실행/활성화/비활성화 + 실행 이력 (cron.*)
  • 스킬: 상태, 활성화/비활성화, 설치, API 키 업데이트 (skills.*)
  • 노드: 목록 + 기능 (node.list)
  • 실행 승인: 게이트웨이 또는 노드 허용 목록 편집 + exec host=gateway/node에 대한 ask 정책 (exec.approvals.*)
  • 설정: ~/.openclaw/openclaw.json 보기/편집 (config.get, config.set)
  • 설정: 검증과 함께 적용 + 재시작 (config.apply) 및 마지막 활성 세션 깨우기
  • 설정 쓰기에는 동시 편집 덮어쓰기를 방지하는 base-hash 가드가 포함됨
  • 설정 스키마 + 폼 렌더링 (config.schema, 플러그인 + 채널 스키마 포함); Raw JSON 편집기도 사용 가능
  • 디버그: 상태/헬스/모델 스냅샷 + 이벤트 로그 + 수동 RPC 호출 (status, health, models.list)
  • 로그: 필터/내보내기가 있는 게이트웨이 파일 로그 실시간 추적 (logs.tail)
  • 업데이트: 패키지/git 업데이트 실행 + 재시작 (update.run) 및 재시작 보고서

크론 작업 패널 참고:

  • 격리된 작업의 경우 전달 기본값은 요약 알림입니다. 내부 전용 실행을 원하면 none으로 전환할 수 있습니다.
  • 알림이 선택되면 채널/대상 필드가 나타납니다.
  • 웹훅 모드는 delivery.mode = "webhook"과 유효한 HTTP(S) 웹훅 URL로 설정된 delivery.to를 사용합니다.
  • 메인 세션 작업에는 웹훅 및 none 전달 모드를 사용할 수 있습니다.
  • 고급 편집 컨트롤에는 실행 후 삭제, 에이전트 재정의 해제, cron 정확/분산 옵션, 에이전트 모델/thinking 재정의, best-effort 전달 토글이 포함됩니다.
  • 폼 검증은 필드별 오류가 인라인으로 표시됩니다. 유효하지 않은 값이 있으면 저장 버튼이 비활성화됩니다.
  • cron.webhookToken을 설정하여 전용 베어러 토큰을 전송할 수 있습니다. 생략 시 인증 헤더 없이 웹훅이 전송됩니다.
  • 폐기 예정 폴백: notify: true가 저장된 레거시 작업은 마이그레이션될 때까지 cron.webhook을 사용할 수 있습니다.

채팅 동작

  • chat.send논블로킹입니다: { runId, status: "started" }로 즉시 확인 응답하고, 응답은 chat 이벤트를 통해 스트리밍됩니다.
  • 같은 idempotencyKey로 재전송하면 실행 중일 때 { status: "in_flight" }를, 완료 후 { status: "ok" }를 반환합니다.
  • chat.history 응답은 UI 안전을 위해 크기가 제한됩니다. 트랜스크립트 항목이 너무 크면, Gateway가 긴 텍스트 필드를 잘라내거나, 무거운 메타데이터 블록을 생략하거나, 초과 크기 메시지를 플레이스홀더([chat.history omitted: message too large])로 대체할 수 있습니다.
  • chat.inject는 세션 트랜스크립트에 어시스턴트 노트를 추가하고 UI 전용 업데이트를 위해 chat 이벤트를 브로드캐스트합니다 (에이전트 실행 없음, 채널 전달 없음).
  • 중지:
    • 중지 클릭 (chat.abort 호출)
    • /stop 입력 (또는 stop, stop action, stop run, stop openclaw, please stop과 같은 독립적인 중단 구문)하여 대역 외 중단
    • chat.abort는 해당 세션의 모든 활성 실행을 중단하기 위해 { sessionKey }를 지원합니다 (runId 불필요)
  • 중단 부분 유지:
    • 실행이 중단되면 부분적인 어시스턴트 텍스트가 UI에 계속 표시될 수 있습니다
    • Gateway는 버퍼링된 출력이 있을 때 중단된 부분 어시스턴트 텍스트를 트랜스크립트 이력에 유지합니다
    • 유지된 항목에는 트랜스크립트 소비자가 중단 부분과 정상 완료 출력을 구별할 수 있도록 중단 메타데이터가 포함됩니다

Tailnet 접근 (권장)

통합 Tailscale Serve (선호)

Gateway를 루프백에 유지하고 Tailscale Serve가 HTTPS로 프록시하도록 합니다:

openclaw gateway --tailscale serve

열기:

  • https://<magicdns>/ (또는 설정된 gateway.controlUi.basePath)

기본적으로 Control UI/WebSocket Serve 요청은 gateway.auth.allowTailscaletrue일 때 Tailscale 신원 헤더(tailscale-user-login)를 통해 인증할 수 있습니다. OpenClaw는 x-forwarded-for 주소를 tailscale whois로 확인하고 헤더와 매칭하여 신원을 검증하며, 요청이 Tailscale의 x-forwarded-* 헤더와 함께 루프백에 도착할 때만 이를 수락합니다. Serve 트래픽에도 토큰/비밀번호를 요구하려면 gateway.auth.allowTailscale: false (또는 gateway.auth.mode: "password" 강제)를 설정하세요. 토큰리스 Serve 인증은 게이트웨이 호스트가 신뢰할 수 있다고 가정합니다. 신뢰할 수 없는 로컬 코드가 해당 호스트에서 실행될 수 있으면, 토큰/비밀번호 인증을 요구하세요.

Tailnet 바인딩 + 토큰

openclaw gateway --bind tailnet --token "$(openssl rand -hex 32)"

그런 다음:

  • http://<tailscale-ip>:18789/ (또는 설정된 gateway.controlUi.basePath)

UI 설정에 토큰을 붙여넣으세요 (connect.params.auth.token으로 전송됨).

비보안 HTTP

대시보드를 일반 HTTP (http://<lan-ip> 또는 http://<tailscale-ip>)로 열면, 브라우저가 비보안 컨텍스트에서 실행되어 WebCrypto를 차단합니다. 기본적으로 OpenClaw는 디바이스 신원 없이 Control UI 연결을 차단합니다.

권장 해결 방법: HTTPS(Tailscale Serve) 사용 또는 UI를 로컬에서 열기:

  • https://<magicdns>/ (Serve)
  • http://127.0.0.1:18789/ (게이트웨이 호스트에서)

비보안 인증 토글 동작:

{
  gateway: {
    controlUi: { allowInsecureAuth: true },
    bind: "tailnet",
    auth: { mode: "token", token: "replace-me" },
  },
}

allowInsecureAuth는 로컬 호환성 토글일 뿐입니다:

  • 비보안 HTTP 컨텍스트에서 localhost Control UI 세션이 디바이스 신원 없이 진행되도록 허용합니다.
  • 페어링 검사를 우회하지 않습니다.
  • 원격(비localhost) 디바이스 신원 요구사항을 완화하지 않습니다.

긴급 사용 전용:

{
  gateway: {
    controlUi: { dangerouslyDisableDeviceAuth: true },
    bind: "tailnet",
    auth: { mode: "token", token: "replace-me" },
  },
}

dangerouslyDisableDeviceAuth는 Control UI 디바이스 신원 검사를 비활성화하며 심각한 보안 저하입니다. 긴급 사용 후 빠르게 원복하세요.

Tailscale에서 HTTPS 설정 가이드를 확인하세요.

UI 빌드

Gateway는 dist/control-ui의 정적 파일을 제공합니다. 다음으로 빌드하세요:

pnpm ui:build # 첫 실행 시 UI 의존성 자동 설치

선택적 절대 경로 (고정 에셋 URL이 필요한 경우):

OPENCLAW_CONTROL_UI_BASE_PATH=/openclaw/ pnpm ui:build

로컬 개발 (별도 개발 서버):

pnpm ui:dev # 첫 실행 시 UI 의존성 자동 설치

그런 다음 UI에서 Gateway WS URL을 지정하세요 (예: ws://127.0.0.1:18789).

디버깅/테스트: 개발 서버 + 원격 Gateway

Control UI는 정적 파일이며, WebSocket 대상은 설정 가능하고 HTTP 오리진과 다를 수 있습니다. 로컬에서 Vite 개발 서버를 실행하면서 Gateway가 다른 곳에서 실행될 때 유용합니다.

  1. UI 개발 서버 시작: pnpm ui:dev
  2. 다음과 같은 URL 열기:
http://localhost:5173/?gatewayUrl=ws://<gateway-host>:18789

선택적 일회성 인증 (필요한 경우):

http://localhost:5173/?gatewayUrl=wss://<gateway-host>:18789#token=<gateway-token>

참고:

  • gatewayUrl은 로드 후 localStorage에 저장되고 URL에서 제거됩니다.
  • token은 URL 프래그먼트에서 가져와 현재 브라우저 탭 세션 및 선택된 게이트웨이 URL에 대해 sessionStorage에 저장되고 URL에서 제거됩니다. localStorage에는 저장되지 않습니다.
  • password는 메모리에만 유지됩니다.
  • gatewayUrl이 설정되면, UI는 설정이나 환경 자격 증명으로 폴백하지 않습니다. token (또는 password)을 명시적으로 제공하세요. 명시적 자격 증명 누락은 오류입니다.
  • Gateway가 TLS 뒤에 있을 때 (Tailscale Serve, HTTPS 프록시 등) wss://를 사용하세요.
  • gatewayUrl은 클릭재킹 방지를 위해 최상위 창에서만 허용됩니다 (임베디드 불가).
  • 비루프백 Control UI 배포는 gateway.controlUi.allowedOrigins를 명시적으로 설정해야 합니다 (전체 오리진). 원격 개발 설정도 포함됩니다.
  • gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true는 Host 헤더 오리진 폴백 모드를 활성화하지만, 위험한 보안 모드입니다.

예시:

{
  gateway: {
    controlUi: {
      allowedOrigins: ["http://localhost:5173"],
    },
  },
}

원격 접근 설정 세부사항: 원격 접근.