Open-source project
trzsz/tsshd avatar
trzsz/tsshd

tsshd: keeping an SSH session alive when the network underneath it moves

tsshd is a UDP-based SSH server built for unreliable networks. It supports seamless roaming across networks and IP changes, and works well on high-latency links such as cellular connections and unstable Wi-Fi.

554 stars24 forksGoMIT

At a glance

What is it?
tsshd is a UDP based SSH server from the trzsz project that hands a session off from a normal SSH connection to a UDP port, so a session survives an IP change or a dropped link. It is OpenSSH compatible in the ways that matter and deliberately not a mosh clone, and the client side tssh is a separate project you also need.
Who is it for?
tsshd suits a developer working over cellular links or flaky Wi-Fi who keeps losing an SSH session to an address change and needs the OpenSSH feature set rather than a terminal multiplexer, and it does not suit a server that must stay reachable only over TCP or a team that cannot install the tssh client on every workstation.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem is a session that outlives its IP address

A normal SSH session is bound to the address it was opened from. When a laptop moves between a wired network and Wi-Fi, or a phone switches from one cell tower to the next, the TCP connection that carried the session is gone, and with it the shell, the running process and whatever you were typing. Reconnecting is a fresh login, not a resumed one.

tsshd addresses that directly. The project describes itself as a UDP based SSH server built for unreliable networks, and the three capabilities it lists are all consequences of that. It survives sleep, wake and temporary network loss. It roams across networks and IP changes without the session dropping. And it supports UDP port forwarding, both local and remote.

The framing is important. This is not a web application or a protocol from scratch. The stated aim is to be fully compatible with OpenSSH while providing additional capabilities, and the client and server are meant to feel like the tools you already use. The trzsz client tssh works exactly like ssh, and the usage is the same as standard SSH, so the muscle memory transfers even though the transport underneath does not.

The audience is fairly specific. The description names high-latency links such as cellular connections and unstable Wi-Fi as the environments where it works well. Anyone on a wired office LAN with a stable address has no problem this project solves.

How the session moves from SSH to UDP

The mechanism is a handover, and it is worth following step by step because it explains both the strengths and the constraints of the design.

The tssh process on the client plays the role of ssh on the client side, and tsshd acts as sshd on the server side. The client first logs in to the server normally as an ssh client. It then starts a new tsshd process on the server, and each session has its own tsshd process.

That new process listens on a random UDP port in the range 61001 to 61999, which is configurable through the TsshdPort setting. The port number and the session secret keys are sent back to the tssh process through the SSH channel. The SSH connection is then closed, and from that point on tssh communicates with tsshd over UDP.

So authentication and authorization happen over the ordinary SSH path, which is the part that makes the OpenSSH compatibility claim credible. Once the identity is established and the session is running, the SSH channel is no longer needed for the traffic itself, and the session can survive the client changing address, because the server can accept the UDP traffic from a new source address.

The port range is a direct operational consequence. A thousand concurrent sessions need ports in that range, and the firewall on the server has to permit UDP across the range for the roaming to work at all. This is the single most common reason a tsshd setup fails to roam, and it is a rule about your network rather than about the software.

UDP mode, KCP and QUIC are three different transports

The client is invoked with the --udp option, and the documentation names two extra options for people who care about latency.

code
     Host xxx
         #!! UdpMode  ( yes | QUIC | KCP )

That snippet is the ssh config form of the same choice. By putting a UdpMode entry in the ~/.ssh/config file under a host, you can omit the --udp or --kcp flag on the command line, so the behaviour becomes a property of the host rather than something you retype.

The KCP option maps to the KCP protocol, and the comparison table in the documentation marks low latency for tsshd as coming from KCP, with the mosh column left blank on that row. The KCP library is a direct dependency: the go.mod file requires github.com/trzsz/kcp-go/v5 at version 5.6.73, alongside github.com/trzsz/quic-go at 0.63.0, github.com/trzsz/smux at 1.6.0 and github.com/trzsz/shellescape at 1.6.0. The presence of both a KCP and a QUIC implementation plus a stream multiplexer suggests the transport is pluggable, and that the project expects you to pick according to the link in front of you.

For most people, the default is the right answer and the --kcp option is the thing to reach for when a link is slow enough that you can feel the delay. The documentation frames it as latency-sensitive users can specify the --kcp option, which is about as much guidance as it gives.

The client itself is a separate repository, tssh, published as trzsz/trzsz-ssh, and the install steps for tsshd all point back to it. Installing the server without the client gets you nothing, so treat the two as one deployment.

What tsshd gives up compared with mosh

The documentation compares tsshd with mosh directly, and the table is more useful than a marketing page because it names the gaps.

The one feature tsshd does not have is local echo and line editing, and the comparison table marks it as Not Planned rather than missing. The text is explicit that tssh and tsshd work exactly like ssh, that there are no plans to support local echo and line editing, and that the project will not have the mosh issues referenced in mosh issue 1041, 1281 and 1295.

This is a design choice with a clear logic behind it. Local echo means the client draws characters as you type them and handles line editing itself, which is what makes mosh feel instant on a slow link. tsshd instead relies on the SSH terminal behaviour, so the characters travel to the server and come back. The result is that a command that produces a lot of output on a high latency link feels slower than it would under mosh, but the behaviour matches what you get from ssh, and the local terminal keeps working normally.

Everything else in the table is a point in tsshd's favour and reflects the OpenSSH base: multi platform and Windows support, X11 forwarding, agent forwarding, port forwarding, output scrollback, OSC52 sequences, ProxyJump and tmux -CC integration are all listed as available. The mosh column for those rows links to open mosh issues.

The practical read is that tsshd is a mosh substitute for people who need SSH features and would not give them up, rather than a faster mosh. If your priority is minimum perceived latency and you do not need agent forwarding or ProxyJump, mosh is the tool that was built for that job.

Installing tsshd across the usual package managers

The distribution support is broad, and the documentation gives an explicit command per platform.

On Ubuntu the route is a personal package archive, added with add-apt-repository.

sh
  sudo apt update && sudo apt install software-properties-common
  sudo add-apt-repository ppa:trzsz/ppa && sudo apt update

  sudo apt install tsshd

On Debian the archive is configured by hand, with the signing key fetched from a keyserver and dearmored into /usr/share/keyrings/trzsz.gpg, then a sources list entry pointing at the launchpad content for the jammy suite.

On Fedora, CentOS and RHEL the package comes from a COPR repository.

sh
  sudo dnf copr enable @trzsz/trzsz
  sudo dnf install tsshd

Arch Linux uses yay, macOS uses Homebrew, and Windows uses scoop, where the extras bucket is added first. The Windows instructions carry an extra requirement that is easy to skip: you need to allow the tsshd.exe path under the scoop apps directory through the firewall for it to work properly. That is the Windows equivalent of the firewall rule, and on that platform the default is to block the inbound UDP traffic that the whole roaming design depends on.

There is also a conda-forge route through pixi, conda and mamba, and the packaging is the reason the repository carries a debian directory and a .goreleaser.yaml file alongside the Go source.

Building from source with the bundled Makefile

The repository is a Go project with a module path of github.com/trzsz/tsshd and a go directive of 1.26.0, so a current toolchain is needed. The build system is a Makefile with the usual targets, and the interesting part is that it is written to work on both Unix and Windows.

The platform detection is done at the top of the file. If GOOS is windows, or if the host reports Windows_NT, the binary name becomes tsshd.exe and the removal command switches to PowerShell, the null device becomes NUL and the test command becomes go test. The install target is guarded so that it is not supported for Windows.

The compile rule builds the server binary from the cmd and tsshd packages.

code
${BIN_DIR}/${TSSHD}: $(wildcard ./cmd/tsshd/*.go ./tsshd/*.go) go.mod go.sum
	go build -o ${BIN_DIR}/ ./cmd/tsshd

There is a test target that runs the test suite in the tsshd package, and an examples target that builds each directory under examples that contains a main.go. The examples tree holds hello, sshd and wish examples, each with its own go.mod, so they are standalone programs rather than part of the main module.

The go.mod dependencies also tell you what the server needs at runtime. go-winio and the conpty library are for Windows console handling, creack/pty for pseudo terminals, go-shlex for command parsing, and golang.org/x/crypto, x/net and x/sys for the SSH and networking side. The trzsz fork of quic-go is used rather than the upstream module, which means the QUIC transport is a maintained fork rather than a stock dependency.

Where a UDP SSH server is the wrong tool

The first and simplest failure mode is a network that does not carry the traffic. Corporate networks, most VPNs and a fair number of cloud security groups block or rewrite UDP to arbitrary high ports. In that environment tsshd will authenticate, the session will start, and then the connection will go quiet the moment the SSH channel closes and the UDP path takes over. The 61001 to 61999 range has to be open end to end, and if it is not, the roaming you installed it for is the thing that breaks.

The second is the security boundary. A session that survives an IP change is a session whose source address is not the one you authenticated from. The session secret keys sent over the SSH channel are what tie the UDP flow to the authenticated session, and the port is random, but the design does mean you are running a server on a wide range of high ports with a per-session secret as the only thing keeping a stranger out. Whether that meets your organisation's bar is a question for whoever owns that policy, not for this review.

The third is the dependency on a client you do not control. tssh is a separate project, and if your organisation standardises on OpenSSH clients that you cannot replace, tsshd is unusable in practice no matter how well the server side works. There is no way to reach a tsshd session from a plain ssh client.

The fourth is the maturity of the project itself. The version numbers are still in the 0.1 range, with v0.1.10 published on 2026-10-03 and v0.1.9 on 2026-07-17, and there is also a rolling dev build published from the main branch. The last push was on 2026-10-18, so the code is moving, but a 0.1 series is a young project and the documentation does not describe a support policy or a compatibility guarantee for the wire protocol. Check that your firewall and your client fleet can both handle it before you commit a team to it.

On the licence, the project is MIT, which is permissive and imposes few obligations on a user who runs the server without modifying it. Redistribution of a modified binary carries the MIT conditions, and if you are considering a fork that changes the protocol you would want to read the LICENSE file yourself and take advice rather than rely on this summary.

Editorial conclusion

tsshd suits a developer working over cellular links or flaky Wi-Fi who keeps losing an SSH session to an address change and needs the OpenSSH feature set rather than a terminal multiplexer, and it does not suit a server that must stay reachable only over TCP or a team that cannot install the tssh client on every workstation. Before you deploy it, confirm that UDP is reachable to the client and decide which transport to allow, because the default UDP mode and the KCP and QUIC options differ in latency behaviour and the server port range of 61001 to 61999 has to be open on your firewall.

Frequently asked questions

What is tsshd and what problem does it solve?

tsshd is a UDP based SSH server built for unreliable networks. It survives sleep, wake and temporary network loss, roams across networks and IP changes, and supports UDP port forwarding for both local and remote forwards.

How does tsshd keep a session alive when the IP address changes?

The tssh client logs in over normal SSH, then starts a tsshd process on the server that listens on a random UDP port between 61001 and 61999. The port and session secret keys go back over the SSH channel, the SSH connection is closed, and the session then runs over UDP.

How do I install tsshd?

Packages are provided for Ubuntu and Debian through a personal package archive, for Fedora, CentOS and RHEL through a COPR repository, and for Arch, macOS, Windows and conda-forge through yay, Homebrew, scoop and pixi respectively. On Windows you must also allow the tsshd.exe path through the firewall.

Does tsshd support local echo and line editing like mosh?

No, and the documentation marks it as Not Planned. tssh and tsshd work exactly like ssh, so there is no local echo or line editing, which is the trade for keeping the full OpenSSH feature set.

What is the difference between tsshd and mosh?

tsshd was inspired by mosh and works like mosh-server, with tssh --udp playing the mosh role, but it is built on the SSH model instead. The comparison table gives tsshd the advantage on Windows support, X11 and agent forwarding, port forwarding, scrollback, OSC52, ProxyJump and tmux -CC integration, while mosh keeps local echo and line editing.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. trzsz/tsshd on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/trzsz-tsshd.svg)](https://hysenlabs.com/projects/trzsz-tsshd)

Was this useful?