# tsshd
**Repository Path**: trzsz/tsshd
## Basic Information
- **Project Name**: tsshd
- **Description**: 低延迟的 ssh,基于 UDP ( KCP ) 实现, 类似 mosh(比 mosh 多了端口转发)
- **Primary Language**: Go
- **License**: MIT
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 7
- **Forks**: 0
- **Created**: 2024-06-24
- **Last Updated**: 2026-07-21
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# tsshd: 基于 UDP、支持漫游与断线重连的 SSH 服务端
[](https://choosealicense.com/licenses/mit/)
[](https://github.com/trzsz/tsshd/releases)
[](https://trzsz.github.io/tsshd)
[](https://trzsz.github.io/cn/tsshd)
**tsshd** 是一个基于 UDP 的 SSH 服务器,专为不稳定网络环境设计,支持在网络切换或 IP 变化时无缝漫游,并能在高延迟链路(如蜂窝网络和不稳定的 Wi-Fi)上稳定工作。
**tsshd** 旨在与 OpenSSH 完全兼容,并提供额外能力:
- 客户端休眠、唤醒或临时网络中断时,SSH 会话仍可保持。
- 在网络切换或 IP 变化时无缝漫游,不会中断 SSH 会话。
- 支持 UDP 端口转发 ( LocalForward 和 RemoteForward )。
## 功能对比
**tsshd** 的灵感来源于 [mosh](https://github.com/mobile-shell/mosh),`tsshd` 类似于 `mosh-server`,而 `tssh --udp` 类似于 `mosh`。
| Feature | mosh ( mosh-server ) | tssh ( tsshd ) |
| -------------------- | :-----------------------------------------------------------: | :---------------------------------------: |
| 超低延迟 | ?? | ✅ [KCP](https://github.com/xtaci/kcp-go) |
| 保持连接 | ✅ | ✅ |
| 切换网络 | ✅ | ✅ |
| 本地回显 & 行编辑 | ✅ | 无支持计划 |
| 支持多平台 / Windows | [mosh#293](https://github.com/mobile-shell/mosh/issues/293) | ✅ |
| SSH X11 转发 | [mosh#41](https://github.com/mobile-shell/mosh/issues/41) | ✅ |
| SSH Agent 转发 | [mosh#120](https://github.com/mobile-shell/mosh/issues/120) | ✅ |
| SSH 端口转发 | [mosh#337](https://github.com/mobile-shell/mosh/issues/337) | ✅ |
| 输出上下滚动 | [mosh#122](https://github.com/mobile-shell/mosh/issues/122) | ✅ |
| OSC52 复制粘贴 | [mosh#637](https://github.com/mobile-shell/mosh/issues/637) | ✅ |
| ProxyJump | [mosh#970](https://github.com/mobile-shell/mosh/issues/970) | ✅ |
| tmux -CC 集成 | [mosh#1078](https://github.com/mobile-shell/mosh/issues/1078) | ✅ |
tssh 和 tsshd 的工作方式与 ssh 完全相同,没有计划支持本地回显和行编辑,也不会出现 mosh 的问题:[mosh#1041](https://github.com/mobile-shell/mosh/issues/1041)、[mosh#1281](https://github.com/mobile-shell/mosh/issues/1281)、[mosh#1295](https://github.com/mobile-shell/mosh/issues/1295) 等。
## 如何使用
1. 在客户端(本地电脑)上安装 [tssh](https://github.com/trzsz/trzsz-ssh?tab=readme-ov-file#installation)。
2. 在服务端(远程机器)上安装 [tsshd](https://github.com/trzsz/tsshd?tab=readme-ov-file#installation)。
3. 使用 `tssh --udp xxx` 登录服务器,用法与标准 SSH 保持一致。
- 对延迟敏感的用户可以指定 `--kcp` 选项。
- 可在 `~/.ssh/config` 中进行如下配置,以省略手动指定 `--udp` 或 `--kcp` 选项:
```
Host xxx
#!! UdpMode ( yes | QUIC | KCP )
```
## 原理简介
- `tssh` 在客户端扮演 `ssh` 的角色,`tsshd` 在服务端扮演 `sshd` 的角色。
- `tssh` 会先作为一个 ssh 客户端正常登录到服务器上,然后在服务器上启动一个 `tsshd` 进程(每次登录都是一个独立的 `tsshd` 进程)。
- `tsshd` 进程会随机侦听一个 61001 到 61999 之间的 UDP 端口(可通过 `TsshdPort` 配置自定义),并将其端口和几个密钥通过 ssh 通道发回给 `tssh` 进程。登录的 ssh 连接会被关闭,然后 `tssh` 进程通过 UDP 与 `tsshd` 进程通讯。
## 安装方法
- Ubuntu 可用 apt 安装
sudo apt install tsshd
```sh
sudo apt update && sudo apt install software-properties-common
sudo add-apt-repository ppa:trzsz/ppa && sudo apt update
sudo apt install tsshd
```
- Debian 可用 apt 安装
sudo apt install tsshd
```sh
sudo apt install curl gpg
curl -s 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x7074ce75da7cc691c1ae1a7c7e51d1ad956055ca' \
| gpg --dearmor -o /usr/share/keyrings/trzsz.gpg
echo 'deb [signed-by=/usr/share/keyrings/trzsz.gpg] https://ppa.launchpadcontent.net/trzsz/ppa/ubuntu jammy main' \
| sudo tee /etc/apt/sources.list.d/trzsz.list
sudo apt update
sudo apt install tsshd
```
- Fedora / CentOS / RHEL 可用 dnf 安装
sudo dnf install tsshd
```sh
sudo dnf copr enable @trzsz/trzsz
sudo dnf install tsshd
```
- 传统版本 CentOS / RHEL 可用 yum 安装
sudo yum install tsshd
- 国内推荐使用 [wlnmp](https://www.wlnmp.com/install) 源,安装 tsshd 只需要添加 wlnmp 源( 配置 epel 源不是必须的 ):
```sh
curl -fsSL "https://sh.wlnmp.com/wlnmp.sh" | bash
sudo yum install tsshd
```
- 也可使用 [gemfury](https://gemfury.com/) 源( 只要网络通,所有操作系统通用 )
```sh
echo '[trzsz]
name=Trzsz Repo
baseurl=https://yum.fury.io/trzsz/
enabled=1
gpgcheck=0' | sudo tee /etc/yum.repos.d/trzsz.repo
sudo yum install tsshd
```
- ArchLinux 可用 yay 安装
yay -S tsshd
```sh
yay -Syu
yay -S tsshd
```
- MacOS 可用 Homebrew 安装
brew install tsshd
```sh
brew install tsshd
```
- Windows 可用 scoop 安装
scoop install tsshd
```sh
scoop bucket add extras
scoop install tsshd
```
需要允许 `C:\Users\\scoop\apps\tsshd\\tsshd.exe` 通过防火墙,才能正常使用。
- 用 pixi / conda / mamba 从 [conda-forge](https://github.com/conda-forge/tsshd-feedstock) 安装
pixi global install tsshd / conda install tsshd / mamba install tsshd
```sh
pixi global install tsshd
```
```sh
conda install -c conda-forge tsshd
```
```sh
mamba install -c conda-forge tsshd
```
- 用 Go 直接安装( 要求 go 1.25 以上 )
go install github.com/trzsz/tsshd/cmd/tsshd@latest
```sh
# 最新发布版本
go install github.com/trzsz/tsshd/cmd/tsshd@latest
# 最新开发版本( main 分支 )
go install github.com/trzsz/tsshd/cmd/tsshd@main
```
安装后,`tsshd` 程序一般位于 `~/go/bin/` 目录下( Windows 一般在 `C:\Users\your_name\go\bin\` )。
- 用 Go 自己编译( 要求 go 1.25 以上 )
sudo make install
```sh
git clone --depth 1 https://github.com/trzsz/tsshd.git
cd tsshd
make
sudo make install
```
- 可从 [GitHub Releases](https://github.com/trzsz/tsshd/releases) 或 [Pre-Release](https://github.com/trzsz/tsshd/releases/tag/dev) 中下载,国内可从 [Gitee 发行版](https://gitee.com/trzsz/tsshd/releases) 中下载,然后本地安装。
下载并本地安装
```sh
sudo apt install /tmp/tsshd_*.deb
sudo dpkg -i /tmp/tsshd_*.deb
sudo dnf install /tmp/tsshd_*.rpm
sudo yum install /tmp/tsshd_*.rpm
sudo rpm -i /tmp/tsshd_*.rpm
tar zxvf tsshd_*.tar.gz && sudo cp tsshd_*/tsshd /usr/bin/
```
## 支持终端
以下客户端或终端支持 `tsshd` 服务端:
- [trzsz-ssh](https://github.com/trzsz/trzsz-ssh) ( tssh ) – 一款用 Go 实现,可直接替代 OpenSSH 客户端的 SSH 客户端。
- [rootshell](https://github.com/kitknox/rootshell) - 一款支持 iPhone、iPad、Vision Pro 和 Mac 平台的免费终端模拟器。
## 重连架构
```
┌───────────────────────┐ ┌───────────────────────┐
│ │ │ │
│ tssh (process) │ │ tsshd (process) │
│ │ │ │
│ ┌───────────────────┐ │ │ ┌───────────────────┐ │
│ │ │ │ │ │ │ │
│ │ KCP/QUIC Client │ │ │ │ KCP/QUIC Server │ │
│ │ │ │ │ │ │ │
│ └───────┬───▲───────┘ │ │ └───────┬───▲───────┘ │
│ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │
│ ┌───────▼───┴───────┐ │ │ ┌───────▼───┴───────┐ │
│ │ ├─┼────────────────┼─► │ │
│ │ Client Proxy │ │ │ │ Server Proxy │ │
│ │ ◄─┼────────────────┼─┤ │ │
│ └───────────────────┘ │ │ └───────────────────┘ │
└───────────────────────┘ └───────────────────────┘
```
- 客户端 `KCP/QUIC Client` 和 `Client Proxy` 在同一台机同一个进程内,它们之间的连接不会断。
- 服务端 `KCP/QUIC Server` 和 `Server Proxy` 在同一台机同一个进程内,它们之间的连接不会断。
- 客户端较长时间没收到服务端的心跳包时,可能是因为网络变化导致原连接失效了,则由 `Client Proxy` 重新建一个到 `Server Proxy` 的连接,认证通过后就使用新连接进行通讯。在 `KCP/QUIC Client` 和 `KCP/QUIC Server` 看来,连接从来没有断开过。
## 安全模型
- `Client Proxy` 与 `KCP/QUIC Client` 运行在客户端同一进程内,`Server Proxy` 与 `KCP/QUIC Server` 也运行在服务器的同一进程内,两个 `Proxy` 均实现了 `net.PacketConn` 接口,数据在内存中直接传递,不经过本地网络协议栈,从而降低被本地其他进程窃听或注入的风险。
- `Server Proxy` 只接受来自认证过的客户端地址的报文。如果客户端因网络变化从新的 IP 或端口重新连接,必须重新完成认证。认证成功后,新地址将替换旧地址,来自旧地址的报文将被忽略。
- `Client Proxy` 在首次连接或重新连接时,需要发送使用 **AES-256-GCM** 加密的认证报文。认证密钥由服务器在 SSH 登录阶段生成,并通过 SSH 安全通道传输给客户端。
- `Server Proxy` 校验客户端 ID,并确保认证序列号严格单调递增,即新序列号必须大于系统历史上所有已接收的认证序列号,以防止重放攻击。验证通过后,服务器将客户端地址标记为已认证,并返回加密的认证确认报文。
- 客户端与服务器之间使用 [kcp-go](https://github.com/xtaci/kcp-go) 或 [quic-go](https://github.com/quic-go/quic-go) 进行端到端加密通信。QUIC 使用 **TLS 1.3** 作为安全协议基础,确保通信数据的机密性和完整性,并支持连接生命周期内的密钥更新机制。KCP 实现自定义密钥轮换机制,周期性更新加密密钥以提供前向安全性,确保通信始终保持端到端加密。
## 配置说明
### Server 配置 (tsshd)
- 默认情况下,tsshd 会复用 OpenSSH 的配置(默认路径 `/etc/ssh/sshd_config`),以尽可能保持与 OpenSSH 一致的行为。
- 如果存在 `$XDG_CONFIG_HOME/tsshd/sshd_config`(默认 `~/.config/tsshd/sshd_config`),tsshd 会优先使用它(即使文件为空)。
### Client 配置 (tssh)
```
Host xxx
#!! UdpMode yes
#!! TsshdPort 61001-61999
#!! TsshdPath ~/go/bin/tsshd
#!! UdpAliveTimeout 1w3d
#!! UdpHeartbeatTimeout 3
#!! UdpReconnectTimeout 15
#!! UdpReconnectExitKey ^d
#!! ShowNotificationOnTop yes
#!! ShowFullNotifications yes
#!! UdpProxyMode UDP
#!! UdpMTU 1400
#!! UdpSessionAttach no
#!! UdpSessionName xxx
```
- `UdpMode`: `no` (默认为`no`: tssh 工作在 TCP 模式), `yes` (默认协议: `QUIC`), `QUIC` ([QUIC](https://github.com/quic-go/quic-go) 协议:速度更快), `KCP` ([KCP](https://github.com/xtaci/kcp-go) 协议:延迟更低).
- `TsshdPort`: 指定 tsshd 监听的端口范围,默认值为 [61001, 61999]。支持指定离散的端口列表(如`6022,7022`),也支持指定离散的端口范围(如`8010-8020,9020-9030,10080`),tsshd 会随机监听其中一个空闲的端口。也可在命令行中使用 `--tsshd-port` 指定端口。
- `TsshdPath`: 指定服务器上 tsshd 二进制程序的路径,如果未配置,则在 $PATH 中查找。也可在命令行中使用 `--tsshd-path` 指定路径。
- `UdpAliveTimeout`: 如果断开连接的时间超过 `UdpAliveTimeout` 设置的时间,tssh 和 tsshd 都会退出,不再支持重连。支持的单位:`w` 周, `d` 天,`h` 时,`m` 分,`s` 秒。默认值为 `1w3d` (10天)。
- `UdpHeartbeatTimeout`: 如果断开连接的时间超过 `UdpHeartbeatTimeout` 设置的时间,tssh 将会尝试换条路重新连到服务器。默认值为 3 秒。
- `UdpReconnectTimeout`: 如果断开连接的时间超过 `UdpReconnectTimeout` 设置的时间,tssh 将会显示失去连接的通知公告。默认值为 15 秒。
- `UdpReconnectExitKey`: 指定在断开连接并尝试重连时,用于退出(或脱离)等待状态的快捷键。支持的值包括 `none`、`ctrl+<字母>` 和 `^<字母>`。默认值为 `^d`(即 Ctrl+D)。
- `ShowNotificationOnTop`: 是否在屏幕顶部显示失去连接的通知。默认为 yes,这可能会覆盖之前的一些输出。设置为 `no` 在光标当前行显示通知。
- `ShowFullNotifications`: 是显示完整的通知,还是显示简短的通知。默认为 yes,这可能会输出几行通知到屏幕上。设置为 `no` 只输出一行通知。
- `UdpProxyMode`: 默认使用 `UDP` 协议进行传输。如果所在的网络环境有防火墙禁止了 `UDP` 流量,可以配置为 `TCP` 以绕过防火墙限制,但这可能会带来额外的延迟。
- `UdpMTU`: 设置 UDP 数据包的最大传输单元(MTU),默认值为 1400。
- `UdpSessionAttach`: 默认为 `no`。配置为 `yes` 时,允许附加到服务器上已存在的会话;同时,本次登录的会话也会运行在可附加模式下,支持后续在其他设备或网络下重新登录时附加。
- `UdpSessionName`: 自定义会话名称。仅在 `UdpSessionAttach` 配置为 `yes` 或通过 `--attach` 参数登录时生效。若服务器端已存在该名称的会话,将直接附加;若不存在,则以此名称创建新会话,供后续登录时自动附加。
## UDP 端口转发
使用 tssh 作为客户端时,支持 UDP 端口转发。
- 命令行 UDP 端口转发,扩展 `-L` / `-R` 参数,增加 `udp/` 前缀 ( 其中 `/` 可以换成 `:`、`_` 或 `-` ):
```
-L udp/[bind_address:]port:host:hostport
-L udp:[bind_address:]port:/remote_socket
-L udp_/local_socket:host:hostport
-L udp-/local_socket:/remote_socket
-R udp/[bind_address:]port:host:hostport
-R udp:[bind_address:]port:/local_socket
-R udp_/remote_socket:host:hostport
-R udp-/remote_socket:/local_socket
```
- 配置文件 UDP 端口转发,类似 `LocalForward` 和 `RemoteForward`,增加 `UDP` 前缀 (不区分大小写):
```
UdpLocalForward [bind_address:]port host:hostport
UdpLocalForward [bind_address:]port /remote_socket
UdpLocalForward /local_socket host:hostport
UdpLocalForward /local_socket /remote_socket
UdpRemoteForward [bind_address:]port host:hostport
UdpRemoteForward [bind_address:]port /local_socket
UdpRemoteForward /remote_socket host:hostport
UdpRemoteForward /remote_socket /local_socket
```
- `ForwardUdpTimeout`: 设置 UDP 转发会话的空闲超时时间。在指定时间内无数据收发时将自动清理对应的转发会话以释放资源。默认 5 分钟。
## 开发者指南:构建自定义 SSH 服务
**tsshd** 不仅仅是一个二进制程序,它还是一个强大的框架,允许你构建具有 **无缝漫游** 和 **低延迟** 能力的自定义 SSH 应用。
### A. 快速开始:自定义业务逻辑
你可以通过 `tsshd` 提供的中间件机制,轻松地在 SSH 会话中注入自己的交互逻辑。
```go
func main() {
// 使用 tsshd.RunMain 作为入口,并注入自定义中间件
code, err := tsshd.RunMain(
tsshd.WithMiddleware(func(next tsshd.Handler) tsshd.Handler {
return func(sess tsshd.Session) {
term := term.NewTerminal(sess, "输入你的名字: ")
name, _ := term.ReadLine()
fmt.Fprintf(sess, "你好, %s!这是一个支持漫游的自定义 SSH 服务。\r\n", name)
}
}),
)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
}
os.Exit(code)
}
```
**运行原理:**
1. **OpenSSH 引导**:当客户端使用 `tssh --udp` 连接时,它首先通过标准 SSH 协议登录。
2. **拉起进程**:OpenSSH 会在服务端拉起你编写的这个二进制程序。
3. **协议切换**:该程序启动后监听随机 UDP 端口,并将密钥返回给客户端,随后客户端切换到 QUIC/KCP 协议与该程序直接通信。
> **注意**:如果你的程序不在 `PATH` 中,请在客户端配置 `TsshdPath` 或使用 `--tsshd-path` 指定路径。
### B. 高级进阶:使用 Wish 构建集成化服务器
如果你不想依赖系统自带的 OpenSSH 来拉起进程,或者想构建一个纯粹的、单文件的自定义 SSH 服务器,可以将 [Wish](https://github.com/charmbracelet/wish)(基于 [gliderlabs/ssh](https://github.com/gliderlabs/ssh))与 `tsshd` 结合。
这种模式下,你的程序可以同时扮演两个角色:
- **常规 SSH 服务器 (TCP)**:监听 22 或自定义端口,处理初始登录。
- **tsshd 服务器 (UDP)**:处理漫游、重连和低延迟传输。
#### 核心设计思路:适配器模式
为了让业务逻辑(如终端交互)在 Wish 和 `tsshd` 之间复用,你可以通过定义统一的 `Session` 接口来屏蔽底层差异:
```go
// 统一 Session 接口,让业务逻辑在 Wish(TCP) 和 tsshd(UDP) 之间通用
type Session = tsshd.Session
func handleBusiness(sess Session) {
fmt.Fprintf(sess, "当前会话类型: %T\r\n", sess)
// 编写你的业务逻辑...
}
```
#### 会话接管 (Process Handoff)
当 Wish 接收到客户端发出的启动 `tsshd` 指令时,你可以通过 `exec.Command` 重新执行当前的二进制文件(带上 `tsshd` 参数),实现从“标准 SSH 握手”到“UDP 低延迟传输”的无缝切换:
1. **检测指令**:在 Wish 中间件中捕获客户端执行 `tsshd` 的请求。
2. **二次启动**:在服务端本地启动一个子进程(当前程序的 tsshd 模式)。
3. **环境继承**:将当前的连接信息(如 `SSH_CONNECTION`)传递给子进程。
### C. 为什么选择这种架构?
- **开发效率**:利用 Go 语言生态,像写 Web 中间件一样编写 SSH 服务。
- **混合部署**:将客户端 (`tssh`) 和服务端 (`tsshd`) 逻辑打包进同一个二进制文件,简化分发。
- **极致体验**:用户既能享受传统 SSH 的安全性,又能获得在高延迟、网络切换环境下的丝滑体验(断线自动重连)。
### D. 示例代码 (Examples)
为了帮助您快速上手,我们在 [`examples/`](https://github.com/trzsz/tsshd/tree/main/examples) 目录下提供了完整可运行的示例代码。您可以将这些示例作为构建自定义 SSH 服务的模板。
- **[examples/hello](https://github.com/trzsz/tsshd/tree/main/examples/hello)**
最基础的实现。它演示了如何使用 `tsshd.WithMiddleware` 拦截 SSH 会话,打印欢迎信息,并使用 `term` 包读取用户输入。非常适合用于构建交互式 CLI 工具。
- **[examples/sshd](https://github.com/trzsz/tsshd/tree/main/examples/sshd)**
一个更全面的示例,展示了如何处理实际的命令执行。它演示了如何正确路由 PTY(交互式)和 Direct(批处理)执行流,处理终端窗口大小调整,以及将标准 I/O 直接流式传输到本地子进程。
- **[examples/wish](https://github.com/trzsz/tsshd/tree/main/examples/wish)**
上述**混合架构**的完整展示。它实现了适配器模式以统一 `Session` 接口,允许相同的业务逻辑在传统的 TCP SSH 服务器(Wish)和低延迟的 UDP `tsshd` 服务器之间无缝运行,并包含完整的进程切换(Handoff)机制。
> **提示**:您可以在本地运行这些示例,并使用 `tssh` 客户端进行测试,以亲身体验低延迟和漫游功能!
## 屏幕截图


## 联系方式
有什么问题可以发邮件给作者 ,也可以提 [Issues](https://github.com/trzsz/tsshd/issues) 。欢迎加入 QQ 群:318578930。
## 赞助打赏
[❤️ 赞助 trzsz ❤️](https://github.com/trzsz),请作者喝杯咖啡 ☕ ? 谢谢您们的支持!