前言

在得知该开源项目以前,我自己就遇到过这方面的需求:

  • 在 CI/CD 执行过程中,进入 Gitlab Runner 进行 Debug (项目中有 Github Action 的示例)
  • 在团队中协助成员完成一些终端操作 (这个需求可能对于 IT Administrator 感触比较深)

介绍

SSHX 是一款基于 Rust 开发的命令行协作工具,支持多人同时在线协作,使用起来也非常简单,SSHX 的主要功能如下:

  • 跨平台
  • 简单小巧
  • 端到端加密
  • 支持多终端
  • 全球网络优化
  • 支持即使通讯
  • 实时显示人员名称和鼠标位置

安装

# 使用安装脚本
curl -sSf https://sshx.io/get | sh

# 或从源码安装
cargo install sshx

使用

分享你的终端给他人:

sshx

  sshx v0.2.1

  ➜  Link:  https://sshx.io/s/dStBgdqp7V#GvmVDg46h40BRz
  ➜  Shell: /bin/zsh

启动后,将生成的链接分享给他人即可,其他人可以基于 Web 在你的终端中进行交互。

首次进入的,需要录入名称:

Join

成员加入后: Joined

Web UI 顶部的工具栏中依次是 Logo、新建终端、Chat、设置和网络状态。

Self-hosted

虽然官方的服务体验还算不错,但是有时候网络抖动还是比较大的,我这边测试的时候网络延迟基本在 ~350ms 左右。

于是我萌生了自建 Server 端的想法,看了一下项目的大致结构,没有提供 docker-compose.yaml 但是有 Dockerfile,那就好办了!

对于想要在内网使用,或者想自建 Server 节点的,可以 Clone 源码,并构建自己的 Docker image。

gh repo clone ekzhang/sshx
cd sshx
docker build -t sshx:latest .

本以为构建完成后,没想到还有两个坑再等着我。

第一个问题是因为端到端加密使用了浏览器提供的 crypto.subtle 接口,如果不满足条件则会导致 JS 执行报错:

crypto.subtle.importKey TypeError: Cannot read properties of undefined

经过一番搜索,发现要使用 crypto.subtle 接口需要满足如下条件中的一个:

  • 在安全的上下文中运行,也就是必须使用 HTTPS 提供服务
  • 使用 HTTP 提供服务,但是域名只能是 localhost

找到问题就好办了,于是我用 mkcert 生成了 sshx.test 域名的自签名证书,并使用 Traefik 做的反向代理,具体 docker-compose.yaml 配置如下:

services:
  sshx:
    image: betterde/sshx:latest
    labels:
      - traefik.enable=true

      - traefik.http.services.sshx.loadbalancer.server.port=8051

      - traefik.http.routers.sshx.tls=true
      - traefik.http.routers.sshx.rule=Host(`sshx.test`)
      - traefik.http.routers.sshx.service=sshx
      - traefik.http.routers.sshx.entrypoints=http,https

    restart: always
    hostname: sshx
    networks:
      - traefik
    command: ["./sshx-server", "--port", "8051", "--listen", "::", "--override-origin", "https://sshx.test"]
    environment:
      - SSHX_SECRET=mylOHBgeQYBnEGkMiY25Q4wEr7Fa7i33
      - SSHX_REDIS_URL=redis://redis:6379
    container_name: sshx

networks:
  traefik:
    external: true

启动服务端:

docker compose up -d

[+] Building 0.0s (0/0)                                                            docker:orbstack
[+] Running 1/0
 ✔ Container sshx  Running

启动客户端:

sshx --server https://sshx.test
2023-11-30T07:16:31.704375Z ERROR sshx: transport error

Caused by:
    0: error trying to connect: invalid peer certificate: UnknownIssuer
    1: invalid peer certificate: UnknownIssuer

从错误提示可以看得出是 CA 证书的问题,于是去该项目代码仓扒一扒 Issue,让我找到了这个 Issue。但作者表示暂时没有这方面的打算,那我们就自行替换 CA 然后手动编译客户端。

使用下面命令替换 Cargo.toml 中的 tls-webpki-rootstls-roots:

# linux
sed -i 's/tls-webpki-roots/tls-roots/g' ./Cargo.toml
# macOS 略微不同,需要在 -i 后 指定备份文件名称,我们这里不需要备份,所以是 ''
sed -i '' 's/tls-webpki-roots/tls-roots/g' ./Cargo.toml

编译 SSHX 客户端:

cargo build --release --bin sshx
    Updating crates.io index
  Downloaded http-range-header v0.3.1
  Downloaded itoa v1.0.9
  Downloaded mime_guess v2.0.4
  Downloaded matchit v0.7.2
  Downloaded async-trait v0.1.73
  Downloaded anstyle v1.0.2
  Downloaded clap v4.4.2
  Downloaded password-hash v0.5.0
  Downloaded jobserver v0.1.26
  Downloaded bitflags v2.4.0
  Downloaded ciborium-io v0.2.1
  Downloaded petgraph v0.6.4
  Downloaded async-channel v1.9.0
  Downloaded rustls-webpki v0.101.4
  Downloaded tokio-tungstenite v0.20.0
  Downloaded clap_builder v4.4.2
  Downloaded pin-project v1.1.3
  Downloaded cipher v0.4.4
  Downloaded sha1_smol v1.0.0
  Downloaded ctr v0.9.2
  Downloaded axum-core v0.3.4
  Downloaded blake2 v0.10.6
  Downloaded proc-macro2 v1.0.66
  Downloaded axum v0.6.20
  Downloaded h2 v0.3.21
  Downloaded syn v2.0.31
  Downloaded zstd v0.12.4
  Downloaded regex-automata v0.3.8
  Downloaded encoding_rs v0.8.33
  Downloaded which v4.4.2
  Downloaded url v2.4.1
  Downloaded zstd-sys v2.0.8+zstd.1.5.5
  Downloaded unicase v2.7.0
  Downloaded slab v0.4.9
  Downloaded serde_path_to_error v0.1.14
  Downloaded scopeguard v1.2.0
  Downloaded quote v1.0.33
  Downloaded pin-project-internal v1.1.3
  Downloaded tokio v1.32.0
  Downloaded nix v0.27.1
  Downloaded regex-syntax v0.7.5
  Downloaded tower-http v0.4.4
  Downloaded regex v1.9.5
  Downloaded aho-corasick v1.0.5
  Downloaded serde_json v1.0.106
  Downloaded webpki-roots v0.23.1
  Downloaded rustls-webpki v0.100.3
  Downloaded bytes v1.5.0
  Downloaded socket2 v0.5.3
  Downloaded serde v1.0.188
  Downloaded ryu v1.0.15
  Downloaded rustls v0.21.7
  Downloaded security-framework v2.9.2
  Downloaded unicode-ident v1.0.11
  Downloaded concurrent-queue v2.2.0
  Downloaded tempfile v3.8.0
  Downloaded utf-8 v0.7.6
  Downloaded sha1 v0.10.5
  Downloaded either v1.9.0
  Downloaded tonic-reflection v0.10.0
  Downloaded prost-derive v0.12.0
  Downloaded prost v0.12.0
  Downloaded tonic-build v0.10.0
  Downloaded prost-types v0.12.0
  Downloaded tonic v0.10.0
  Downloaded errno v0.3.3
  Downloaded fastrand v2.0.0
  Downloaded pin-project-lite v0.2.13
  Downloaded serde_derive v1.0.188
  Downloaded deadpool-redis v0.13.0
  Downloaded clap_lex v0.5.1
  Downloaded zstd-safe v6.0.6
  Downloaded smallvec v1.11.0
  Downloaded redis v0.23.3
  Downloaded thiserror-impl v1.0.48
  Downloaded inout v0.1.3
  Downloaded ciborium-ll v0.2.1
  Downloaded equivalent v1.0.1
  Downloaded anstream v0.5.0
  Downloaded sync_wrapper v0.1.2
  Downloaded rustversion v1.0.14
  Downloaded pkg-config v0.3.27
  Downloaded log v0.4.20
  Downloaded prettyplease v0.2.15
  Downloaded security-framework-sys v2.9.1
  Downloaded deadpool-runtime v0.1.3
  Downloaded dashmap v5.5.3
  Downloaded itertools v0.11.0
  Downloaded thiserror v1.0.48
  Downloaded num_cpus v1.16.0
  Downloaded deadpool v0.10.0
  Downloaded close_fds v0.3.2
  Downloaded rustls-pemfile v1.0.3
  Downloaded base64ct v1.6.0
  Downloaded cpufeatures v0.2.9
  Downloaded clap_derive v4.4.2
  Downloaded argon2 v0.5.2
  Downloaded home v0.5.5
  Downloaded hyper v0.14.27
  Downloaded memchr v2.6.3
  Downloaded tungstenite v0.20.0
  Downloaded combine v4.6.6
  Downloaded ciborium v0.2.1
  Downloaded prost-build v0.12.0
  Downloaded httpdate v1.0.3
  Downloaded anyhow v1.0.75
  Downloaded cc v1.0.83
  Downloaded event-listener v2.5.3
  Downloaded base64 v0.21.4
  Downloaded aes v0.8.3
  Downloaded rustix v0.38.12
  Downloaded 111 crates (10.1 MB) in 3.06s (largest was `encoding_rs` at 1.4 MB)
   Compiling libc v0.2.147
   Compiling proc-macro2 v1.0.66
   Compiling unicode-ident v1.0.11
   Compiling cfg-if v1.0.0
   Compiling autocfg v1.1.0
   Compiling serde v1.0.188
   Compiling pin-project-lite v0.2.13
   Compiling version_check v0.9.4
   Compiling typenum v1.16.0
   Compiling parking_lot_core v0.9.8
   Compiling log v0.4.20
   Compiling smallvec v1.11.0
   Compiling futures-core v0.3.28
   Compiling generic-array v0.14.7
   Compiling lock_api v0.4.10
   Compiling scopeguard v1.2.0
   Compiling itoa v1.0.9
   Compiling once_cell v1.18.0
   Compiling anyhow v1.0.75
   Compiling slab v0.4.9
   Compiling futures-sink v0.3.28
   Compiling futures-task v0.3.28
   Compiling either v1.9.0
   Compiling tracing-core v0.1.31
   Compiling quote v1.0.33
   Compiling futures-util v0.3.28
   Compiling fnv v1.0.7
   Compiling syn v2.0.31
   Compiling itertools v0.11.0
   Compiling subtle v2.5.0
   Compiling pin-utils v0.1.0
   Compiling rustversion v1.0.14
   Compiling indexmap v1.9.3
   Compiling rustix v0.38.12
   Compiling num_cpus v1.16.0
   Compiling parking_lot v0.12.1
   Compiling signal-hook-registry v1.4.1
   Compiling mio v0.8.8
   Compiling socket2 v0.5.3
   Compiling getrandom v0.2.10
   Compiling crypto-common v0.1.6
   Compiling jobserver v0.1.26
   Compiling rand_core v0.6.4
   Compiling block-buffer v0.10.4
   Compiling httparse v1.8.0
   Compiling cc v1.0.83
   Compiling tinyvec_macros v0.1.1
   Compiling digest v0.10.7
   Compiling tinyvec v1.6.0
   Compiling errno v0.3.3
   Compiling bitflags v2.4.0
   Compiling hashbrown v0.12.3
   Compiling ppv-lite86 v0.2.17
   Compiling percent-encoding v2.3.0
   Compiling form_urlencoded v1.2.0
   Compiling rand_chacha v0.3.1
   Compiling cpufeatures v0.2.9
   Compiling unicode-bidi v0.3.13
   Compiling regex-syntax v0.7.5
   Compiling untrusted v0.7.1
   Compiling unicode-normalization v0.1.22
   Compiling thiserror v1.0.48
   Compiling equivalent v1.0.1
   Compiling tower-service v0.3.2
   Compiling heck v0.4.1
   Compiling hashbrown v0.14.0
   Compiling ring v0.16.20
   Compiling bytes v1.5.0
   Compiling prettyplease v0.2.15
   Compiling futures-channel v0.3.28
   Compiling idna v0.4.0
   Compiling indexmap v2.0.0
   Compiling rand v0.8.5
   Compiling fastrand v2.0.0
   Compiling home v0.5.5
   Compiling regex-automata v0.3.8
   Compiling async-trait v0.1.73
   Compiling core-foundation-sys v0.8.4
   Compiling fixedbitset v0.4.2
   Compiling try-lock v0.2.4
   Compiling tempfile v3.8.0
   Compiling petgraph v0.6.4
   Compiling want v0.3.1
   Compiling url v2.4.1
   Compiling which v4.4.2
   Compiling axum-core v0.3.4
   Compiling sha1 v0.10.5
   Compiling socket2 v0.4.9
   Compiling base64 v0.21.4
   Compiling utf-8 v0.7.6
   Compiling regex v1.9.5
   Compiling ryu v1.0.15
   Compiling serde_json v1.0.106
   Compiling rustls v0.21.7
   Compiling serde_derive v1.0.188
   Compiling tokio-macros v2.1.0
   Compiling tracing-attributes v0.1.26
   Compiling futures-macro v0.3.28
   Compiling prost-derive v0.12.0
   Compiling thiserror-impl v1.0.48
   Compiling pin-project-internal v1.1.3
   Compiling multimap v0.8.3
   Compiling data-encoding v2.4.0
   Compiling httpdate v1.0.3
   Compiling bitflags v1.3.2
   Compiling byteorder v1.4.3
   Compiling tower-layer v0.3.2
   Compiling pin-project v1.1.3
   Compiling tracing v0.1.37
   Compiling core-foundation v0.9.3
   Compiling security-framework-sys v2.9.1
   Compiling prost v0.12.0
   Compiling axum v0.6.20
   Compiling mime v0.3.17
   Compiling prost-types v0.12.0
   Compiling utf8parse v0.2.1
   Compiling security-framework v2.9.2
   Compiling anstyle-parse v0.2.1
   Compiling async-stream-impl v0.3.5
   Compiling rustls-pemfile v1.0.3
   Compiling inout v0.1.3
   Compiling anstyle v1.0.2
   Compiling colorchoice v1.0.0
   Compiling matchit v0.7.2
   Compiling lazy_static v1.4.0
   Compiling anstyle-query v1.0.0
   Compiling memchr v2.6.3
   Compiling regex-syntax v0.6.29
   Compiling prost-build v0.12.0
   Compiling sync_wrapper v0.1.2
   Compiling rustls-webpki v0.101.4
   Compiling sct v0.7.0
   Compiling tonic-build v0.10.0
   Compiling anstream v0.5.0
   Compiling sshx-core v0.2.1 (/Users/George/Develop/Rust/sshx/crates/sshx-core)
   Compiling regex-automata v0.1.10
   Compiling async-stream v0.3.5
   Compiling rustls-native-certs v0.6.3
   Compiling cipher v0.4.4
   Compiling base64ct v1.6.0
   Compiling clap_lex v0.5.1
   Compiling serde_path_to_error v0.1.14
   Compiling serde_urlencoded v0.7.1
   Compiling strsim v0.10.0
   Compiling tokio v1.32.0
   Compiling http v0.2.9
   Compiling http-body v0.4.5
   Compiling tungstenite v0.20.0
   Compiling overload v0.1.1
   Compiling nu-ansi-term v0.46.0
   Compiling clap_builder v4.4.2
   Compiling password-hash v0.5.0
   Compiling tokio-util v0.7.8
   Compiling h2 v0.3.21
   Compiling tower v0.4.13
   Compiling tokio-io-timeout v1.2.0
   Compiling tokio-tungstenite v0.20.0
   Compiling tokio-stream v0.1.14
   Compiling tokio-rustls v0.24.1
   Compiling matchers v0.1.0
   Compiling tracing-log v0.1.3
   Compiling sharded-slab v0.1.4
   Compiling clap_derive v4.4.2
   Compiling blake2 v0.10.6
   Compiling thread_local v1.1.7
   Compiling tracing-subscriber v0.3.17
   Compiling nix v0.27.1
   Compiling argon2 v0.5.2
   Compiling aes v0.8.3
   Compiling ctr v0.9.2
   Compiling close_fds v0.3.2
   Compiling encoding_rs v0.8.33
   Compiling ansi_term v0.12.1
   Compiling clap v4.4.2
   Compiling hyper v0.14.27
   Compiling hyper-timeout v0.4.1
   Compiling tonic v0.10.0
   Compiling sshx v0.2.1 (/Users/George/Develop/Rust/sshx/crates/sshx)
    Finished release [optimized] target(s) in 35.27s

将编译好的客户端可执行文件放到 /usr/local/bin 目录,并启动:

sudo mv target/release/sshx /usr/local/bin/
sshx --server https://sshx.test

  sshx v0.2.1

  ➜  Link:  https://sshx.test/s/ynl7pSGppb#MYnh4yeL3LVdTn
  ➜  Shell: /bin/zsh

在浏览器里打开链接后,可以看到网络延迟 4ms,用户体验又上升了一个台阶:

Network Status

在内部使用,让需要远程协助的人下载你打包好的客户端并执行命令即可!

总结

在过去,我多次遇到帮助他人调试 CLI 中的错误,而每个人的习惯是不同的,例如:用的屏幕、键盘等,SSHX 则避免了这些问题。

同时也避免了一些尴尬,如:

  • 例如看到对方不该看的内容
  • 操作中多次需要对方输入密码

有了 SSHX 以后,降低了沟通成本,提高了协作效率!

I hope this is helpful, Happy hacking…