아키텍처
전체 흐름
기본값(로컬 tmux + 터널):
코드
Browser (phone)
|
| HTTPS
v
Cloudflare Quick Tunnel
|
| HTTP/WS
v
Local Termbridge server
|
| PTY
v
Tmux session
직접 샌드박스 모드(Daytona, 터널 없음):
코드
Browser (phone)
|
| HTTPS
v
Daytona preview link
|
| HTTP/WS
v
Termbridge server (sandbox)
|
| PTY
v
Tmux session (sandbox)
--no-tunnel이 설정되면 Termbridge은 Cloudflare을 건너뛰고 제공된 공개 URL를 사용합니다.
컴포넌트
CLI 프로세스
- UI 에셋을 제공하는 HTTP 서버를 시작합니다.
- 터미널 I/O용 WebSocket 서버를 시작합니다.
- 하나 이상의 tmux 세션(또는 Daytona PTY)을 생성합니다.
- 일회용 교환 토큰을 발급합니다.
- 터널이 활성화된 경우 터널을 시작하고 모니터링합니다(현재 Cloudflare).
- 직접 샌드박스 모드에서는 샌드박스 안에서 Termbridge을 실행하고 공유 URL을 기다립니다.
터미널 백엔드
- tmux 백엔드: 실제 키 입력과 출력을 위해
node-pty을 사용해 tmux에 연결합니다. - Daytona 백엔드: 샌드박스 안에서 Daytona PTY를 사용합니다.
- 전체 색상 지원을 위해
TERM=xterm-256color및COLORTERM=truecolor을 설정합니다. - tmux의 경우 UI을 깔끔하게 유지하도록 tmux 상태 표시줄을 비활성화합니다.
터미널 레지스트리
- 사용 가능한 터미널 세션을 추적합니다.
- UI에 목록을 제공하고 선택한 터미널 ID를 확인합니다.
인증 및 세션
- 일회용 토큰은 URL으로 출력되고 QR 코드에 인코딩됩니다.
GET /__tb/s/:token가 토큰을 교환하고 쿠키 세션을 설정합니다.- WebSocket 연결에는 유효한 세션 쿠키와 CSRF 토큰이 필요합니다.
- CSRF 토큰은
GET /__tb/api/csrf을 통해 가져와 WebSocket 쿼리 매개변수로 전달됩니다.
프록시 모드
--proxy <port>이 전달되면:
- 모든 termbridge 경로는
/__tb/접두사 아래에 있습니다. /__tb/가 아닌 요청은 대상 앱으로 프록시됩니다.- UI는 뷰 전환기를 통해 터미널/미리보기 뷰를 표시합니다.
- 미리보기 뷰는
/를 가리키는 iframe을 불러옵니다. - HMR용 WebSocket 연결은 대상에 전달됩니다.
보안
- CSRF 보호: 사이트 간 탈취를 방지하기 위해 WebSocket 업그레이드에 CSRF 토큰이 필요합니다.
- 입력 제한: 64KB HTTP 본문, WebSocket 메시지 1MB, 메시지당 터미널 입력 64KB입니다.
- 요청 제한: 토큰 교환과 WebSocket 연결에 IP별 제한을 적용합니다.
API 엔드포인트
프록시된 앱과의 충돌을 피하기 위해 모든 경로는 /__tb/ 접두사 아래에 있습니다:
GET /__tb/healthz- 상태 확인GET /__tb/s/:token- 토큰 교환 → 쿠키 → 리디렉션GET /__tb/api/terminals- 터미널 목록GET /__tb/api/csrf- WebSocket용 CSRF 토큰 가져오기GET /__tb/api/config- 설정 가져오기(proxyPort, devProxyUrl)POST /__tb/api/terminals- 새 tmux 세션 생성GET /__tb/app/*- SPA 대체 경로WS /__tb/ws/terminal/:terminalId?csrf=<token>- 터미널 I/O 스트리밍
프록시 모드가 활성화된 경우:
GET /- 프록시된 앱으로 리디렉션(비활성화된 경우/__tb/app)* /*- 대상 앱으로 프록시됨
WebSocket 프로토콜
클라이언트 -> 서버:
JSON
{ "type": "input", "data": "ls -la" }
{ "type": "resize", "cols": 120, "rows": 32 }
{ "type": "control", "key": "ctrl_c" }
서버 -> 클라이언트:
JSON
{ "type": "output", "data": "..." }
{ "type": "status", "state": "connected" }
UI 스택
- Vite + TanStack Router
- xterm.js + Fit 애드온 + WebGL 렌더러
- 입력 바를 고정한 모바일 우선 레이아웃
- 지수형 백오프로 자동 재연결(최대 10회 재시도)
- 연결 상태 표시기