Architecture
High-level flow
Default (local tmux + tunnel):
Browser (phone)
|
| HTTPS
v
Cloudflare Quick Tunnel
|
| HTTP/WS
v
Local Termbridge server
|
| PTY
v
Tmux sessionDirect 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-ptyto attach to tmux for real keystrokes and output. - Daytona backend: Uses Daytona PTYs inside a sandbox.
- Sets
TERM=xterm-256colorandCOLORTERM=truecolorfor 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/:tokenredeems the token and sets a cookie session.- WebSocket connections require a valid session cookie and CSRF token.
- CSRF token fetched via
GET /__tb/api/csrfand 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 checkGET /__tb/s/:token- token redemption → cookie → redirectGET /__tb/api/terminals- list terminalsGET /__tb/api/csrf- get CSRF token for WebSocketGET /__tb/api/config- get config (proxyPort, devProxyUrl)POST /__tb/api/terminals- create a new tmux sessionGET /__tb/app/*- SPA fallbackWS /__tb/ws/terminal/:terminalId?csrf=<token>- stream terminal I/O
When proxy mode is enabled:
GET /- redirects to proxied app (or/__tb/appif 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