Skip to the content.

tsshd: UDP-based SSH Server with Roaming Support

MIT License GitHub Release GitHub tsshd 中文文档

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.

tsshd aims to be fully compatible with OpenSSH while providing additional capabilities:

Comparison

tsshd was inspired by mosh, and the tsshd works like mosh-server, while the tssh --udp works like mosh.

Feature mosh ( mosh-server ) tssh ( tsshd )
Low Latency ?? KCP
Keep Alive
Client Roaming
Local Echo & Line Editing Not Planned
Multi Platform / Windows mosh#293
SSH X11 Forwarding mosh#41
SSH Agent Forwarding mosh#120
SSH Port Forwarding mosh#337
Output Scrollback mosh#122
OSC52 Sequence mosh#637
ProxyJump mosh#970
tmux -CC Integration mosh#1078

tssh and tsshd works exactly like ssh, there are no plans to support local echo and line editing, and will not have the mosh issues: mosh#1041, mosh#1281, mosh#1295, etc.

How to use

  1. Install tssh on the client ( your local machine ).

  2. Install tsshd on the server ( the remote host ).

  3. Use tssh --udp xxx to log in. The usage is the same as standard SSH.

    • Latency-sensitive users can specify the --kcp option.
    • Alternatively, configure the following in ~/.ssh/config to omit the --udp or --kcp option:
      Host xxx
          #!! UdpMode  ( Yes | QUIC | KCP )
      

How it works

Installation

Supported Terminals

The following clients or terminals support the tsshd server:

Reconnection

┌───────────────────────┐                ┌───────────────────────┐
│                       │                │                       │
│    tssh (process)     │                │    tsshd (process)    │
│                       │                │                       │
│ ┌───────────────────┐ │                │ ┌───────────────────┐ │
│ │                   │ │                │ │                   │ │
│ │  KCP/QUIC Client  │ │                │ │  KCP/QUIC Server  │ │
│ │                   │ │                │ │                   │ │
│ └───────┬───▲───────┘ │                │ └───────┬───▲───────┘ │
│         │   │         │                │         │   │         │
│         │   │         │                │         │   │         │
│ ┌───────▼───┴───────┐ │                │ ┌───────▼───┴───────┐ │
│ │                   ├─┼────────────────┼─►                   │ │
│ │   Client  Proxy   │ │                │ │   Server  Proxy   │ │
│ │                   ◄─┼────────────────┼─┤                   │ │
│ └───────────────────┘ │                │ └───────────────────┘ │
└───────────────────────┘                └───────────────────────┘

Security Model

Configurations

Server Configuration (tsshd)

Client Configuration (tssh)

Host xxx
    #!! UdpMode Yes
    #!! TsshdPort 61001-61999
    #!! TsshdPath ~/go/bin/tsshd
    #!! UdpAliveTimeout 86400
    #!! UdpHeartbeatTimeout 3
    #!! UdpReconnectTimeout 15
    #!! ShowNotificationOnTop yes
    #!! ShowFullNotifications yes
    #!! UdpProxyMode UDP
    #!! UdpMTU 1400

UDP Port Forwarding

When using tssh as the client, UDP port forwarding is supported.

Developer Guide: Building Custom SSH Services

tsshd is more than just a binary program; it is a powerful framework that allows you to build custom SSH applications with seamless roaming and low-latency capabilities.

A. Quick Start: Custom Business Logic

You can easily inject your own interaction logic into an SSH session using the middleware mechanism provided by tsshd.

func main() {
    // Use tsshd.RunMain as the entry point and inject custom middleware
    code, err := tsshd.RunMain(
        tsshd.WithMiddleware(func(next tsshd.Handler) tsshd.Handler {
            return func(sess tsshd.Session) {
                term := term.NewTerminal(sess, "Enter your name: ")
                name, _ := term.ReadLine()
                fmt.Fprintf(sess, "Hello, %s! This is a custom SSH service with roaming support.\r\n", name)
            }
        }),
    )
    if err != nil {
        fmt.Fprintf(os.Stderr, "%v\n", err)
    }
    os.Exit(code)
}

How it Works:

  1. OpenSSH Bootstrapping: When a client connects using tssh --udp, it first logs in via the standard SSH protocol.
  2. Process Spawning: OpenSSH spawns your custom binary on the server side.
  3. Protocol Switch: The program starts and listens on a random UDP port, sends the session keys back to the client, and then the client switches to the QUIC/KCP protocol to communicate directly with the program.

Note: If your binary is not in the system PATH, you must specify the path on the client side using the TsshdPath config or the --tsshd-path CLI option.

B. Advanced: Building Integrated Servers with Wish

If you don’t want to rely on the system’s OpenSSH to spawn processes, or if you want to build a pure, single-binary custom SSH server, you can combine Wish (based on gliderlabs/ssh) with tsshd.

In this mode, your program can play two roles simultaneously:

Core Design Concept: Adapter Pattern

To reuse business logic (such as terminal interaction) across both Wish and tsshd, you can define a unified Session interface to abstract away the underlying differences:

// Unified Session interface to make business logic shared between Wish (TCP) and tsshd (UDP)
type Session = tsshd.Session

func handleBusiness(sess Session) {
    fmt.Fprintf(sess, "Current session type: %T\r\n", sess)
    // Write your business logic here...
}
Session Handoff (Process Handoff)

When Wish receives a request from the client to start tsshd, you can use exec.Command to re-execute the current binary (with tsshd arguments) to achieve a seamless switch from a “standard SSH handshake” to “UDP low-latency transmission”:

  1. Instruction Detection: Capture the client’s request to execute tsshd within the Wish middleware.
  2. Secondary Launch: Start a sub-process locally on the server (running the current program in tsshd mode).
  3. Environment Inheritance: Pass current connection info (like SSH_CONNECTION) to the sub-process.

C. Why Choose This Architecture?

D. Examples

To help you get started quickly, we provide fully working sample code in the examples/ directory. You can use these as templates for your own custom SSH services.

Tip: You can run these examples locally and test them using the tssh client to experience the low-latency and roaming features firsthand!

Contact

Feel free to email the author lonnywong@qq.com, or create an issue. Welcome to join the QQ group: 318578930.

❤️ Sponsor trzsz ❤️, buy the author a drink 🍺 ? Thank you for your support!