运维和后端开发里有一类麻烦,不是「连不上服务器」这种大事,而是一堆很小但天天重复的操作:
- 连上去敲一条命令看看状态,
- 把一个安装包传上去,
- 把一份日志拉下来,
- 瞄一眼 CPU 和内存满没满,
- 然后在生产、测试、数据库、日志机之间来回切。
每一件单独看都不算事。可一旦机器多起来,系统自带的 ssh / scp / sftp 各管一摊、IP 和端口靠脑子记、参数每次重敲------这种「碎」就成了真正的时间黑洞。
r-shell 想把这摊碎活收进一个命令行二进制 里:connections 管连接、exec 跑命令、shell 开交互终端、upload / download 走 SFTP、stats 打系统快照。它用 Rust 写内核,SSH 栈是纯 Rust 的 russh,不依赖 OpenSSL / libssh,所以 macOS / Linux / Windows 都能出一个零依赖、拷过去就能跑的单文件。
这篇不讲 AI,只讲一件事:怎么把多服务器的日常操作,收敛成一个顺手、可脚本化、带安全默认值的命令行工具。 文中每条命令和输出都对应仓库里能跑的实现。

一、它能干什么
一张表先把全貌摆出来:
| 子命令 | 作用 |
|---|---|
connections |
增删改查已保存的主机(存在本地 workspace.json) |
exec |
在远程主机上执行单条命令并打印输出 |
shell |
打开完整交互式 PTY(vim / htop / less 都能用) |
ls |
列出远程目录 |
upload / download |
通过 SFTP 单文件上传 / 下载 |
stats |
一次性的 CPU / 内存 / 磁盘 / 网络快照(Linux 与 Windows 通吃) |
mcp |
启动本地 MCP 服务器(可选,本文不展开) |
同一个二进制在三大平台都能跑。exec / shell / upload / download 适用于任意 POSIX 主机;ls 面向 Linux(依赖 GNU ls);stats 则做了 OS 适配,Linux 读 /proc、Windows 走 PowerShell CIM,都能出数。
二、和系统自带的 ssh / scp 有什么区别
常有人问:ssh、scp 不是够用了吗?够用,但 r-shell 解决的是「够用之上的碎」。它的定位看这张表最清楚:
| 场景 | 传统 ssh / scp | r-shell |
|---|---|---|
| 连接信息管理 | 手写 ~/.ssh/config 或脑子记 IP |
connections 子命令统一增删改查 |
| 执行远程命令 | ssh user@host "cmd" |
r-shell exec -c prod -- cmd |
| 文件传输 | scp 单独拼路径 |
upload / download 复用同一份连接定义 |
| 看负载 | 手动 top / df / free 各看一遍 |
stats 一条命令聚合成一屏 |
| 输出 | 面向人眼 | 表格之外都给 --json,对脚本友好 |
| 安全默认 | 取决于系统与个人习惯 | 内置主机密钥 TOFU、凭据文件 0600 |
| 分发 | 依赖系统自带 | 纯 Rust 单二进制,零系统依赖,拷了就跑 |
一句话:r-shell 不是要取代 ssh,而是把「连接管理 + 常用操作 + 安全默认 + 可脚本化」打包成一个顺手的工具。
三、技术选型:为什么是 Rust + russh,且不依赖 OpenSSL
三个关键决策:
- 语言用 Rust。SSH、SFTP、系统采样这些活儿,既要正确又要能扛并发,Rust 的所有权和类型系统能把「连接状态、凭据边界」这类不变量直接编译进类型里,少一类运行期惊吓。
- SSH 栈用纯 Rust 的
russh,而不是去绑 OpenSSL / libssh。这一条对「分发」太关键了:一旦动态依赖 OpenSSL,你在 Windows 上就得操心运行时和版本地狱;改用russh后,整套握手、认证、PTY、known_hosts都在 Rust 里,编出来就是一个零系统依赖的单二进制,拷到一台干净机器上直接能跑。 - 异步用 tokio 。SSH / SFTP 是典型 I/O 密集场景,全程异步;命令行参数与子命令树交给
clap的 derive 宏声明,--help自动生成;交互终端的 raw mode 和无回显密码输入交给crossterm。
依赖很克制,核心就这几样(core 的 Cargo.toml):
toml
russh # 纯 Rust SSH 协议:握手 / 认证 / 通道 / PTY
russh-keys # 密钥与 known_hosts 处理
russh-sftp # SFTP 子系统:文件传输 / 列目录
tokio # 异步运行时
sysinfo # 本机资源采样
CLI 这一层再叠上 clap(命令行)和 crossterm(终端控制)。全程没有 OpenSSL。
四、架构:CLI 与桌面端共享同一套内核
r-shell 最初其实是个图形界面应用。正因为业务逻辑和界面一开始就解耦,后来重构出命令行版时,几乎零成本复用了全部后端------CLI 和桌面 GUI 共用同一个 core:同样的连接管理、同样的 SSH 实现、同样的系统采样。你在 GUI 里存的连接,CLI 也认;反过来也成立。
text
┌───────────────────────────┐
桌面 GUI ───┤ flutter_rust_bridge (FFI) ├──┐
└───────────────────────────┘ │
▼
r-shell CLI ───────────────────────▶ core(共享内核)
├── native_backend SSH/SFTP、连接管理器
├── monitor /proc 与 PowerShell CIM 采样
├── model SavedConnection / 脱敏 sanitized()
└── storage workspace.json(0600)
CLI 入口本身很薄,clap 解析完就把活儿丢给 core:
text
cli/
└── src/main.rs # 参数解析、子命令分发、输出格式化(表格 / JSON)
core/
└── src/ # native_backend / monitor / model / storage / mcp ------ CLI 与 GUI 共用
五、命令实战(附真实输出)
下面按子命令给出可直接复制的示例,输出格式都对应 main.rs 里真实的打印逻辑。
1. connections ------ 像通讯录一样管连接
bash
# 新增一个用公钥认证的连接
r-shell connections add \
--name prod-web --host 203.0.113.10 --username deploy \
--auth publickey --key-path ~/.ssh/id_ed25519 \
--folder Work --description "生产环境 Web 服务器"
# 列表(表格)
r-shell connections list
表格输出:
text
ID NAME HOST AUTH FOLDER
ssh-1781247286839 prod-web deploy@203.0.113.10:22 publickey Work
ssh-1781247290114 test-db root@10.0.0.5:22 password Staging
加 --json 给脚本用,而且是脱敏的------只告诉你有没有密码 / 私钥,绝不回吐明文:
json
[
{
"connection_id": "ssh-1781247286839",
"name": "prod-web",
"host": "203.0.113.10",
"username": "deploy",
"port": 22,
"auth_method": "publickey",
"folder": "Work",
"tags": [],
"description": "生产环境 Web 服务器",
"status": "Disconnected",
"has_password": false,
"has_private_key_path": true
}
]
改字段、删连接也都在一条命令里:
bash
r-shell connections update ssh-1781247290114 --port 2222 --folder Staging
r-shell connections remove ssh-1781247290114
2. exec ------ 跑一条命令就走
-- 之后的内容原样发给远端。既能用已存连接(-c),也能临时给 --host:
bash
r-shell exec -c prod-web -- uname -a
r-shell exec -c prod-web -- "ls -la /var/www && df -h"
r-shell exec --host 203.0.113.10 --user deploy -- systemctl status nginx
「连接 → 执行 → 自动断开」一气呵成,特别适合写进巡检 / 部署脚本里批量跑。
3. shell ------ 完整交互式终端
raw 模式下的完整 PTY,vim、htop、less 这类需要伪终端的程序都能正常用。会话卡住时按 Ctrl-] 强制退出本地循环:
bash
r-shell shell -c prod-web
4. ls ------ 列远程目录
bash
r-shell ls -c prod-web /var/log
输出列依次是:类型(DIR / FILE / LNK)、权限、大小、修改时间、名称:
text
DIR drwxr-xr-x 4096 2026-06-20 14:31 nginx
FILE -rw-r--r-- 10240 2026-06-21 09:02 syslog
FILE -rw-r--r-- 204800 2026-06-21 08:55 dpkg.log
LNK lrwxrwxrwx 24 2026-06-18 02:00 alternatives.log
加 --json 同样可以拿去喂脚本。
5. upload / download ------ SFTP 传文件
走 SFTP,不依赖远端有没有 scp,只要 SSH 通就能传:
bash
# 本地 -> 远程
r-shell upload -c prod-web ./app.tar.gz /tmp/app.tar.gz
# Uploaded ./app.tar.gz -> /tmp/app.tar.gz (12.4 MB)
# 远程 -> 本地
r-shell download -c prod-web /tmp/remote.log ./local.log
# Downloaded /tmp/remote.log -> ./local.log (843.2 KB)
6. stats ------ 一屏看完系统资源
连续采样两次,算出 CPU 占用和网络速率,一条命令出一份快照。Linux 上读 /proc:
bash
r-shell stats -c prod-web
text
OS: Linux 6.1.0
Uptime: 12d 4h 31m
CPU: 7.4% (8 cores, load 0.42)
Memory: 61.2% (4.9/7.8 GB)
Disk: 40.0% (3.8/9.5 GB)
Network: down 1.5 KB/s up 320 B/s
同一条命令打到 Windows 主机也能出数------内核里换成一段 PowerShell CIM 采集,自动处理好编码:
text
OS: Microsoft Windows 11 专业工作站版 10.0.29591
Uptime: 7d 6h 12m
CPU: 9.0% (8 cores, load 0.00)
Memory: 52.0% (8.3/15.9 GB)
Disk: 52.4% (56.3/118.1 GB)
Network: down 18.6 KB/s up 2.4 KB/s
六、一次性命令的生命周期:连接 → 执行 → 断开
exec / ls / upload / download / stats 都遵循同一套「用完即走」的模型,这也是它适合脚本化的原因:
text
解析目标(-c 已存连接 / --host 临时主机;缺密码则安全提示输入)
↓
建立 SSH 连接(握手 → 主机密钥 TOFU 校验 → 密码或公钥认证)
↓
执行子命令对应的操作
↓
自动关闭连接,干净退出
每条命令都自包含、互不残留状态,写进 CI / 巡检脚本里行为可预测。(需要在一条会话里连发多条命令、保持工作目录的场景,则交给 shell 的交互式 PTY。)
七、面向运维的安全默认值
SSH 工具直连服务器凭据,安全不能是「可选项」。r-shell 把几条底线做成了默认行为:
- 主机密钥 TOFU(首次信任) 。按
~/.ssh/known_hosts校验:首次连接记录主机密钥,之后必须一致;一旦对不上(典型的中间人,或主机被换),直接中止连接 而不是默默连上去。只有显式传--insecure才跳过------那是留给一次性测试机的,不是日常姿势。 - 凭据只进不出 。密码、私钥路径、口令绝不会被打印;任何连接列表都走
sanitized(),只暴露has_password/has_private_key_path这种布尔值。 - 密码输入不回显。终端进 raw 模式逐字节读取,屏幕上不显形。
- 配置文件仅属主可读 。
workspace.json在 Unix 上以0600创建、目录0700,不让同机器上别的用户cat到你的跳板信息。
已保存连接的落盘位置:
| 系统 | 路径 |
|---|---|
| macOS | ~/Library/Application Support/r-shell/workspace.json |
| Linux | ~/.local/share/r-shell/workspace.json |
| Windows | %LOCALAPPDATA%\r-shell\workspace.json |
八、安装
源码编译
只需要 Rust 和 Cargo(rustup.rs),不需要 OpenSSL 或 libssh:
bash
git clone https://github.com/MageGojo/r-shell-cli.git
cd r-shell-cli
cargo build --release --manifest-path cli/Cargo.toml
sudo install -m 0755 cli/target/release/r-shell /usr/local/bin/r-shell
r-shell --version
不想装,直接跑也行:
bash
cargo run --manifest-path cli/Cargo.toml -- exec -c prod-web -- uptime
预编译包
懒得编译的话,Releases 里有现成的:
| 平台 | 文件 |
|---|---|
| macOS(Apple Silicon) | r-shell-macos-apple-silicon.dmg |
| macOS(Intel) | r-shell-macos-intel.dmg |
| Windows x64 | r-shell-windows-x64-installer.exe |
macOS 上把二进制拷进 PATH 后,记得清一下 Gatekeeper 隔离标记:xattr -dr com.apple.quarantine /usr/local/bin/r-shell;Windows 安装器会自动把 r-shell 加进 PATH。因为是没买付费证书的开源软件,首次打开时按系统提示放行即可。
九、顺带一提:它还有个桌面端
抛开命令行,同一套 core 还撑起了一个 Flutter 写界面的桌面应用:命令块终端(每条命令和它的输出各成一块,带退出码、耗时)、实时监控走势图、SFTP 拖拽、多标签管多台。CLI 适合脚本和远程会话,GUI 适合盯监控和翻历史,两者数据互通。
另外,
r-shell mcp还能起一个只绑127.0.0.1的本地 MCP 服务器,让支持 MCP 的工具借一条常驻 SSH 会话干活------那是另一个话题,本文不展开。
十、适合谁
- 运维 / DevOps :统一管理一堆服务器,批量
exec巡检、upload/download发版拉日志,把远程操作写进流水线。 - 后端开发 :快速连测试机执行命令、传安装包,不用每次拼一长串
ssh/scp。 - 想要零依赖单文件的人:不想在目标机上装一堆东西,拷一个二进制就能用。
- Rust 学习者 :
clap子命令树、russh的 SSH 编程、tokio异步 I/O、known_hosts校验、业务与界面解耦------都是能直接照着读的活例子。
如果你只管一两台机器,它是个顺手的 SSH 工具;如果你要管很多台并写自动化,它的连接管理和可脚本化会更值。
十一、开源与下载
r-shell 已开源(MIT),由 极数本源(apizero.cn)· MageGojo 出品:
觉得有用就去仓库点个 star。日常要在多台服务器之间跑命令、传文件、看负载的,可以拿它当一个轻量、安全、可脚本化的 SSH 工作台;在学 Rust 命令行开发的,也很适合作为源码阅读和二次开发的参考。
⚠️ 免责声明:本项目仅供学习与合法运维使用。SSH / 命令执行 / 文件读写均会对远程主机产生实际影响,使用者应自行确认操作对象与命令内容,并对重要数据做好备份。请仅在你拥有合法授权的主机上使用;使用本工具产生的一切后果由使用者自行承担。