架构
高层流程
默认模式(本地 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,禁用 tmux 状态栏,让 UI 保持简洁。
终端注册表
- 跟踪可用的终端会话。
- 为 UI 提供列表,并验证所选终端 ID。
身份验证与会话
- 一次性令牌会以 URL 打印,并编码在 QR 代码中。
GET /__tb/s/:token兑换令牌并设置 Cookie 会话。- WebSocket 连接需要有效的会话 Cookie 和 CSRF 令牌。
- 通过
GET /__tb/api/csrf获取 CSRF 令牌,并通过 WebSocket 查询参数传递。
代理模式
传入 --proxy <port> 时:
- 所有 termbridge 路由都位于
/__tb/前缀下 - 非
/__tb/请求会代理到目标应用 - UI 通过 Views 切换器提供 Terminal/Preview 视图
- Preview 视图会加载指向
/的 iframe - HMR 的 WebSocket 连接会转发到目标
安全
- CSRF 防护:WebSocket 升级需要 CSRF 令牌,以防止跨站劫持。
- 输入限制:HTTP 请求正文 64KB、WebSocket 消息 1MB、每条消息终端输入 64KB。
- 速率限制:令牌兑换和 WebSocket 连接均按 IP 限制。
API 端点
所有路由都位于 /__tb/ 前缀下,以避免与代理应用冲突:
GET /__tb/healthz- 健康检查GET /__tb/s/:token- 兑换令牌 → Cookie → 重定向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 次)
- 连接状态指示器