Termbridge

Architecture

High-level flow

Default (local tmux + tunnel):

Browser (phone)
  |
  | HTTPS
  v
Cloudflare Quick Tunnel
  |
  | HTTP/WS
  v
Local Termbridge server
  |
  | PTY
  v
Tmux session

Direct sandbox mode (Daytona, no tunnel):

Browser (phone)
  |
  | HTTPS
  v
Daytona preview link
  |
  | HTTP/WS
  v
Termbridge server (sandbox)
  |
  | PTY
  v
Tmux session (sandbox)

When --no-tunnel is set, Termbridge skips Cloudflare and uses your provided public URL.

Components

CLI process

  • Starts the HTTP server that serves the UI assets.
  • Starts the WebSocket server for terminal I/O.
  • Creates one or more tmux sessions (or Daytona PTYs).
  • Issues one-time redemption tokens.
  • Starts and monitors the tunnel when enabled (Cloudflare today).
  • In direct sandbox mode, launches Termbridge inside the sandbox and waits for the share URL.

Terminal backend

  • tmux backend: Uses node-pty to attach to tmux for real keystrokes and output.
  • Daytona backend: Uses Daytona PTYs inside a sandbox.
  • Sets TERM=xterm-256color and COLORTERM=truecolor for full color support.
  • For tmux, disables the tmux status bar to keep the UI clean.

Terminal registry

  • Tracks available terminal sessions.
  • Provides a list for the UI and validates selected terminal IDs.

Auth and session

  • One-time token is printed as a URL and encoded in a QR code.
  • GET /__tb/s/:token redeems the token and sets a cookie session.
  • WebSocket connections require a valid session cookie and CSRF token.
  • CSRF token fetched via GET /__tb/api/csrf and passed in WebSocket query param.

Proxy mode

When --proxy <port> is passed:

  • All termbridge routes live under /__tb/ prefix
  • Non-/__tb/ requests are proxied to the target app
  • UI exposes Terminal/Preview views via the Views switcher
  • Preview view loads an iframe pointing to /
  • WebSocket connections for HMR are forwarded to the target

Security

  • CSRF protection: WebSocket upgrades require a CSRF token to prevent cross-site hijacking.
  • Input limits: 64KB HTTP body, 1MB WebSocket message, 64KB terminal input per message.
  • Rate limiting: Per-IP limits on token redemption and WebSocket connections.

API endpoints

All routes live under the /__tb/ prefix to avoid conflicts with proxied apps:

  • GET /__tb/healthz - health check
  • GET /__tb/s/:token - token redemption → cookie → redirect
  • GET /__tb/api/terminals - list terminals
  • GET /__tb/api/csrf - get CSRF token for WebSocket
  • GET /__tb/api/config - get config (proxyPort, devProxyUrl)
  • POST /__tb/api/terminals - create a new tmux session
  • GET /__tb/app/* - SPA fallback
  • WS /__tb/ws/terminal/:terminalId?csrf=<token> - stream terminal I/O

When proxy mode is enabled:

  • GET / - redirects to proxied app (or /__tb/app if disabled)
  • * /* - proxied to target app

WebSocket protocol

Client -> server:

{ "type": "input", "data": "ls -la" }
{ "type": "resize", "cols": 120, "rows": 32 }
{ "type": "control", "key": "ctrl_c" }

Server -> client:

{ "type": "output", "data": "..." }
{ "type": "status", "state": "connected" }

UI stack

  • Vite + TanStack Router
  • xterm.js + Fit addon + WebGL renderer
  • Mobile-first layout with a fixed input bar
  • Auto-reconnect with exponential backoff (up to 10 retries)
  • Connection status indicator

On this page