Library / SDK
Eugeny/russh avatar
Eugeny/russh

russh is a low-level async SSH library where legacy algorithms are opt-in

Rust SSH client & server library

1,909 stars311 forksRustApache-2.0

At a glance

What is it?
russh is an Apache-2.0 licensed Rust and Tokio SSH client and server library that exposes channels, authentication, key exchange and forwarding directly, with safe algorithms by default and legacy ones behind features. It suits people building an SSH product rather than scripting a session, and the clippy-deny safety policy, the pinned ssh-key release candidate and the one-crypto-backend requirement shape what you build.
Who is it for?
russh earns a place in a Rust product that needs SSH as a component rather than a subprocess, since the client, server and forwarding paths are all first class, russh supports PuTTY keys and russh-sftp adds SFTP support.
Can I use it commercially?
Yes. Apache-2.0 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 18 days ago.
What is it written in?
Mainly Rust, 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.

From daily snapshots

Star history

  • Eugeny/russh1,909 ★ · +8
Star history
Repository2026-10-162026-10-23
Eugeny/russh1.9k1.9k

8 Stars in the last 7 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

One crypto backend, chosen in Cargo.toml, not by default

The first thing a dependency declaration has to answer is the crypto backend, because russh requires exactly one and there is no implicit choice. The README's default recommendation is aws-lc-rs:

toml
[dependencies]
russh = { version = "0.63", features = ["aws-lc-rs"] }
tokio = { version = "1", features = ["full"] }

The alternative is ring, and it comes with a warning attached:

toml
russh = { version = "0.63", default-features = false, features = ["ring", "flate2", "rsa"] }

The reason for the extra features in the second form is easy to miss. Turning off default features also turns off zlib compression and rsa support, so selecting ring means re-adding flate2 and rsa by hand. A dependency line that silently drops RSA host key support produces a connection failure that looks like an algorithm mismatch rather than a missing feature.

The version in the README example is 0.63 while the published releases have moved to 0.64, with v0.64.1 on 2026-10-05 and v0.64.0 the day before. At 0.x, Cargo treats the minor as breaking, so 0.63 and 0.64 are different incompatible lines and the README example is behind the newest tag.

The algorithm list is the compatibility policy

Russh aims for broad interoperability with real-world servers, and the README states the policy plainly: algorithms currently considered safe are on, older ones are available and must be opted into.

That is more useful than a count. The key exchange list carries mlkem768x25519-sha256 as a post-quantum hybrid, curve25519-sha256 in two spellings, and the diffie-hellman-group14 through group18 family. OpenSSH strict key exchange is there as the Terrapin mitigation, and DH-GEX supports programmatic group choice so you can select the group rather than let the negotiation decide. The legacy column holds the NIST curves, diffie-hellman-group14-sha1, group1-sha1 and the older GEX.

Ciphers split the same way: chacha20-poly1305 and the GCM and CTR AES suites as recommended, with the CBC AES modes and 3des-cbc in legacy, and 3des requiring the des feature. MACs follow with the ETM SHA-2 variants and plain SHA-2 recommended, SHA-1 legacy.

For host keys and public-key authentication the recommended set is ed25519, the three ECDSA curves and rsa-sha2-256 and rsa-sha2-512, with ssh-rsa marked as SHA-1 and OpenSSH certificates supported. Authentication methods are publickey, password, keyboard-interactive, none and OpenSSH certificate authentication.

Compression is none plus zlib and [email protected], the latter needing the flate2 feature, which is on by default.

A deny list rather than a promise about panics

The safety section is the strongest signal in this README, and it is enforced by lint rather than by convention.

Russh denies clippy::unwrap_used, clippy::expect_used, clippy::indexing_slicing and clippy::panic. Exceptions are reviewed and justified manually, which is the detail that makes this credible: a crate that denies panics entirely would not be buildable, so the useful claim is that each exception was argued for rather than typed past a warning.

The stated reason is that the library is built to withstand malicious or misbehaving peers. That is the exact threat model for an SSH parser, where input arrives from a host you have not authenticated yet, and it is why the deny list matters more here than it would in an application crate.

cryptovec uses unsafe for faster copying, initialisation and binding to native APIs, which is a deliberate trade at the layer where byte buffers cross into the crypto library. The repository has cryptovec/ as its own workspace member precisely so that this surface is isolated and reviewable.

SECURITY.md at the repository root is where to look for how to report a problem in this component.

Forwarding is the feature list, not a plugin

The features section is what distinguishes a protocol library from a client tool. Local port forwarding uses the direct-tcpip channel type, and remote port forwarding uses forward-tcpip. Both directions work for UNIX sockets as well, with direct-streamlocal marked client only and forward-streamlocal listed separately.

Channels themselves are AsyncRead and AsyncWrite capable, so a russh channel is a Tokio stream and you pipe it into whatever the rest of your program does. That is what makes the library usable for something other than a terminal: the channel is the interface, and exec versus a shell is one call difference.

Also listed: OpenSSH agent forwarding channels, keepalive request handling, the server-sig-algs extension, the PuTTY PPK key format and Pageant support on Windows. The PPK item matters more than it looks: it means a Windows user can be handed a PuTTY key file rather than being told to convert it with puttygen first.

Both directions of client and server are implemented in one crate, which is unusual and is what makes the adopters list below as varied as it is.

Five workspace members and an ssh-key pinned to a release candidate

The Cargo.toml defines a five-member workspace: russh, russh-config, cryptovec, pageant and russh-util, on resolver 2. The workspace lists russh, russh-config, cryptovec, pageant and russh-util as separate crates.

The dependency pinning is where a reader should stop and think. The workspace depends on ssh-key at the exact version =0.7.0-rc.11, not a semver range, with features for ed25519, the three NIST curves, encryption, ppk and sha1. An exact pin to a release candidate means the library was tested against that specific pre-release, and a crate whose own dependencies are pre-releases carries churn that a normal version range would not.

The rest of the tree is conventional: tokio 1.17, async-trait, futures, thiserror 2, rand 0.10 with thread_rng, and the digest, hmac, sha1, sha2 and signature crates. Crate versions of 0.9 to 0.11 across the crypto primitives indicate an ecosystem that is moving through a breaking-change cycle, which is expected for a 0.x library built on current crypto primitives.

There is also a rust-toolchain.toml at the root and a bench.sh, so the pinned toolchain is part of the build contract.

Adopters show both halves of the API in production

The adopter list is unusually specific about which half of the library each project uses, which is more informative than a logo wall.

Server use dominates. medusa, the multi-protocol honeypot, uses russh::server as the basis of the honeypot, which is the clearest statement of the threat model being taken seriously. warpgate, an SSH, HTTPS and MySQL bastion, uses both russh::server and russh::client for its smart SSH functionality. lapdev, a self-hosted remote development environment, uses russh::server to build a proxy into the environment, and Sandhole exposes HTTP, SSH and TCP services through port forwarding using russh::server with a ratatui admin interface.

Client use is less common and more specific. HexPatch uses russh::client together with russh_sftp::client for remote editing of files, and Devolutions Gateway uses russh::client for the web-based SSH client of a just-in-time access gateway.

Two projects show the terminal pattern: kartoffels and rebels-in-the-sky both use russh::server to deliver a game rendered with ratatui, and kty, a terminal for Kubernetes, uses russh::server plus russh_sftp::server to provide scp based file management. Motor OS builds its own SSH daemon on russh::server, and Cubic VM, a command-line VM manager, also appears in the list.

The surrounding ecosystem is two crates: russh-sftp for the SFTP subsystem on both sides, and async-ssh2-tokio, described as a simple high-level API for running commands over SSH, which is the right answer if russh itself is more than your task needs.

Editorial conclusion

russh earns a place in a Rust product that needs SSH as a component rather than a subprocess, since the client, server and forwarding paths are all first class, russh supports PuTTY keys and russh-sftp adds SFTP support. It is the wrong dependency if you only need to run a command occasionally, because async-ssh2-tokio provides a simple high-level API for running commands over SSH, and it is the wrong choice if you cannot accept a dependency tree pinned to an ssh-key release candidate. Before starting, pick exactly one crypto backend feature and enable it deliberately, keep the legacy algorithms off unless a specific target requires them, and read the security policy alongside the deny list for unwrap, expect, indexing and panic, since that policy is the main reason to trust the parser with a hostile peer.

Frequently asked questions

How do I add russh to a Cargo project?

Declare russh with a crypto backend feature and tokio, for example russh = { version = "0.63", features = ["aws-lc-rs"] } with tokio = { version = "1", features = ["full"] }. Exactly one crypto backend is required, either aws-lc-rs or ring.

Why do I need flate2 and rsa when I choose the ring backend?

Selecting ring requires default-features = false, and that turns off the default zlib compression and rsa support. The README's ring line therefore adds flate2 and rsa back explicitly: features = ["ring", "flate2", "rsa"].

Can russh connect to old servers with legacy algorithms?

Yes, by opting in. The README lists legacy key exchange including diffie-hellman-group1-sha1, legacy ciphers including the CBC AES modes and 3des-cbc with the des feature, and legacy SHA-1 MACs. These are not enabled by default.

What does russh deny by default in its own code?

clippy::unwrap_used, clippy::expect_used, clippy::indexing_slicing and clippy::panic are all denied, with exceptions reviewed and justified manually. cryptovec uses unsafe for faster copying, initialisation and native API binding.

Does russh support SFTP and port forwarding?

Port forwarding is built in, local and remote, for TCP and for UNIX sockets, with direct-streamlocal marked client only. SFTP is a separate crate, russh-sftp, providing both server and client subsystems, with examples in russh/examples/sftp_client.rs and sftp_server.rs.

Official sources

  1. Eugeny/russh on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
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/eugeny-russh.svg)](https://hysenlabs.com/projects/eugeny-russh)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/eugeny-russh.svg)](https://hysenlabs.com/projects/eugeny-russh)

Was this useful?