Termal Desktop

为什么要在 SSH 上放一个桌面。

在远程服务器上放一个图形环境,听起来像是为了方案去找问题。以下是老实的论证——包括那些你应该关掉这一页、继续用终端的情况。

「这些我用 ssh 和 vim 早就能做了」

确实如此。这一页上的每一件事,用一个 SSH 会话、一个 shell 和你早已熟悉的编辑器都能完成。如果你管理的是一台服务器、vim 用得很顺、工作流本来就装得进终端——那这个产品不适合你,我们宁愿你继续用现在的工具。

图形层的存在,不是因为终端不够用。而是因为终端是一种顺序式的界面,而有些工作本身并不是顺序的。一边看着传输进度,一边读日志,一边改配置文件——在任何桌面上就是三个窗口,在终端里则是三个 tmux 面板外加大量的自律。

这个主张是刻意收窄的:不是「比终端更好」,而是「在一组特定任务上比终端更快」。Termal OS 内置了一个真正的 PTY shell,恰恰是因为大多数时候,终端仍然是对的工具。

图形层真正站得住脚的场合

四种情形,都是我们听得最多的。

  • 搬文件,并且看得见进度。scp 在两个位置之间复制一个目录,你得到的是一个闪烁的光标和一点希望。文件浏览器给你的是任务队列、每个传输的实时百分比,以及当目标位置已存在同名文件时的重命名——而不是无声的覆盖。在慢速链路上传 4 GB 的目录时,「它还在动吗」是一个真实的问题。
  • 读不是你写的代码。改一个熟悉的文件,那是 vim 的活。理解一份陌生的代码库——在文件之间跳转、顺着 include 往下走、在整棵目录树里搜索——那是文件树和标签页的活。这正是一个架在远程文件系统上的 Monaco 编辑器所提供的,而且不用把任何东西签出到本地。
  • 接手一台你从没见过的服务器。这是最有力的一种情形。Termal 会识别这台机器上跑着什么——Plesk、cPanel,还是原生的 nginx 或 Apache——列出它承载的站点及各自实际使用的 PHP 版本,显示正在运行的服务和容器,并找出日志文件。靠手工得到同样一幅图景,意味着十几条命令,外加知道每个发行版把东西藏在哪里。
  • 站在服务器自己的网络位置上测试。一条只在服务器上通、别处都不通的内部路由,从终端里很难看清楚。HTTP 客户端会在服务器上执行 curl,并把响应头和正文摊开给你看。浏览器还要更进一步:默认情况下它从你自己的机器出网,但你可以把它的网络出口切到服务器——流量随即通过你已有的那条 SSH 连接上开出的 SOCKS5 隧道走,工具栏上的标记会告诉你当前是哪一种。再配上按标签页停靠的开发者工具,一个只对内可见的页面,就从「靠推断」变成了「直接看」。
Termal OS 列出某台服务器上托管的所有网站,每个站点都标明实际使用的 PHP 版本,并带有统计、访问日志、错误和 git pull 按钮
第三种情形,一屏之内:服务器承载的每一个站点、各自实际使用的 PHP 版本,以及是否有更新在等着。靠手工得到这些,意味着十几条命令,外加知道你的发行版把东西放在哪儿。域名已作模糊处理。
Termal OS 的「服务器之间传输」窗口,显示复制文件时 41% 的进度条,两侧各有一个文件浏览器
第一种情形:一次正在进行的服务器之间的复制,有进度条,而不是一个闪烁的光标。
Termal OS 浏览器设置提供两种网络出口:从本机直连,或通过 SSH 服务器的 SOCKS 隧道,每张卡片都标明各自的网络服务商
第四种情形是一个设置项:同一个浏览器,两种出网方式——直接从你的机器出去,或者经由 SSH 隧道从服务器出去。图中两个公网 IP 和所在城市都已作像素化处理。

这一切,都在同一条连接上

这是架构上真正要紧的部分,也是这个桌面并非「一堆 SSH 调用外面套层皮」的原因。

Termal OS 维护着一个可复用的 SSH 连接池——每台服务器一条,带保活机制,而所有东西都跑在它上面:指标、文件浏览器、终端、编辑器、日志跟踪。打开文件管理器并不会新开一个会话。没有额外端口,没有代理程序,没有第二次认证,机器上也没有安装任何东西。从服务器的角度看,你只是一次普通的 SSH 登录,在做一些普通的事。

正是这个约束,让这个桌面能在你既没有 root、也无权安装任何东西的主机上工作——虚拟主机、受管主机、客户的机器。一个需要守护进程的图形管理面板,在那些地方毫无用处。

桌面里究竟有什么

一个带任务栏、开始菜单和桌面图标的窗口管理器,以及 23 个应用。真正干活的那些:

  • 文件浏览器——SFTP 浏览器:复制、移动、上传、把目录打包下载、权限设置、拖放、带进度的传输队列。
  • 终端——一个真正的 PTY shell,不是那种只能执行单条命令的输入框。
  • Termal Code——Monaco(VS Code 用的那个编辑器),带文件树和标签页,直接在远程文件系统上编辑。
  • 浏览器——多标签、书签、下载、查看源码,以及按标签页停靠的开发者工具。
  • 监视器、进程、日志——实时指标、可以直接结束进程的列表,以及能自动发现常见 Apache、nginx、PHP、MySQL 和 syslog 文件的日志跟踪。
  • Web 请求、Zip、Git、FTP、回收站——那些小工具;没有它们,你会在任务做到一半时被赶回 shell。
  • 助手——用日常语言提问,得到一条命令和它的解释。在你点击之前什么都不会执行,而且用的是你自己的 API 密钥

此外还有邮件客户端、便签、计算器、单位换算、取色器和几个小游戏。二十三个里有十三个默认是关闭的——只有应用商店、设置、文件浏览器和回收站是常驻的——因为一个把文件浏览器埋在游戏菜单底下的首次启动,本身就是反对这整个想法的最佳论据。用得上什么,再打开什么。

Termal OS 桌面上,Termal Git 显示提交历史和差异,旁边是打开着 PHP 文件的 Monaco 编辑器 Termal Code
Git 历史、一份 diff 和 Monaco 编辑器同时打开——顺序式界面的问题,用最朴素的方式解决了。
Termal OS 中对远程文件的右键菜单,提供打开、用其他程序打开、下载、下载到我的电脑、创建桌面快捷方式、压缩、复制、剪切、重命名、权限、移到回收站和永久删除
在远程文件上点右键:用其他程序打开、下载到你的电脑、压缩、权限、移到回收站。它用起来像桌面,因为它本来就是。

开发者应该看的部分

这个桌面是可扩展的,而它的扩展模型是整份代码里最值得一看的东西。

第三方应用运行在一个沙箱化的 iframe 里。它无法直接接触文件系统、网络或剪贴板。每一次特权调用都通过消息发给宿主,由宿主对照该应用在清单中声明的权限进行核对——而权限只有六种:fs.readfs.writenetstorageclipboardwebview。安装时它们会明确展示给你。运行时代码文件头部写的规则毫不含糊:iframe 永远不被信任,一切由宿主校验。

这一点在这里比在大多数插件体系里都更重要,因为这些应用面对的是你已经授予 SSH 访问权限的服务器。一个插件能悄悄读走你密钥的应用商店,是无法自圆其说的。

而且这个 SDK 并不是为外部人另开的一套次等接口:内置的计算器就是通过 Termal.app() 注册的——正是第三方应用使用的那个公开入口。SDK 随附八个完整的示例应用,从便签到 webview 宿主再到服务器小组件。

一个第三方 Termal 应用运行在沙箱中,其日志显示:清单权限为剪贴板与存储、剪贴板写入、setTitle、存储在重启后依然保留
上面那段论述,在实际运行中的样子。这是一个第三方应用在它自己的沙箱里——它自身日志的第一行,就是它声明的权限集合,而下面的每一次调用,都是清单允许的调用。

完整的参考——清单、运行时、对话框、文件选择器、存储、网络、webview、剪贴板、窗口控制、翻译、打包——都在 Termal App Studio 页面上。

它不是什么

  • 不是终端的替代品。它内置了一个,而你也会用到它。如果你的工作本来就装得进 shell,这个桌面提供不了你需要的东西。
  • 不是远程桌面协议。没有 X11,没有 VNC,没有 RDP,你这一端也没有显示服务器。窗口管理器在应用内本地运行;只有文件、shell 和指标的流量会经过那条 SSH 连接。
  • 不是始终在线的。关掉窗口后采集仍会继续,但应用必须运行在一台醒着的机器上。合上笔记本,采集就停了——参见 与 Netdata 的对比,这一点在那里最要紧。
  • 不适合上千台服务器。几台到几十台。仅限通过 SSH 的 Linux:没有 SNMP,没有 Windows,也没有网络发现。