把 SSH 工作台搬上全球边缘网络:深度拆解 ternssh —— 基于 Cloudflare Workers + Durable Objects 的免客户端 Web 终端与 SFTP 文件系统(纯 TypeScript 协议栈/零信任安全/全景实战)
如果你是一位经常需要在多台 VPS、跨国云主机之间来回穿梭的开发者或 SRE,你一定经历过这样的窘境:在没有随身携带主力工作本的紧急时刻,或是受制于严苛的公司内网环境,想要连上远程服务器排查故障,通常只有两个选择——要么临时下载配置 SSH 客户端和私钥,要么自建一套像 JumpServer、Apache Guacamole 或 Next Terminal 这样功能完备的 Web 堡垒机。
然而,传统的 Web SSH 方案存在着不可回避的痛点:它们通常是基于 Python、Go 或 Java 编写的常驻服务,动辄占用数百 MB 甚至上 GB 内存;必须暴露公网 HTTP/WebSocket 端口,极易成为全网扫描器挖掘 0day 漏洞的靶子;而在轻量化方面,大多数简易网页终端又缺乏趁手的 SFTP 文件管理与实时系统监控能力。
最近开源的 ternssh(GitHub: HaradaKashiwa/ternssh)提供了一种颠覆性的全新解法:直接将完整的 SSH 工作台、SFTP 文件管理器与监控仪表盘搬上了 Cloudflare Edge 边缘网络。它不仅做到了零服务器常驻(Serverless)、全球 Anycast 就近接入,更在底层硬核实现了一套无原生 C++ 依赖的纯 TypeScript SSH2/SFTP 协议栈。
本文将以第一视角带你深入拆解 ternssh 的系统架构、协议穿透黑科技、零信任安全防线以及从 Workers 到 Docker 的落地实战。
1. 为什么我们需要边缘原生的 Web SSH?
在深入代码之前,我们先梳理一下开发者在远程连接工具链上的核心矛盾:
| 维度 | 本地桌面客户端 (Termius / Warp) | 传统 Web 堡垒机 (JumpServer / Guacamole) | ternssh (Cloudflare Workers) |
|---|---|---|---|
| 设备便携性 | 差(需逐台设备安装配置、同步私钥) | 优(任意浏览器即开即用) | 极致(任意现代浏览器,全球秒级加载) |
| 服务器常驻资源 | 无(运行在客户端) | 高(常驻 512MB~2GB 内存,容器长期占用) | 零成本(Edge Serverless 纯按量计费,无常驻消耗) |
| 网络延迟表现 | 取决于本地到目标机路由 | 取决于中转堡垒机节点 | 全球 Anycast(通过 Cloudflare 边缘骨干网就近建连) |
| 公网暴露攻击面 | 仅开放目标机 SSH 端口 | 开放中转机 Web 端口与数据库,需打补丁 | 收敛至 Cloudflare Access,支持硬件 Key 零信任 2FA |
| 运维功能完整性 | 高(终端 + SFTP + 端口转发) | 高(偏向权限审计,稍显臃肿) | 轻巧聚焦(终端 + 拖拽看板 + SFTP + 在线编辑器) |
对于个人开发者、独立黑客以及小型 DevOps 团队而言,花费不菲的服务器预算去长期维护一台仅在紧急时使用的堡垒机,显然是不划算的。而基于 Cloudflare Workers 免费配额即可运转的 ternssh,恰好切中了这个“轻量、高可用、高安全”的黄金平衡点。
2. 核心架构拆解:V8 沙箱中的 SSH2 协议穿越
许多熟悉 Cloudflare Workers 的同学第一反应可能是:“Workers 不是运行在 Google V8 Isolate 隔离沙箱里吗?它怎么可能建立 TCP 连接去跑 SSH 协议?”
这正是 ternssh 最令人惊艳的技术突破点。
2.1 全链路拓扑图
flowchart TD
subgraph Browser ["客户端浏览器 (React 19 + Tailwind v4)"]
UI["可拖拽仪表盘 Dashboard"]
XTerm["xterm.js 虚拟终端 (Canvas/WebGL)"]
CM["CodeMirror 6 远程文件编辑器"]
SFTPUI["SFTP 树状文件树 & 上传管理器"]
end
subgraph CF_Edge ["Cloudflare Global Network (Edge Workers)"]
Access["Cloudflare Access (Zero Trust JWT 鉴权)"]
Router["Worker Entry (server/src/index.ts)"]
D1[("Cloudflare D1 SQLite 数据库\n存储主机配置/密钥/面板状态")]
DO["Durable Objects (SshSession 单例持久连接)"]
SocketAPI["cloudflare:sockets API (原生 TCP 套接字)"]
end
subgraph Target ["远端目标服务器 (Any VPS / Cloud)"]
SSHPort["sshd (Port 22 / TCP)"]
Proc["/proc 系统指标采样"]
FileSystem["Linux 文件系统 (SFTP Subsystem)"]
end
UI -->|"HTTPS 静态请求"| Router
XTerm -->|"WebSocket 双向终端流"| Access
SFTPUI -->|"WebSocket SFTP 分片流"| Access
CM -->|"文件热保存"| SFTPUI
Access -->|"JWT 验签通过"| Router
Router -->|"路由委派"| DO
Router -->|"读写凭证与设置"| D1
DO -->|"创建 TCP 套接字"| SocketAPI
SocketAPI -->|"原始 TCP SSH2 流量"| SSHPort
SSHPort -->|"探针定时读取"| Proc
SSHPort -->|"SFTP 子系统读写"| FileSystem
2.2 核心硬核点:为什么手搓纯 TypeScript SSH 栈?
在传统 Node.js 环境下,做 SSH 相关的工具几乎 100% 依赖著名开源库 ssh2。但 ssh2 依赖了底层 C++ 绑定的原生加密库以及 Node.js 的标准 net.Socket。在 Cloudflare Workers 的纯 V8 沙箱里,这些原生编译模块完全无法载入。
ternssh 作者 Harada Kashiwa 在 server/src/ssh/ 下直接纯手写了一整套 SSH 协议的核心实现:
- 网络传输层 (
transport.ts):基于 Cloudflare 官方提供的import { connect } from 'cloudflare:sockets',在边缘节点与目标服务器建立原始双向 TCP 流。 - 密钥交换与加密 (
kex.ts,packet.ts):完全基于浏览器的标准 WebCrypto API(crypto.subtle),实现了 Curve25519、ECDH-SHA2-NISTP256、Diffie-Hellman 等密钥交换算法,以及 AES-128-GCM、AES-256-GCM、ChaCha20-Poly1305 等对称加解密与 MAC 校验。 - 状态机与会话保持 (
session.ts):处理 SSH 认证报文(Password / Public Key 签名)、Channel 打开、PTY 伪终端请求(pty-req)、窗口缩放尺寸同步(window-change)以及心跳保持。 - SFTP 子系统完整解析 (
sftp.ts,sftp-handler.ts):在已经建立的 SSH Channel 上封装 SFTP 二进制协议头,实现SSH_FXP_OPEN、SSH_FXP_READ、SSH_FXP_WRITE、SSH_FXP_STAT等状态码,支持文件流式读取与写入。
2.3 Durable Objects 的中枢协同
SSH 会话是有状态的长连接,而标准的 Cloudflare Worker 是无状态、随用随起的短生命周期函数。为了保证终端输入输出不会因为 Worker 调度而中断,ternssh 采用了 Durable Objects (SshSession):
sequenceDiagram
autonumber
participant Client as 浏览器 (xterm.js)
participant Worker as Worker Gateway
participant DO as Durable Object (SshSession)
participant Target as 目标主机 (Port 22)
Client->>Worker: 发起 WebSocket 升级握手 (/api/ws/ssh?session_id=xxx)
Worker->>DO: 转发 WebSocket 至对应 Durable Object ID
DO->>DO: 校验会话 Token 与本地 SQLite 锁
DO->>Target: connect({ hostname, port }) 建立 TCP
Target-->>DO: SSH-2.0 握手报文
DO->>Target: 纯 TS 执行 KEX & WebCrypto 密钥协商
DO->>Target: 发送 UserAuth (公钥/私钥签名)
Target-->>DO: SSH_MSG_USERAUTH_SUCCESS
DO->>Target: 请求 pty-req & shell
DO-->>Client: WebSocket 建立完毕,流式输出欢迎横幅
rect rgb(30, 40, 60)
Note over Client,Target: 全双工双向低延迟流转
Client->>DO: 键盘击键数据 (WebSocket Frame)
DO->>Target: 加密 SSH 数据包 (TCP Socket)
Target-->>DO: 解密回显终端字符
DO-->>Client: xterm.js 绘制 ANSI 字符
end
这种架构使得无论用户在世界的哪一个角落发起连接,Cloudflare Anycast 都会将前端就近路由,并在最靠近目标机器的 Edge 机房实例化 Durable Object,极大地缩短了 RTT(往返时延)。
3. 功能亮点:不仅是终端,更是现代化工作台
ternssh 并没有停留在“网页敲命令”的初级阶段,而是打造了一整套现代化的运维工作台:
3.1 拖拽式系统监控仪表盘
- 在连接服务器后,ternssh 可以通过轻量后台探针定期采样远端服务器的负载(Load Average)、CPU 使用率、内存占比、磁盘使用空间与网络 I/O。
- 前端使用基于 React 19 的网格布局系统,仪表盘卡片支持自由拖拽、缩放、组合,无论是竖屏监控还是多主机并排巡检都能轻松应对。
3.2 基于 CodeMirror 6 的远端热重载编辑器
- 过去在 Web 终端里修改 Nginx 配置或 Docker Compose 文件,必须忍受在低延迟网络下用 Vim 盲打的痛苦。
- ternssh 内置了强大的 CodeMirror 6 编辑器,支持 JSON、YAML、Nginx、Shell、Python、Rust 等数十种主流语言的语法高亮与行号显示。
- 在左侧 SFTP 树状列表中双击文件,即可直接在右侧选项卡唤起编辑器;按下
Cmd + S/Ctrl + S,系统自动通过 SFTP 协议增量保存并回写远端。
3.3 零信任防护:Cloudflare Access 原生防线
- 传统的开源 Web SSH 最怕密码被爆破或服务代码暴露漏洞。
- ternssh 深度集成了 Cloudflare Zero Trust 的 Access 鉴权机制。在环境变量中配置
ACCESS_TEAM_DOMAIN和ACCESS_AUD后,Worker 会在入口强制校验 HTTP 请求头中的Cf-Access-Jwt-Assertion。 - 只有通过了企业 SSO(如 Google Workspace、GitHub Org、Okta)并且满足设备证书/硬件 Key 策略的用户才能接触到 WebSocket 入口,实现了真正的“零暴露、零公网密码渗透”。
4. 生产环境实战部署方案
ternssh 提供了两种极具弹性的部署途径:Cloudflare 边缘云端部署 与 本地/私服 Docker 部署。
方案一:Cloudflare Workers 边缘零成本极速部署(推荐)
-
克隆项目源码并安装依赖:
git clone https://github.com/HaradaKashiwa/ternssh.git cd ternssh npm install -
准备 D1 数据库与配置文件:
# 拷贝生产配置模版 cp wrangler.production.jsonc.example wrangler.production.jsonc # 在 Cloudflare 创建 D1 数据库 npx wrangler d1 create ternssh-db将终端输出的
database_id回填到wrangler.production.jsonc的d1_databases节点中。 -
构建前端并执行边缘发布:
# 构建 React 19 前端静态资源 npm run build # 应用 D1 远程数据库迁移 npm run db:migrate # 一键推送到 Cloudflare 全球网络 npm run deploy -
绑定 Cloudflare Access(安全必备):
在 Cloudflare Zero Trust 控制台创建一个 Access Application,指向你的 Worker 自定义域名(如ssh.yourdomain.com),并将生成的 Application AUD 与 Team Domain 写入环境变量:npx wrangler secret put ACCESS_TEAM_DOMAIN npx wrangler secret put ACCESS_AUD
方案二:Docker / 本地私有化快速启动
如果你的服务器处于没有外网或严格合规的内网局域网,ternssh 官方镜像也打包了完整的单机本地运行环境(底层基于 Wrangler 本地沙箱模拟 D1 与 DO):
# docker-compose.yml
services:
ternssh:
image: ghcr.io/haradakashiwa/ternssh:latest
container_name: ternssh
restart: unless-stopped
ports:
- "8787:8787"
volumes:
- ternssh-data:/app/.wrangler
environment:
# 可选:如果前端挂了反向代理,可配置 Access JWT 校验
- ACCESS_TEAM_DOMAIN=
- ACCESS_AUD=
volumes:
ternssh-data:
一键启动:
docker compose up -d
启动后直接访问 http://localhost:8787 即可初始化管理面板。
5. 深度实测心得与踩坑避险指南(Gotchas)
在深入试用与审查代码后,有以下几个核心细节值得在生产落地时重点关注:
[!WARNING]
1. Cloudflare Workers TCP Sockets 连接限制
- Cloudflare 的
cloudflare:sockets现阶段仅支持对标准非保留公网 IP 和域名的 TCP 连接,无法直接连接127.0.0.1或内网私有网段(如192.168.x.x)。若需穿透内网,目标主机前置需要暴露公网入口或通过 Cloudflare Tunnel / 端口转发。- 在 Cloudflare Free 计划下,TCP 连接受到并发连接数限制;同时如果长达 100 秒没有任何数据包往返,边缘节点会主动切断 Socket。避坑方案:建议在目标主机的
/etc/ssh/sshd_config中配置ClientAliveInterval 30和ClientAliveCountMax 3,由服务端定时发送心跳空包防超时。
[!TIP]
2. 首次连接信任(TOFU)与公钥指纹
ternssh 在首次连接目标主机时,会将目标服务器的 Host Key 指纹记录在 Cloudflare D1 数据库中。如果远端服务器重装或被更换,前端会弹出安全告警阻断连接,有效防止了中间人攻击(MITM)。在迁移服务器时如果遇到认证失败,只需进入主机管理面板刷新指纹缓存即可。
[!NOTE]
3. 大文件传输的内存天花板
Cloudflare Worker 单个请求的内存上限通常为 128MB。ternssh 在 SFTP 上传与下载时采用了分片流式管道设计(Chunk Streaming),避免一次性将上百兆文件载入内存。但在网络抖动环境下传输超大文件(>500MB),仍建议优先使用命令行rsync,将 Web SFTP 留给代码配置文件与日志的高频调阅。
6. 总结与展望
HaradaKashiwa/ternssh 是一次非常大胆且优雅的技术实践。它证明了:
- Serverless 与边缘计算的边界正在急剧扩大:从最初简单的 HTTP API、SSR 网页渲染,到现在完全可以用纯 TypeScript 实现复杂的双工长连接网络协议栈(如 SSH2/SFTP)。
- 零信任基础设施的普及化:借助 Cloudflare 强大的免费生态矩阵(Workers + D1 + Durable Objects + Access),个人开发者和初创团队不需要购买额外服务器,就能在 5 分钟内搭建一套比肩工业级安全的全球可访问运维中枢。
如果你正好在寻找一款无需常驻开销、随时随地在浏览器中开箱即用的轻量 SSH 工作台,ternssh 绝对值得你立刻部署一试。
- GitHub 源码:HaradaKashiwa/ternssh
- 官方文档:ternssh.com/docs/home