把 SSH 工作台搬上全球边缘网络:深度拆解 ternssh —— 基于 Cloudflare Workers + Durable Objects 的免客户端 Web 终端与 SFTP 文件系统(纯 TypeScript 协议栈/零信任安全/全景实战)

把 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 协议的核心实现:

  1. 网络传输层 (transport.ts):基于 Cloudflare 官方提供的 import { connect } from 'cloudflare:sockets',在边缘节点与目标服务器建立原始双向 TCP 流。
  2. 密钥交换与加密 (kex.ts, packet.ts):完全基于浏览器的标准 WebCrypto API(crypto.subtle),实现了 Curve25519、ECDH-SHA2-NISTP256、Diffie-Hellman 等密钥交换算法,以及 AES-128-GCM、AES-256-GCM、ChaCha20-Poly1305 等对称加解密与 MAC 校验。
  3. 状态机与会话保持 (session.ts):处理 SSH 认证报文(Password / Public Key 签名)、Channel 打开、PTY 伪终端请求(pty-req)、窗口缩放尺寸同步(window-change)以及心跳保持。
  4. 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 边缘零成本极速部署(推荐)

  1. 克隆项目源码并安装依赖:

    git clone https://github.com/HaradaKashiwa/ternssh.git
    cd ternssh
    npm install
    
  2. 准备 D1 数据库与配置文件:

    # 拷贝生产配置模版
    cp wrangler.production.jsonc.example wrangler.production.jsonc
    
    # 在 Cloudflare 创建 D1 数据库
    npx wrangler d1 create ternssh-db
    

    将终端输出的 database_id 回填到 wrangler.production.jsonc 的 d1_databases 节点中。

  3. 构建前端并执行边缘发布:

    # 构建 React 19 前端静态资源
    npm run build
    
    # 应用 D1 远程数据库迁移
    npm run db:migrate
    
    # 一键推送到 Cloudflare 全球网络
    npm run deploy
    
  4. 绑定 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 是一次非常大胆且优雅的技术实践。它证明了:

  1. Serverless 与边缘计算的边界正在急剧扩大:从最初简单的 HTTP API、SSR 网页渲染,到现在完全可以用纯 TypeScript 实现复杂的双工长连接网络协议栈(如 SSH2/SFTP)。
  2. 零信任基础设施的普及化:借助 Cloudflare 强大的免费生态矩阵(Workers + D1 + Durable Objects + Access),个人开发者和初创团队不需要购买额外服务器,就能在 5 分钟内搭建一套比肩工业级安全的全球可访问运维中枢。

如果你正好在寻找一款无需常驻开销、随时随地在浏览器中开箱即用的轻量 SSH 工作台,ternssh 绝对值得你立刻部署一试。