simple_ssh is a lightweight, asynchronous Rust library that simplifies SSH operations such as executing remote commands, transferring files via SCP, and interactive PTY sessions. Built on top of the russh and russh-keys crates, it offers a streamlined API for secure and efficient SSH interactions.
- Asynchronous SSH client operations using
tokio - Execute remote shell commands (
cmd,exec,system) - Transfer files securely using the SCP protocol
- Interactive PTY shell sessions with raw mode and auto-resize
- Programmatic PTY sessions via
PtyHandlefor embedding in TUIs - Terminal multiplexer support (1x2, 2x1, 2x2 layouts)
- IPv6 link-local address support with scope ID
- Authentication modes: public key, password, and none
- SSH certificate support for key authentication
- Minimalistic and focused API design
Add simple_ssh to your project's Cargo.toml:
[dependencies]
simple_ssh = "0.1.3"To install the CLI binaries (simple-ssh and simple-scp), use the cli feature:
cargo install simple_ssh --features cliThis installs both simple-ssh and simple-scp binaries to your cargo bin directory.
use simple_ssh::Session;
use anyhow::Result;
#[tokio::main]
async fn main() -> Result<()> {
let session = Session::init()
.with_port(22)
.with_host("192.168.0.100")
.with_user("root")
.with_passwd("toor")
.build()?;
let mut ssh = session.connect().await?;
println!("Connected");
// Execute a shell command
let code = ssh.cmd("ls -la").await?;
println!("Exitcode: {:?}", code);
// Execute with arguments (properly escaped)
let code = ssh.exec(&["ls", "-la", "/tmp"].iter().map(|s| s.to_string()).collect()).await?;
println!("Exitcode: {code}");
// Execute via sh -c (like system())
let code = ssh.system("echo $HOME && ls -la").await?;
println!("Exitcode: {:?}", code);
ssh.close().await?;
Ok(())
}use simple_ssh::Session;
use anyhow::Result;
#[tokio::main]
async fn main() -> Result<()> {
let session = Session::init()
.with_port(22)
.with_host("192.168.0.100")
.with_user("root")
.with_passwd("toor")
.build()?;
let mut ssh = session.connect().await?;
println!("Connected");
ssh.scp("local_file.txt", "/remote/path/remote_file.txt").await?;
println!("File transferred successfully.");
Ok(())
}For IPv6 link-local addresses, use the --scope option to specify the network interface:
use simple_ssh::Session;
use anyhow::Result;
#[tokio::main]
async fn main() -> Result<()> {
let session = Session::init()
.with_host("fe80::1")
.with_scope("eth0") // Network interface name or index
.with_user("root")
.with_passwd("password")
.build()?;
let mut ssh = session.connect().await?;
// ...
Ok(())
}For non-interactive PTY sessions where you control the I/O (e.g., embedding in a TUI):
use simple_ssh::Session;
use anyhow::Result;
#[tokio::main]
async fn main() -> Result<()> {
let session = Session::init()
.with_host("192.168.0.100")
.with_user("root")
.with_passwd("toor")
.build()?;
let mut ssh = session.connect().await?;
// Open a PTY handle for programmatic control
let mut handle = ssh
.pty_builder()
.with_term("xterm-256color")
.with_size(80, 24)
.open()
.await?;
// Send input
handle.write(b"ls -la\n").await?;
// Exit the shell so handle.read() returns None and handle.wait() completes
handle.write(b"exit\n").await?;
// Read output - loop ends when shell exits and handle.read() returns None
while let Some(data) = handle.read().await {
println!("Received: {:?}", data);
}
// Wait for exit status
let status = handle.wait().await?;
println!("Exit status: {:?}", status.code());
Ok(())
}Two example binaries are provided for command-line use:
Interactive SSH client with PTY support and terminal multiplexing:
# Interactive shell
simple-ssh -H 192.168.1.1 -u root -P password
# Execute command
simple-ssh -H server.example.com -u admin -P secret "uname -a"
# With private key
simple-ssh -H server.example.com -i /path/to/key
# IPv6 link-local with scope
simple-ssh -H fe80::1%eth0 -u root -P password
# Terminal multiplexer (2 panes stacked vertically)
simple-ssh -H 192.168.1.1 -u root -P password --mux 1x2
# Terminal multiplexer (2 panes side by side)
simple-ssh -H 192.168.1.1 -u root -P password --mux 2x1
# Terminal multiplexer (4 panes in 2x2 grid)
simple-ssh -H 192.168.1.1 -u root -P password --mux 2x2File transfer utility:
# Transfer file using password authentication
simple-scp -H 192.168.1.1 -u root -P password /local/file.txt /remote/path.txt
# Transfer file using private key
simple-scp -H server.example.com -i /path/to/key /local/file.txt /remote/path.txt
# With custom port
simple-scp -H 192.168.1.1 -p 2222 -u admin -P secret /local/file.txt /remote/path.txt| Option | Description |
|---|---|
-H, --host <HOST> |
SSH host to connect to (required) |
-u, --user <USER> |
SSH username (default: root) |
-P, --passwd <PASSWD> |
SSH password |
-i, --key <KEY> |
Path to private key file |
-p, --port <PORT> |
SSH port (default: 22) |
--scope <SCOPE> |
IPv6 scope ID (e.g., interface name or number) |
-a, --auth <AUTH> |
Authentication method (password, key, none) |
--mux <MODE> |
Terminal multiplexer mode: 1x2, 2x1, or 2x2 |
| Option | Description |
|---|---|
-H, --host <HOST> |
SSH host to connect to (required) |
-u, --user <USER> |
SSH username (default: root) |
-P, --passwd <PASSWD> |
SSH password |
-i, --key <KEY> |
Path to private key file |
-p, --port <PORT> |
SSH port (default: 22) |
--scope <SCOPE> |
IPv6 scope ID (e.g., interface name or number) |
-a, --auth <AUTH> |
Authentication method (password, key, none) |
<LOCAL> |
Local file path to upload |
<REMOTE> |
Remote destination path |
# Development build
cargo build
# Release build
cargo build --release
# Build CLI examples
cargo build --bin simple-ssh --features cli
cargo build --bin simple-scp --features cli
# Static musl build (for distribution)
cargo build --release --target x86_64-unknown-linux-muslThe musl build produces a fully static binary with no dynamic library dependencies, suitable for deployment in containerized or minimal environments.
# Run all tests
cargo test
# Run specific test
cargo test test_session_builder
# Run with output
cargo test -- --nocapturesimple_ssh is actively developed and provides a stable API for common SSH operations.
The core functionalities including command execution, SCP file transfer, and PTY sessions
are fully implemented and tested. Contributions, issues, and feature requests are welcome!
This project is licensed under the MIT License. See the LICENSE file for details.
russh - The underlying SSH library used for client and server implementations.