Control UI (브라우저)
Control UI는 Gateway가 제공하는 작은 Vite + Lit 단일 페이지 앱입니다.- 기본값:
http://<host>:18789/ - 선택적 접두사:
gateway.controlUi.basePath설정(예:/openclaw)
빠르게 열기(로컬)
Gateway가 같은 컴퓨터에서 실행 중이라면 다음 주소를 엽니다. 페이지가 열리지 않으면 먼저 Gateway를 시작하세요:openclaw gateway.
인증 정보는 WebSocket 핸드셰이크 중 다음 필드를 통해 전달됩니다.
connect.params.auth.tokenconnect.params.auth.password대시보드 설정 패널은 현재 브라우저 탭 세션과 선택한 gateway URL에 대한 token만 유지하며, password는 저장하지 않습니다. 온보딩 마법사는 기본적으로 gateway token을 생성하므로, 처음 연결할 때 여기에 붙여 넣으면 됩니다.
기기 페어링(첫 연결)
새 브라우저나 기기에서 Control UI에 연결하면 Gateway는 일회성 페어링 승인을 요구합니다. 같은 Tailnet에서gateway.auth.allowTailscale: true를 사용하더라도 마찬가지입니다. 이는 무단 접근을 막기 위한 보안 조치입니다.
표시되는 메시지: “disconnected (1008): pairing required”
기기 승인 방법:
openclaw devices revoke --device <id> --role <role>로 취소하지 않는 한 다시 승인할 필요가 없습니다. token 회전과 취소는 Devices 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) - Chat에서 도구 호출과 실시간 도구 출력 카드 스트리밍(에이전트 이벤트)
- 채널: WhatsApp/Telegram/Discord/Slack + 플러그인 채널(Mattermost 등) 상태, QR 로그인, 채널별 설정(
channels.status,web.login.*,config.patch) - 인스턴스: presence 목록 + 새로고침(
system-presence) - 세션: 목록 + 세션별 thinking/verbose 재정의(
sessions.list,sessions.patch) - 크론 작업: 목록/추가/수정/실행/활성화/비활성화 + 실행 이력(
cron.*) - 스킬: 상태, 활성화/비활성화, 설치, API 키 업데이트(
skills.*) - 노드: 목록 + caps(
node.list) - exec 승인: gateway 또는 node 허용 목록 편집 +
exec host=gateway/node의 ask 정책(exec.approvals.*) - 설정:
~/.openclaw/openclaw.json조회/편집(config.get,config.set) - 설정: 검증 후 적용 + 재시작(
config.apply) 및 마지막 활성 세션 깨우기 - 설정 저장에는 동시 편집 덮어쓰기를 막기 위한 base-hash 가드가 포함됩니다
- 설정 스키마 + 폼 렌더링(
config.schema, 플러그인 + 채널 스키마 포함), Raw JSON 편집기 유지 - 디버그: status/health/models 스냅샷 + 이벤트 로그 + 수동 RPC 호출(
status,health,models.list) - 로그: gateway 파일 로그 실시간 tail + 필터/내보내기(
logs.tail) - 업데이트: 패키지/git 업데이트 + 재시작(
update.run) 및 재시작 보고서
- 격리된 작업의 기본 전달 방식은 announce summary입니다. 내부 전용 실행이 필요하면 none으로 바꿀 수 있습니다.
- announce를 선택하면 channel/target 필드가 나타납니다.
- webhook 모드는
delivery.mode = "webhook"을 사용하며,delivery.to에는 유효한 HTTP(S) webhook URL을 넣어야 합니다. - 메인 세션 작업에서는 webhook 및 none 전달 모드를 사용할 수 있습니다.
- 고급 편집 항목에는 실행 후 삭제, agent override 해제, cron exact/stagger 옵션, agent model/thinking override, best-effort 전달 토글이 포함됩니다.
- 폼 검증은 필드 단위 오류와 함께 인라인으로 처리되며, 값이 잘못되면 저장 버튼이 비활성화됩니다.
- 전용 bearer token을 보내려면
cron.webhookToken을 설정하세요. 생략하면 인증 헤더 없이 webhook을 보냅니다. - 하위 호환용 fallback으로,
notify: true가 저장된 레거시 작업은 마이그레이션 전까지cron.webhook을 계속 사용할 수 있습니다.
채팅 동작
chat.send는 논블로킹입니다. 즉시{ runId, status: "started" }를 반환하고, 응답은chat이벤트로 스트리밍됩니다.- 같은
idempotencyKey로 다시 보내면 실행 중에는{ status: "in_flight" }, 완료 후에는{ status: "ok" }를 반환합니다. chat.history응답은 UI 안전을 위해 크기가 제한됩니다. transcript 항목이 너무 크면 Gateway는 긴 텍스트 필드를 잘라내거나, 무거운 메타데이터 블록을 생략하거나, 지나치게 큰 메시지를 자리표시자([chat.history omitted: message too large])로 대체할 수 있습니다.chat.inject는 세션 transcript에 어시스턴트 메모를 추가하고, UI 전용 업데이트를 위해chat이벤트를 브로드캐스트합니다(에이전트 실행 없음, 채널 전달 없음).- 중지:
- Stop 클릭(
chat.abort호출) /stop입력(또는stop,stop action,stop run,stop openclaw,please stop같은 단독 중단 문구)으로 out-of-band 중단chat.abort는{ sessionKey }(runId없음)를 지원하므로 해당 세션의 모든 활성 실행을 중단할 수 있습니다
- Stop 클릭(
- 중단 시 부분 출력 보존:
- 실행이 중단되더라도 어시스턴트의 부분 출력은 UI에 계속 표시될 수 있습니다
- 버퍼된 출력이 있으면 Gateway는 중단된 어시스턴트 부분 출력을 transcript history에 저장합니다
- 저장된 항목에는 abort metadata가 포함되어 일반 완료 출력과 구분할 수 있습니다
Tailnet 접근(권장)
통합 Tailscale Serve(권장)
Gateway는 loopback에만 두고, Tailscale Serve가 HTTPS로 프록시하도록 둡니다.https://<magicdns>/(또는 설정한gateway.controlUi.basePath)
gateway.auth.allowTailscale이 true이면, Control UI/WebSocket Serve 요청은 Tailscale identity headers(tailscale-user-login)로 인증할 수 있습니다. OpenClaw는 tailscale whois로 x-forwarded-for 주소를 해석해 헤더와 일치하는지 검증하고, 요청이 loopback으로 들어오면서 Tailscale의 x-forwarded-* 헤더가 있을 때만 이를 허용합니다. Serve 트래픽에도 token/password를 요구하려면 gateway.auth.allowTailscale: false로 설정하거나 gateway.auth.mode: "password"를 강제하세요.
token 없는 Serve 인증은 gateway host가 신뢰된다는 전제를 둡니다. 해당 호스트에서 신뢰할 수 없는 로컬 코드가 실행될 수 있다면 token/password 인증을 요구하세요.
tailnet 바인드 + token
http://<tailscale-ip>:18789/(또는 설정한gateway.controlUi.basePath)
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 host에서)
allowInsecureAuth는 로컬 호환성을 위한 토글일 뿐입니다.
- 비보안 HTTP 컨텍스트에서 localhost Control UI 세션이 기기 식별 없이 진행되도록 허용합니다.
- pairing 검사를 우회하지 않습니다.
- 원격(non-localhost) 기기 식별 요구사항을 완화하지 않습니다.
dangerouslyDisableDeviceAuth는 Control UI 기기 식별 검사를 비활성화하며, 심각한 보안 약화를 의미합니다. 긴급 상황이 끝나면 빠르게 원복하세요.
HTTPS 설정 가이드는 Tailscale를 참고하세요.
UI 빌드
Gateway는dist/control-ui에서 정적 파일을 제공합니다. 다음 명령으로 빌드합니다.
ws://127.0.0.1:18789)을 지정하세요.
디버깅/테스트: 개발 서버 + 원격 Gateway
Control UI는 정적 파일이며 WebSocket 대상은 설정 가능하므로 HTTP origin과 달라도 됩니다. 로컬에서 Vite 개발 서버를 띄우고 Gateway는 다른 곳에서 실행할 때 특히 유용합니다.- UI 개발 서버 시작:
pnpm ui:dev - 다음과 같은 URL 열기:
gatewayUrl은 로드 후 localStorage에 저장되며 URL에서는 제거됩니다.token은 URL fragment에서 가져와 현재 브라우저 탭 세션과 선택한 gateway URL용 sessionStorage에 저장되고, URL에서는 제거됩니다. localStorage에는 저장되지 않습니다.password는 메모리에만 유지됩니다.gatewayUrl이 설정되면 UI는 config나 환경 자격 증명으로 대체하지 않습니다.token(또는password)을 명시적으로 제공해야 하며, 없으면 오류입니다.- Gateway가 TLS 뒤에 있다면
wss://를 사용하세요(Tailscale Serve, HTTPS proxy 등). gatewayUrl은 클릭재킹 방지를 위해 최상위 창에서만 허용됩니다(임베드 환경 제외).- 비-loopback Control UI 배포에서는
gateway.controlUi.allowedOrigins를 명시적으로 설정해야 합니다(완전한 origin 값). 여기에는 원격 개발 설정도 포함됩니다. gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true는 Host-header origin fallback 모드를 켜지만, 위험한 보안 모드입니다.