Crates.io version Crates.io downloads GitHub Downloads CI dependency status
A high-performance SSH client with SSH-compatible syntax for both single-host and parallel cluster operations, built with Rust and russh.
Developed and maintained as part of the Backend.AI project.
- v2.2.3 (2026年05月25日): Sync both internal russh forks to upstream stable (bssh-russh to russh 0.61.1, bssh-russh-sftp to russh-sftp 2.3.0), advancing the bundled RustCrypto chain (sha2/sha1 0.11, hmac 0.13, aes 0.9, digest 0.11, pbkdf2 0.13) and collapsing ssh-key onto a single 0.7.0-rc.10; re-port the high-frequency PTY
Handle::datadrain fix onto the new server session loop, add a dedicated regression test for it, and retire three patches now merged upstream (#207). Patch RUSTSEC-2026-0009 (time stack-exhaustion DoS) by bumpingtimeto 0.3.47, which raises the minimum supported Rust to 1.88 (#208). - v2.2.2 (2026年05月25日): Keep idle SSH sessions alive (#206): lower the default
--server-alive-intervalfrom 60s to 30s so keepalive traffic beats common one-minute idle reapers, normalize--server-alive-interval 0to fully disabled keepalive instead of a zero-duration timer, and leave the client-sideinactivity_timeoutdisabled so healthy interactive sessions (tmux, idle shells, long-running REPLs) are never closed by bssh itself. Dead-peer detection now resolves in about 120s instead of 180s. - v2.2.1 (2026年05月19日): Workspace dependency upgrade pass and a controlled sync of both internal russh forks to upstream stable, picking up the SSH-agent half of CVE-2026-46673 (256 KiB frame-length cap forward-port from upstream russh
a2d48a7) and the cryptovec hardening half viarussh-cryptovec0.60.3. Bumpslru0.17 to 0.18,signal-hook0.3 to 0.4, theopentelemetryfamily 0.31 to 0.32, andnix0.31.3; syncsbssh-russhto upstream russh 0.60.3 andbssh-russh-sftpto upstream russh-sftp 2.1.2 with the two pipelined File I/O helpers re-ported on top of the newFeaturesAPI (#203). Adds the missing[dev-dependencies]block tobssh-russhso its 75 inline tests (agent round-trip, PKCS#8 decoding, channel lifecycle, GEX, compress) compile and run for the first time since the fork's inception (#204). Drops a redundant.into_iter()in the synced SFTP session code that rustc 1.95's stricterclippy::useless_conversionlint flags (#205). - v2.2.0 (2026年05月18日): Collect
--passwordonce up-front and share the secret across all parallel SSH tasks viaArc<Password>, fixing per-node stdin races and progress-UI interleaving; addBSSH_PASSWORDenv support; warn (on stderr) when-S/--sudo-passwordis passed to subcommands where it has no effect (ping,upload,download,list,cache-stats) (#200, #201). Resolve all cargo-audit findings by replacingattywithstd::io::IsTerminaland acknowledging the unfixable rsa Marvin Attack advisory in.cargo/audit.toml(#198). Drop five stale or redundant direct dependencies (arrayvec,ctrlc,directories,signal-hook 0.4, plus the macOS objc2/block2/dispatch2 chain) by migrating tostd::sync::LazyLock/OnceLock,tokio::signal::ctrl_c, anddirs(#199). - v2.1.4 (2026年05月10日): SFTP transfer perf: stream uploads/downloads in 255 KiB chunks instead of buffering whole files (~160x lower RSS, ~11x faster 1 GiB upload), pipeline up to 64 concurrent SFTP requests, raise server
MAX_READ_SIZEto the 255 KiB SFTP standard (#195, #196, #197) - v2.1.3 (2026年04月30日): Fix SCP/SFTP path doubling on absolute paths and chroot dead config (#186); vendor
russh-sftpwithserde_bytesperf fix (+29% SFTP upload throughput); forward-port unreleased upstream russh fixes; standardize man page trailers - v2.1.2 (2026年04月27日): Restore terminal mouse tracking state on PTY session disconnect (#190); release workflow fixes
- v2.1.1 (2026年04月17日): Fix server panic and auth rejection on every client connection
- v2.1.0 (2026年04月14日): Rust 2024 edition migration, EnvGuard for safe test env handling, bytes pin
- v2.0.1 (2026年04月13日): Security updates (RSA Marvin Attack fix), bssh-keygen in Debian pipeline
- SSH Compatibility: Drop-in replacement for SSH with compatible command-line syntax
- Port Forwarding: Full support for local (-L), remote (-R), and dynamic (-D) SSH port forwarding
- Jump Host Support: Connect through bastion hosts using OpenSSH ProxyJump syntax (
-J) - Parallel Execution: Execute commands across multiple nodes simultaneously
- Hostlist Expressions: pdsh-style range expansion (
node[1-5],rack[1-2]-node[1-3]) for compact host specification - Fail-Fast Mode: Stop immediately on first failure with
-kflag (pdsh compatible) - Interactive Terminal UI (TUI): Real-time monitoring with 4 view modes (Summary/Detail/Split/Diff) for multi-node operations
- Cluster Management: Define and manage node clusters via configuration files
- Progress Tracking: Real-time progress indicators with smart detection (percentages, fractions, apt/dpkg)
- Flexible Authentication: Support for SSH keys, SSH agent, password authentication, and encrypted key passphrases
- Host Key Verification: Secure host key checking with known_hosts support
- Cross-Platform: Works on Linux and macOS
- Output Management: Multiple output modes (TUI, stream, file, normal) with auto-detection
- Interactive Mode: Interactive shell sessions with single-node or multiplexed multi-node support
- SSH Config Caching: High-performance caching of SSH configurations with TTL and file modification detection
- Configurable Timeouts: Set both connection timeout (
--connect-timeout) and command execution timeout (--timeout) with support for unlimited execution - SSH Keepalive: Configurable keepalive settings (
--server-alive-interval,--server-alive-count-max) to prevent idle connection timeouts
The easiest way to install bssh on macOS and Linux is through Homebrew:
brew tap lablup/tap brew install bssh
For Ubuntu users, bssh is available through the official PPA:
# Add the PPA repository sudo add-apt-repository ppa:lablup/backend-ai sudo apt update # Install bssh sudo apt install bssh
For Debian and other Debian-based distributions, download the .deb package from the releases page:
# Download the latest .deb package (replace VERSION with the actual version) wget https://github.com/lablup/bssh/releases/download/vVERSION/bssh_VERSION_OS_ARCH.deb # Example: bssh_0.4.0_ubuntu24.04.noble_amd64.deb # Install the package sudo dpkg -i bssh_VERSION_OS_ARCH.deb # If there are dependency issues, fix them with: sudo apt-get install -f
Download the latest release from the GitHub releases page:
- Go to https://github.com/lablup/bssh/releases
- Download the appropriate binary for your platform
- Extract the archive and place the binary in your
$PATH
cargo build --release sudo cp target/release/bssh /usr/local/bin/
# Connect to a host (just like SSH!) bssh user@hostname # Execute a command bssh user@hostname "uptime" # With specific port and key bssh -p 2222 -i ~/.ssh/key.pem admin@server.com # Using SSH options bssh -o StrictHostKeyChecking=no user@host # Query SSH capabilities bssh -Q cipher
PTY Session Escape Sequences:
Like OpenSSH, bssh supports escape sequences in PTY sessions. These must be typed at the beginning of a line (after pressing Enter):
| Escape | Description |
|---|---|
~. |
Disconnect from the remote host |
# Local port forwarding (-L) # Forward local port 8080 to example.com:80 via SSH bssh -L 8080:example.com:80 user@host # Remote port forwarding (-R) # Forward remote port 8080 to localhost:80 bssh -R 8080:localhost:80 user@host # Dynamic port forwarding / SOCKS proxy (-D) # Create SOCKS5 proxy on local port 1080 bssh -D 1080 user@host # Multiple port forwards bssh -L 3306:db:3306 -R 80:web:80 -D 1080 user@host # Bind to specific address bssh -L 127.0.0.1:8080:web:80 user@host # Local only bssh -L *:8080:web:80 user@host # All interfaces # SOCKS4 proxy (specify version) bssh -D 1080/4 user@host # SOCKS4 bssh -D *:1080/5 user@host # SOCKS5 on all interfaces # Port forwarding with command execution bssh -L 5432:postgres:5432 user@host "psql -h localhost" # Port forwarding with cluster operations bssh -C production -L 8080:internal:80 "curl http://localhost:8080"
# Connect through a single jump host (bastion) bssh -J jump@bastion.example.com user@internal-server # Multiple jump hosts (connection chain) bssh -J "jump1@proxy1,jump2@proxy2" user@final-destination # Jump host with custom port bssh -J admin@bastion:2222 user@internal-host # IPv6 jump host bssh -J "[2001:db8::1]:22" user@destination # Combine with cluster operations bssh -J bastion.example.com -C production "uptime" # File transfer through jump host bssh -J bastion.example.com -H internal-server upload app.tar.gz /opt/ bssh -J admin@bastion:2222 -C production download /etc/config ./backups/ # Interactive mode through jump hosts bssh -J bastion.example.com user@internal-server bssh -J "jump1,jump2" -C production interactive # Multi-hop with file transfer bssh -J "bastion1,bastion2,bastion3" -H target upload -r ./app/ /opt/app/
# Execute commands on multiple hosts (automatic command execution) bssh -H "user1@host1.com,user2@host2.com:2222" "uptime" # Using cluster from config bssh -C production "df -h" # Hostlist expressions (pdsh-style range expansion) bssh -H "node[1-5]" "uptime" # node1, node2, node3, node4, node5 bssh -H "node[01-05]" "df -h" # Zero-padded: node01, node02, ... bssh -H "node[1,3,5]" "ps aux" # Specific values: node1, node3, node5 bssh -H "rack[1-2]-node[1-3]" "uptime" # Cartesian product: 6 hosts bssh -H "web[1-3].example.com" "nginx -v" # With domain suffix bssh -H "admin@db[01-03]:5432" "psql --version" # With user and port bssh -H "^/etc/hosts.cluster" "uptime" # Read hosts from file # Filter specific hosts with pattern matching bssh -H "web1,web2,db1,db2" -f "web*" "systemctl status nginx" bssh -C production -f "db*" "pg_dump --version" bssh -H "node[1-10]" -f "node[1-5]" "uptime" # Filter with hostlist expression # Exclude specific hosts from execution bssh -H "node1,node2,node3" --exclude "node2" "uptime" bssh -C production --exclude "db*" "systemctl restart nginx" bssh -H "node[1-10]" --exclude "node[3-5]" "uptime" # Exclude with hostlist expression # With custom SSH key bssh -C staging -i ~/.ssh/custom_key "systemctl status nginx" # Use SSH agent for authentication bssh -A -C production "systemctl status nginx" # Use password authentication (will prompt for password) bssh --password -H "user@host.com" "uptime" # Use sudo password for privileged commands (prompts securely) bssh -S -C production "sudo apt update && sudo apt upgrade -y" # Combine sudo password with SSH agent authentication bssh -A -S -C production "sudo systemctl restart nginx" # Use encrypted SSH key (will prompt for passphrase) bssh -i ~/.ssh/encrypted_key -C production "df -h" # Limit parallel connections bssh -C production --parallel 5 "apt update" # Set command timeout (10 seconds) bssh -C production --timeout 10 "quick-check" # No timeout (unlimited execution time) bssh -C staging --timeout 0 "long-running-backup" # Set connection timeout (default: 30 seconds) bssh -C production --connect-timeout 10 "uptime" # Different timeouts for connection and command bssh -C production --connect-timeout 5 --timeout 600 "long-running-job" # Configure SSH keepalive (prevent idle connection timeouts) bssh -C production --server-alive-interval 30 "long-running-job" # Disable keepalive (set interval to 0) bssh -C production --server-alive-interval 0 "quick-job" # Keepalive with custom max retries (default: 3) bssh -C production --server-alive-interval 30 --server-alive-count-max 5 "long-running-job" # Fail-fast mode: stop immediately on any failure (pdsh -k compatible) bssh -k -H "web1,web2,web3" "deploy.sh" bssh --fail-fast -C production "critical-script.sh" # Combine fail-fast with require-all-success for critical operations bssh -k --require-all-success -C production "service-restart.sh"
bssh automatically selects the best output mode based on your environment:
Interactive Terminal UI with real-time monitoring - automatically enabled when running in an interactive terminal.
# TUI mode automatically activates for multi-node commands bssh -C production "apt-get update" # Features: # - Summary view: All nodes at a glance with progress bars # - Detail view: Full output from specific node with scrolling # - Split view: Monitor 2-4 nodes simultaneously in panes # - Diff view: Compare output from two nodes side-by-side # - Auto-scroll: Automatic following of new output # - Progress detection: Percentage, fraction, apt/dpkg indicators # - Real-time updates: Output streams in real-time (50ms polling) # - Memory protection: 10MB buffer per node with graceful overflow
TUI View Modes:
| View Mode | Description | Access Key |
|---|---|---|
| Summary | All nodes overview with status, progress bars, and recent output | Default view |
| Detail | Full output from a single node with scrollback | 1-9 (node number) |
| Split | Side-by-side display of 2-4 nodes (last 20 lines each) | s |
| Diff | Compare two nodes line-by-line | d |
Keyboard Shortcuts:
| Key | Context | Action |
|---|---|---|
| Global Keys (work in any view) | ||
q |
Any view | Quit TUI |
Ctrl+C |
Any view | Quit TUI |
? |
Any view | Toggle help overlay |
Esc |
Any view | Return to summary view (or close help) |
l |
Any view | Toggle log panel visibility |
| Summary View | ||
1-9 |
Summary | Jump to detail view for node N |
s |
Summary | Enter split view (first 2-4 nodes) |
d |
Summary | Enter diff view (first 2 nodes) |
| Detail View | ||
↑ |
Detail | Scroll up 1 line |
↓ |
Detail | Scroll down 1 line |
← |
Detail | Switch to previous node |
→ |
Detail | Switch to next node |
PgUp |
Detail | Scroll up 10 lines |
PgDn |
Detail | Scroll down 10 lines |
Home |
Detail | Jump to top of output |
End |
Detail | Jump to bottom (re-enables follow mode) |
f |
Detail | Toggle auto-scroll (follow mode) |
1-9 |
Detail | Jump to specific node N |
| Split View | ||
1-4 |
Split | Focus on specific node (switch to detail view) |
| Diff View | ||
↑/↓ |
Diff | Scroll* |
| Log Panel (when visible) | ||
j |
Log panel | Scroll log up |
k |
Log panel | Scroll log down |
+ |
Log panel | Increase log panel height |
- |
Log panel | Decrease log panel height |
t |
Log panel | Toggle timestamps |
*Note: Diff view scroll is planned but not yet implemented.
Log Panel:
The TUI includes an in-app log panel that captures error and warning messages without breaking the alternate screen. This prevents log messages from corrupting the TUI display during execution.
- Toggle visibility with
lkey - Color-coded by level: ERROR (red), WARN (yellow), INFO (white), DEBUG (gray)
- Configurable buffer size via
BSSH_TUI_LOG_MAX_ENTRIESenvironment variable (default: 1000, max: 10000) - Panel height adjustable from 3-10 lines
TUI Activation:
- Automatic: Multi-node execution in interactive terminal
- Disabled when:
- Single node execution
- Output piped or redirected (
| tee,>) - CI environment (
CI=true) - Explicit flags (
--stream,--output-dir)
- Minimum terminal size: 40x10 characters
# Enable stream mode explicitly bssh -C production --stream "tail -f /var/log/syslog" # Output: # [node1] Oct 30 10:15:23 systemd[1]: Started nginx.service # [node2] Oct 30 10:15:24 kernel: [UFW BLOCK] IN=eth0 OUT= # [node1] Oct 30 10:15:25 nginx: Configuration test successful # Stream mode without hostname prefix (pdsh -N compatibility) bssh -C production --stream --no-prefix "uname -a" # Output (no [node] prefixes): # Linux node1 5.15.0-generic # Linux node2 5.15.0-generic
# Save each node's output to timestamped files bssh -C production --output-dir ./logs "ps aux" # Creates: # ./logs/node1_20251030_101523.stdout # ./logs/node2_20251030_101523.stdout # ./logs/node1_20251030_101523.stderr (if there are errors)
# Automatically used when output is piped or redirected bssh -C production "uptime" | tee results.txt bssh -C production "df -h" > disk-usage.log # Manually disable TUI in terminals CI=true bssh -C production "command"
bssh provides two modes for handling Ctrl+C during parallel execution:
Default (Two-Stage):
- First Ctrl+C: Shows status (running/completed counts)
- Second Ctrl+C (within 1 second): Terminates all jobs
Batch Mode (-b / --batch):
- Single Ctrl+C: Immediately terminates all jobs
- Useful for non-interactive scripts and CI/CD pipelines
# Default behavior (two-stage Ctrl+C) bssh -C production "long-running-command" # Ctrl+C once: shows status # Ctrl+C again (within 1s): terminates # Batch mode (immediate termination) bssh -C production -b "long-running-command" # Ctrl+C once: immediately terminates all jobs # Useful for automation bssh -H nodes --batch --stream "deployment-script.sh"
bssh supports pdsh compatibility mode, enabling it to act as a drop-in replacement for pdsh. This allows seamless migration from pdsh without modifying existing scripts.
📖 Complete Documentation:
- Migration Guide - Step-by-step migration from pdsh to bssh
- Options Reference - Complete option mapping table
- Examples - Real-world usage patterns
1. Binary symlink (recommended for full compatibility):
# Create symlink (done automatically by Homebrew) sudo ln -sf "$(which bssh)" /usr/local/bin/pdsh # Now pdsh commands use bssh pdsh -w host1,host2 "uptime"
2. Environment variable:
BSSH_PDSH_COMPAT=1 bssh -w host1,host2 "uptime"3. CLI flag:
bssh --pdsh-compat -w host1,host2 "uptime"4. Shell alias:
# Add to ~/.bashrc or ~/.zshrc alias pdsh='bssh --pdsh-compat'
| pdsh option | bssh equivalent | Description |
|---|---|---|
-w hosts |
-H hosts |
Target hosts (comma-separated) |
-x hosts |
--exclude hosts |
Exclude hosts from target list |
-f N |
--parallel N |
Fanout (parallel connections, default: 32) |
-l user |
-l user |
Remote username |
-t N |
--connect-timeout N |
Connection timeout in seconds |
-u N |
--timeout N |
Command timeout in seconds |
-N |
--no-prefix |
Disable hostname prefix in output |
-b |
--batch |
Batch mode (single Ctrl+C terminates) |
-k |
--fail-fast |
Stop on first failure |
-q |
(query mode) | Show target hosts and exit |
-S |
--any-failure |
Return largest exit code from any node |
# Basic command execution pdsh -w node1,node2,node3 "uptime" # With fanout limit pdsh -w nodes -f 10 "df -h" # Exclude specific hosts pdsh -w node[1-5] -x node3 "hostname" # Query mode: show target hosts without executing pdsh -w host1,host2,host3 -x host2 -q # Output: # host1 # host3 # Combine multiple options pdsh -w servers -f 20 -l admin -t 30 -N "systemctl status nginx" # Fail fast mode pdsh -w nodes -k "critical-operation.sh"
Query mode (-q) supports glob pattern matching for exclusions:
# Exclude hosts matching a pattern pdsh -w web1,web2,db1,db2 -x "db*" -q # Output: # web1 # web2 # Use wildcards in exclusion pdsh -w node1,node2,backup1,backup2 -x "*backup*" -q # Output: # node1 # node2
# Test connectivity to hosts bssh -C production ping bssh -H "host1,host2" ping # List configured clusters bssh list # Interactive mode (single or multiplexed) bssh -C production interactive bssh -H "host1,host2" interactive # File transfer operations bssh -C production upload local.txt /tmp/ bssh -H "host1,host2" download /etc/hosts ./backups/
| Version | Behavior | Use Case |
|---|---|---|
| v1.0-v1.1 | Returns 0 if all succeed, 1 if any fails | Health checks |
| v1.2.0+ (default) | Returns main rank's actual exit code | MPI workloads, CI/CD |
MPI Workloads - ✅ No changes needed:
# Now returns actual exit codes: 0, 139 (SIGSEGV), 137 (OOM), etc. bssh exec "mpirun ./simulation"
Health Checks - Add --require-all-success flag:
# v1.0-v1.1 bssh exec "health-check" # v1.2.0+ (preserve old behavior) bssh --require-all-success exec "health-check"
- Default: Return main rank's exit code (MPI standard)
--require-all-success: Return 0 only if all nodes succeed--check-all-nodes: Return main rank code, or 1 if main OK but others failed
See examples/mpi_exit_code.sh and examples/health_check.sh for detailed examples.
bssh supports multiple authentication methods:
- Default keys: Automatically tries
~/.ssh/id_ed25519,~/.ssh/id_rsa,~/.ssh/id_ecdsa,~/.ssh/id_dsa - Custom key: Use
-iflag to specify a key file - Encrypted keys: Automatically detects and prompts for passphrase
- Auto-detection: Automatically uses SSH agent if
SSH_AUTH_SOCKis set - Explicit: Use
-Aflag to force SSH agent authentication
- Use
-P/--passwordflag to enable password authentication - The password is prompted once up-front, before any parallel connection tasks start, and is shared securely across all nodes — the prompt appears exactly once regardless of how many hosts are targeted
- Password is prompted securely without echo
- For automation, set
BSSH_PASSWORDin the environment (not recommended; see security notes in the Sudo Password section)
# Use default SSH key (auto-detect) bssh -H "user@host" "uptime" # Use specific SSH key (prompts for passphrase if encrypted) bssh -i ~/.ssh/custom_key -c production "df -h" # Use SSH agent bssh -A -c production "systemctl status" # Use password authentication bssh -P -H "user@host" "ls -la" # Authentication through jump hosts bssh -A -J bastion.example.com user@internal-server "uptime" bssh -i ~/.ssh/prod_key -J "jump1,jump2" -C production "df -h"
bssh supports automatic sudo password injection for commands that require elevated privileges. When enabled, bssh will:
- Securely prompt for the sudo password before command execution
- Detect sudo password prompts in command output
- Automatically inject the password when prompted
- Clear the password from memory after use
# Basic sudo command (will prompt for sudo password) bssh -S -C production "sudo apt update" # Combine with SSH agent authentication bssh -A -S -C production "sudo systemctl restart nginx" # Multiple sudo commands in a single session bssh -S -C production "sudo apt update && sudo apt upgrade -y" # Sudo with specific SSH key bssh -i ~/.ssh/admin_key -S -C production "sudo reboot"
Environment Variable Alternative:
For automation scenarios, you can use the BSSH_SUDO_PASSWORD environment variable:
# NOT RECOMMENDED for security reasons export BSSH_SUDO_PASSWORD="your-password" bssh -S -C production "sudo apt update"
Security Warnings:
- Environment variables may be visible in process listings
- Avoid storing passwords in shell history
- The
-Sflag with secure prompt is the recommended approach - Password is automatically cleared from memory after use using
zeroize
bssh supports configuration via environment variables:
BSSH_MAX_JUMP_HOSTS: Maximum number of jump hosts allowed in a chain- Default: 10
- Absolute maximum: 30 (security cap)
- Invalid or zero values fall back to default
- Example:
BSSH_MAX_JUMP_HOSTS=20 bssh -J host1,host2,...,host20 target
BACKENDAI_CLUSTER_HOSTS: Comma-separated list of all cluster nodesBACKENDAI_CLUSTER_HOST: Current node hostnameBACKENDAI_CLUSTER_ROLE: Node role (main/sub)
SSH_AUTH_SOCK: SSH agent socket path (Unix-like systems)
BSSH_PASSWORD: SSH password for automated password authentication- Used when
--password/-Pis set andBSSH_PASSWORDis non-empty; skips the interactive prompt - WARNING: Not recommended for security reasons
- Environment variables may be visible in process listings and shell history
- Use the interactive
-Pprompt instead for security-sensitive operations - Example:
BSSH_PASSWORD=secret bssh -P -H "user@host" "uptime"
- Used when
BSSH_SUDO_PASSWORD: Sudo password for automated sudo authentication- WARNING: Not recommended for security reasons
- Environment variables may be visible in process listings
- Use the
-Sflag with secure prompt instead - Example:
BSSH_SUDO_PASSWORD=password bssh -S -C prod "sudo apt update"
bssh loads configuration from the following sources in priority order:
- Backend.AI Environment Variables (automatic detection)
- Current directory (
./config.yaml) - XDG config directory (
$XDG_CONFIG_HOME/bssh/config.yamlor~/.config/bssh/config.yaml) - CLI specified path (via
--configflag, default:~/.config/bssh/config.yaml)
When running inside a Backend.AI multi-node session, bssh automatically detects cluster configuration from environment variables. No manual configuration or cluster specification needed!
Backend.AI environment variables used:
BACKENDAI_CLUSTER_HOSTS: Comma-separated list of all node hostnamesBACKENDAI_CLUSTER_HOST: Current node's hostnameBACKENDAI_CLUSTER_ROLE: Current node's role (main or sub)
Note: Backend.AI multi-node clusters use SSH port 2200 by default, which is automatically configured.
Automatic Detection:
When these environment variables are set, bssh automatically creates a "backendai" cluster and uses it by default when no -c or -H options are specified.
Example:
# Inside Backend.AI multi-node session, just run: bssh "uptime" # Automatically executes on all cluster nodes # Or specify a command explicitly: bssh "nvidia-smi" # Check GPU status on all nodes # Interactive mode also works automatically: bssh interactive # Opens interactive session with all Backend.AI nodes # You can still override with explicit options if needed: bssh -C other-cluster "command" # Use a different cluster bssh -H specific-host "command" # Use specific host
Create a configuration file at any of these locations:
./config.yaml(current directory)~/.config/bssh/config.yaml(user config directory)~/.bssh/config.yaml(default location)
defaults: user: admin port: 22 ssh_key: ~/.ssh/id_rsa parallel: 10 timeout: 300 # Command timeout in seconds (0 for unlimited) jump_host: bastion.example.com # Global default jump host (optional) server_alive_interval: 30 # SSH keepalive interval in seconds (0 to disable) server_alive_count_max: 3 # Max keepalive messages without response # Global interactive mode settings (optional) interactive: default_mode: multiplex # single_node or multiplex prompt_format: "[{node}] $ " # Variables: {node}, {user}, {host}, {pwd} history_file: ~/.bssh_history show_timestamps: false # Show timestamps in output work_dir: /home/admin # Initial working directory broadcast_prefix: "!all " # Prefix for broadcasting to all nodes node_switch_prefix: "!" # Prefix for special commands colors: # Node-specific colors in output node1: red node2: blue node3: green keybindings: switch_node: "Ctrl+N" broadcast_toggle: "Ctrl+B" quit: "Ctrl+Q" clusters: production: nodes: - web1.example.com - web2.example.com - user@web3.example.com:2222 ssh_key: ~/.ssh/prod_key timeout: 600 # Override default timeout for this cluster jump_host: prod-bastion.example.com # Cluster-specific jump host # Cluster-specific interactive settings (overrides global) interactive: default_mode: single_node prompt_format: "prod> " work_dir: /var/www staging: nodes: - host: staging1.example.com port: 2200 user: deploy jump_host: staging-bastion:2222 # Node-specific jump host - staging2.example.com user: staging_user jump_host: "" # Explicitly disable jump host for this cluster
bssh supports configuring jump hosts at three levels in your configuration file, with environment variable support:
Priority Order (highest to lowest):
- CLI
-Joption - Always takes precedence - Node-level - Per-node
jump_hostin detailed node config - Cluster-level -
jump_hostin cluster defaults - Global default -
jump_hostin top-level defaults
Example:
defaults: jump_host: ${BASTION_HOST} # Environment variables supported clusters: production: nodes: - host: prod1.internal - host: prod2.internal jump_host: "" # Explicitly disable for this node jump_host: prod-bastion.example.com direct-access: nodes: - host: direct.example.com jump_host: "" # Empty string disables inheritance
Notes:
- Empty string (
"") explicitly disables jump host inheritance at any level - Environment variables (
${VAR}or$VAR) are expanded in jump_host values - Node-level jump_host requires detailed node syntax (not simple hostname strings)
Important: Username Handling
The user field in config applies only to destination nodes, not to jump hosts:
clusters: internal: nodes: - 192.168.0.100 user: admin # Used for destination (192.168.0.100) jump_host: bai@bastion # User 'bai' for bastion (jump host)
- With username in jump_host:
bai@bastion:4300→ uses "bai" for bastion - Without username:
bastion:4300→ uses your current local username (like OpenSSH)
If jump host authentication fails due to username mismatch, specify the username explicitly in the jump_host field.
bssh fully supports OpenSSH-compatible configuration files via the -F flag or default SSH config locations (~/.ssh/config, /etc/ssh/ssh_config). In addition to standard SSH directives, bssh supports advanced options for certificate-based authentication and port forwarding control.
These options enable enterprise-grade PKI authentication using SSH certificates:
| Option | Description | Example |
|---|---|---|
| CertificateFile | SSH certificate file for PKI authentication (max 100 files) | CertificateFile ~/.ssh/id_rsa-cert.pub |
| CASignatureAlgorithms | CA signature algorithms for certificate validation (max 50) | CASignatureAlgorithms ssh-ed25519,rsa-sha2-512 |
| HostbasedAuthentication | Enable host-based authentication (yes/no) | HostbasedAuthentication yes |
| HostbasedAcceptedAlgorithms | Algorithms for host-based auth (max 50) | HostbasedAcceptedAlgorithms ssh-ed25519,rsa-sha2-512 |
These options provide fine-grained control over SSH port forwarding:
| Option | Description | Example |
|---|---|---|
| GatewayPorts | Control remote port forwarding (yes/no/clientspecified) | GatewayPorts clientspecified |
| ExitOnForwardFailure | Terminate connection if port forwarding fails (yes/no) | ExitOnForwardFailure yes |
| PermitRemoteOpen | Allowed destinations for remote forwarding (max 1000) | PermitRemoteOpen localhost:8080 |
These options control SSH proxy connection behavior:
| Option | Description | Example |
|---|---|---|
| ProxyUseFdpass | Pass connected file descriptor from ProxyCommand to ssh(1) instead of continuing execution (yes/no, default: no, OpenSSH 6.5+) | ProxyUseFdpass yes |
ProxyUseFdpass optimizes ProxyCommand usage by eliminating an unnecessary lingering process and reducing I/O overhead. When enabled, the proxy command passes the established connection file descriptor directly to ssh and exits, rather than remaining active to relay data throughout the session. This is particularly useful with proxy commands like netcat that support file descriptor passing (nc -F).
Note: This option is currently parsed from SSH configuration files for compatibility but is not yet utilized in bssh's SSH client implementation, as proxy connections are not yet supported.
These options enable powerful automation workflows and command execution features:
| Option | Description | Example |
|---|---|---|
| PermitLocalCommand | Allow local command execution after connection (yes/no, default: no) | PermitLocalCommand yes |
| LocalCommand | Execute local command after successful connection (supports tokens: %h, %H, %n, %p, %r, %u) | LocalCommand rsync -av ~/project/ %h:~/project/ |
| RemoteCommand | Execute command on remote host instead of shell | RemoteCommand tmux attach -t dev || tmux new -s dev |
| KnownHostsCommand | Command to fetch host keys dynamically (supports tokens) | KnownHostsCommand /usr/local/bin/fetch-host-key %H |
| ForkAfterAuthentication | Fork to background after authentication (yes/no) | ForkAfterAuthentication yes |
| SessionType | Session type: none/subsystem/default | SessionType none |
| StdinNull | Redirect stdin from /dev/null (yes/no) | StdinNull yes |
Token Substitution: LocalCommand and KnownHostsCommand support the following tokens:
%h- Remote hostname (from config)%H- Remote hostname (as specified on command line)%n- Original hostname%p- Remote port%r- Remote username%u- Local username%%- Literal percent sign
These options provide enhanced security and host key management features:
| Option | Description | Example |
|---|---|---|
| NoHostAuthenticationForLocalhost | Skip host key verification for localhost (yes/no, default: no) | NoHostAuthenticationForLocalhost yes |
| HashKnownHosts | Hash hostnames in known_hosts file for security (yes/no, default: no) | HashKnownHosts yes |
| CheckHostIP | Check host IP address in known_hosts (yes/no, deprecated in OpenSSH 8.5+) | CheckHostIP no |
| VisualHostKey | Display ASCII art of host key fingerprint (yes/no, default: no) | VisualHostKey yes |
| HostKeyAlias | Alias for host key lookup in known_hosts | HostKeyAlias lb.example.com |
| VerifyHostKeyDNS | Verify host keys using DNS SSHFP records (yes/no/ask, default: no) | VerifyHostKeyDNS ask |
| UpdateHostKeys | Accept updated host keys from server (yes/no/ask, default: no) | UpdateHostKeys ask |
These options provide fine-grained control over authentication behavior:
| Option | Description | Example |
|---|---|---|
| NumberOfPasswordPrompts | Password retry attempts (1-10, default: 3) | NumberOfPasswordPrompts 1 |
| EnableSSHKeysign | Enable ssh-keysign for host-based auth (yes/no, default: no) | EnableSSHKeysign yes |
These options control network-level connection behavior:
| Option | Description | Example |
|---|---|---|
| BindInterface | Bind connection to specific network interface | BindInterface tun0 |
| IPQoS | Set IP QoS/DSCP values (interactive bulk) | IPQoS lowdelay throughput |
| RekeyLimit | Control SSH session key renegotiation (data time) | RekeyLimit 1G 1h |
These options control X11 display forwarding behavior:
| Option | Description | Example |
|---|---|---|
| ForwardX11Timeout | Timeout for untrusted X11 forwarding (0 = no timeout) | ForwardX11Timeout 1h |
| ForwardX11Trusted | Enable trusted X11 forwarding (yes/no, default: no) | ForwardX11Trusted yes |
These options provide essential authentication management, security enforcement, and user convenience features:
| Option | Description | Example |
|---|---|---|
| IdentitiesOnly | Only use identity files specified in config, ignore SSH agent (yes/no) | IdentitiesOnly yes |
| AddKeysToAgent | Auto-add keys to SSH agent (yes/no/ask/confirm) | AddKeysToAgent yes |
| UseKeychain | [macOS only] Use macOS Keychain for SSH key passphrases (yes/no) | UseKeychain yes |
| IdentityAgent | Custom SSH agent socket path or "none" | IdentityAgent ~/.1password/agent.sock |
| PubkeyAcceptedAlgorithms | Restrict allowed public key algorithms (max 50) | PubkeyAcceptedAlgorithms ssh-ed25519,rsa-sha2-512 |
| RequiredRSASize | Minimum RSA key size in bits (1024-16384, warns <2048) | RequiredRSASize 2048 |
| FingerprintHash | Fingerprint hash algorithm (md5/sha256) | FingerprintHash sha256 |
Key Benefits:
- IdentitiesOnly: Solves multi-account authentication conflicts
- AddKeysToAgent: Eliminates manual ssh-add commands
- UseKeychain: Seamlessly integrates with macOS Keychain for passphrase management (Apple-specific OpenSSH extension)
- IdentityAgent: Enables modern agent tools (1Password, gpg-agent, etc.)
- PubkeyAcceptedAlgorithms: Enforces security policies
- RequiredRSASize: Prevents weak RSA keys
- FingerprintHash: Flexibility for legacy systems
Platform Notes:
- UseKeychain is an Apple-specific patch to OpenSSH and only available on macOS
- Fully integrated with macOS Keychain via Security Framework for secure passphrase storage and retrieval
- Passphrases are automatically stored after successful authentication and retrieved from Keychain on subsequent connections
- For cross-platform configurations, use
IgnoreUnknown UseKeychainto prevent errors on non-macOS systems
# ~/.ssh/config # Production servers with certificate authentication Host *.prod.example.com User admin CertificateFile ~/.ssh/prod-user-cert.pub CertificateFile ~/.ssh/prod-host-cert.pub CASignatureAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256 HostbasedAuthentication yes HostbasedAcceptedAlgorithms ssh-ed25519,rsa-sha2-512
# Secure hosts with restricted port forwarding Host *.secure.prod.example.com GatewayPorts clientspecified ExitOnForwardFailure yes PermitRemoteOpen localhost:8080 PermitRemoteOpen db.internal:5432 PermitRemoteOpen cache.internal:6379
# Optimized proxy connection with file descriptor passing Host internal-server ProxyCommand nc -X connect -x proxy.example.com:1080 -F %h %p ProxyUseFdpass yes # SOCKS proxy with netcat (reduces overhead) Host *.internal.example.com ProxyCommand nc -x socks.example.com:1080 -F %h %p ProxyUseFdpass yes # Jump host with ProxyCommand and fd passing Host bastion-optimized ProxyCommand ssh -W %h:%p jump.example.com ProxyUseFdpass yes
# Development server with automatic file synchronization Host dev-server User developer PermitLocalCommand yes LocalCommand rsync -av ~/project/ %h:~/project/ # Auto-attach to tmux session on connection Host project-server RemoteCommand tmux attach -t project || tmux new -s project RequestTTY yes # Cloud instances with dynamic host key fetching Host *.cloud.example.com KnownHostsCommand /usr/local/bin/fetch-cloud-key %H StrictHostKeyChecking accept-new # Background SSH tunnel for port forwarding Host tunnel ForkAfterAuthentication yes SessionType none LocalForward 8080 internal-server:80 StdinNull yes
# Local development environment - skip localhost verification Host localhost 127.0.0.1 ::1 NoHostAuthenticationForLocalhost yes NumberOfPasswordPrompts 1 # Security-hardened configuration with host key protection Host *.secure.example.com HashKnownHosts yes VisualHostKey yes VerifyHostKeyDNS ask UpdateHostKeys ask CheckHostIP no # Load-balanced service with shared host key Host lb-node-* HostKeyAlias lb.example.com # Multi-homed host with specific interface binding Host vpn-only BindInterface tun0 IPQoS lowdelay throughput # High-security session with frequent rekeying Host sensitive-data RekeyLimit 500M 30m # X11 forwarding with timeout and trust for graphics workstation Host graphics-workstation ForwardX11 yes ForwardX11Trusted yes ForwardX11Timeout 2h
# Multi-account setup - prevent agent key conflicts Host work HostName work.example.com IdentityFile ~/.ssh/work_rsa IdentitiesOnly yes Host personal HostName github.com User git IdentityFile ~/.ssh/personal_ed25519 IdentitiesOnly yes # Auto-add keys to SSH agent for convenience Host * AddKeysToAgent yes # macOS-specific: Use Keychain for SSH key passphrases # For cross-platform configs, add IgnoreUnknown to prevent errors on non-macOS systems Host * IgnoreUnknown UseKeychain UseKeychain yes # Custom SSH agent integration (1Password, gpg-agent) Host secure-* IdentityAgent ~/.1password/agent.sock # Disable SSH agent for specific hosts Host no-agent-host IdentityAgent none # Security-hardened production servers Host *.prod.example.com # Only allow modern, secure algorithms PubkeyAcceptedAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256 # Enforce strong RSA keys RequiredRSASize 2048 # Use modern fingerprint hashing FingerprintHash sha256 # Legacy system compatibility Host legacy.example.com # Allow older RSA keys RequiredRSASize 1024 # Use MD5 for legacy fingerprint verification FingerprintHash md5
# Base security settings Host * HostbasedAuthentication no ExitOnForwardFailure no PermitLocalCommand no # Production certificate configuration Host *.prod.example.com CertificateFile ~/.ssh/prod-cert.pub CASignatureAlgorithms ssh-ed25519,rsa-sha2-512 HostbasedAuthentication yes # Match directive for secure hosts Match host *.secure.prod.example.com GatewayPorts clientspecified ExitOnForwardFailure yes PermitRemoteOpen localhost:8080 # Development hosts with automation Match host *.dev.example.com PermitLocalCommand yes LocalCommand notify-send "Connected to %h" # Specific host overrides Host web.secure.prod.example.com User webadmin Port 443 CertificateFile ~/.ssh/web-specific-cert.pub
# Use default SSH config (~/.ssh/config) bssh user@host.prod.example.com # Use custom SSH config file bssh -F ~/custom-ssh-config user@host.prod.example.com # SSH config works with cluster operations bssh -C production "uptime" # Config options apply to all cluster nodes bssh -F ~/.ssh/prod-config -C production upload app.tar.gz /opt/
Options:
-H, --hosts <HOSTS> Comma-separated list of hosts (user@host:port format)
-C, --cluster <CLUSTER> Cluster name from configuration file
-f, --filter <PATTERN> Filter hosts by pattern (supports wildcards like 'web*')
--exclude <HOSTS> Exclude hosts from target list (comma-separated, supports wildcards)
--config <CONFIG> Configuration file path [default: ~/.config/bssh/config.yaml]
-u, --user <USER> Default username for SSH connections
-i, --identity <IDENTITY> SSH private key file path (prompts for passphrase if encrypted)
-A, --use-agent Use SSH agent for authentication (Unix/Linux/macOS only)
-P, --password Use password authentication (will prompt for password)
-S, --sudo-password Prompt for sudo password to auto-respond to sudo prompts
-J, --jump-host <JUMP_HOSTS> Jump hosts: [user@]host[:port],... (uses local user if not specified)
-L, --local-forward <SPEC> Local port forwarding [bind_address:]port:host:hostport
-R, --remote-forward <SPEC> Remote port forwarding [bind_address:]port:host:hostport
-D, --dynamic-forward <SPEC> Dynamic port forwarding (SOCKS) [bind_address:]port[/version]
--strict-host-key-checking <MODE> Host key checking mode (yes/no/accept-new) [default: accept-new]
-p, --parallel <PARALLEL> Maximum parallel connections [default: 10]
--timeout <TIMEOUT> Command timeout in seconds (0 for unlimited) [default: 300]
--connect-timeout <SECONDS> SSH connection timeout in seconds (minimum: 1) [default: 30]
--server-alive-interval <SECONDS> SSH keepalive interval in seconds (0 to disable) [default: 30]
--server-alive-count-max <COUNT> Max keepalive messages without response [default: 3]
--output-dir <OUTPUT_DIR> Output directory for command results
-N, --no-prefix Disable hostname prefix in output (pdsh -N compatibility)
-v, --verbose Increase verbosity (-v, -vv, -vvv)
-h, --help Print help
-V, --version Print version
# Inside Backend.AI session - automatic cluster detection bssh "hostname" # Shows hostnames of all nodes bssh "nvidia-smi --query-gpu=name,memory.total --format=csv" # GPU info bssh "python train.py --distributed" # Run distributed training
bssh -C production "sudo apt update && sudo apt upgrade -y"bssh -H "server1,server2,server3" "df -h | grep -E '^/dev/'"
bssh -C webservers "sudo systemctl restart nginx"bssh -C production --output-dir ./logs "tail -n 100 /var/log/syslog"# Set 30 minute timeout for backup operations bssh -C production --timeout 1800 "backup-database.sh" # No timeout for data migration (may take hours) bssh -C production --timeout 0 "migrate-data.sh" # Quick health check with 5 second timeout bssh -C monitoring --timeout 5 "health-check.sh"
Start an interactive shell session on cluster nodes:
# Interactive session on all nodes (multiplex mode - default) bssh -C production interactive # Interactive session on a single node bssh -C production interactive --single-node # Custom prompt format bssh -H server1,server2 interactive --prompt-format "{user}@{host}> " # Set initial working directory bssh -C staging interactive --work-dir /var/www # Interactive mode with keepalive for long-running sessions (e.g., tmux) bssh -C production --server-alive-interval 30 --server-alive-count-max 5 interactive
Interactive mode can be configured in your config.yaml file with both global and per-cluster settings. CLI arguments always override configuration file settings.
Global Configuration (applies to all clusters unless overridden):
interactive: default_mode: multiplex # or single_node prompt_format: "[{node}] $ " history_file: ~/.bssh_history show_timestamps: true # Add timestamps to output work_dir: /home/user broadcast_prefix: "!all " # Custom prefix for broadcast commands node_switch_prefix: "!" # Custom prefix for special commands
Per-Cluster Configuration (overrides global settings):
clusters: production: interactive: default_mode: single_node # Different mode for this cluster prompt_format: "PROD> " work_dir: /var/app
Configuration Priority:
- CLI arguments (highest priority)
- Cluster-specific configuration
- Global configuration
- Built-in defaults
In multiplex mode, commands are sent to active nodes with visual indicators:
[●くろまる ●くろまる ●くろまる] bssh> uptime
[node1] 10:23:45 up 5 days, 2:14, 1 user, load average: 0.15, 0.12, 0.09
[node2] 10:23:45 up 3 days, 4:22, 2 users, load average: 0.23, 0.19, 0.17
[node3] 10:23:45 up 7 days, 1:45, 1 user, load average: 0.08, 0.11, 0.10
[●くろまる ●くろまる ●くろまる] bssh> exit
Interactive mode supports special commands for node management. By default, these commands start with ! but the prefix can be customized in the configuration file.
| Command | Description |
|---|---|
!all |
Activate all connected nodes |
!broadcast <cmd> |
Execute command on all nodes temporarily (without changing active nodes) |
!node<N> or !n<N> |
Switch to node N (e.g., !node1, !n2) |
!list or !nodes |
List all nodes with their connection status |
!status |
Show currently active nodes |
!help or !? |
Show help for special commands |
exit |
Exit interactive mode |
Note: The ! prefix and !broadcast command can be customized via configuration:
interactive: node_switch_prefix: "@" # Use @ instead of ! broadcast_prefix: "@all " # Use @all instead of !broadcast
The prompt shows node status with visual indicators:
●くろまるActive node (commands will be executed)○しろまるInactive node (connected but not receiving commands)·Disconnected node
Examples:
[●くろまる ●くろまる ●くろまる] bssh>- All 3 nodes active[●くろまる ○しろまる ○しろまる] bssh>- Only first node active[1 · ·] (1/3) bssh>- Node 1 active, nodes 2 and 3 inactive
For large clusters (>10 nodes), the prompt uses a compact format:
[All 50/50] bssh>- All 50 nodes active[None 0/50] bssh>- No nodes active[Nodes 1,2,3... +47] (50/50) bssh>- Specific nodes active
$ bssh -C production interactive Connected to 3 nodes [●くろまる ●くろまる ●くろまる] bssh> !status Active nodes: node1.example.com, node2.example.com, node3.example.com [●くろまる ●くろまる ●くろまる] bssh> !node1 Switched to node 1 [●くろまる ○しろまる ○しろまる] (1/3) bssh> hostname [node1] node1.example.com [●くろまる ○しろまる ○しろまる] (1/3) bssh> !broadcast date Broadcasting command to all connected nodes... [node1] Thu Aug 22 10:30:00 UTC 2025 [node2] Thu Aug 22 10:30:00 UTC 2025 [node3] Thu Aug 22 10:30:00 UTC 2025 [●くろまる ○しろまる ○しろまる] (1/3) bssh> !all All nodes activated [●くろまる ●くろまる ●くろまる] bssh> df -h / [node1] Filesystem Size Used Avail Use% Mounted on [node1] /dev/sda1 20G 5.5G 14G 30% / [node2] Filesystem Size Used Avail Use% Mounted on [node2] /dev/sda1 20G 7.2G 12G 38% / [node3] Filesystem Size Used Avail Use% Mounted on [node3] /dev/sda1 20G 4.1G 15G 22% / [●くろまる ●くろまる ●くろまる] bssh> exit Goodbye!
When using the --output-dir option, bssh saves command outputs to structured files:
output-dir/
├── hostname1_20250821_143022.stdout # Standard output
├── hostname1_20250821_143022.stderr # Standard error (if any)
├── hostname2_20250821_143022.stdout # Per-node outputs
├── hostname2_20250821_143022.error # Connection/execution errors
├── hostname3_20250821_143022.empty # Marker for no output
└── summary_20250821_143022.txt # Overall execution summary
.stdout: Contains standard output from successful commands.stderr: Contains standard error output (created only if stderr is not empty).error: Contains error messages for failed connections or executions.empty: Marker file when command produces no outputsummary_*.txt: Overall execution summary with success/failure counts
Each output file includes metadata headers:
# Command: df -h
# Host: server1.example.com
# User: admin
# Exit Status: 0
# Timestamp: 20250821_143022
[actual command output follows]
# Save outputs to timestamped directory bssh -C production --output-dir ./results/$(date +%Y%m%d) "ps aux | head -10" # Collect system information bssh -C all-servers --output-dir ./system-info "uname -a; df -h; free -m" # Debug failed services bssh -C webservers --output-dir ./debug "systemctl status nginx"
Read ARCHITECTURE documentation for more information.
cargo build
cargo testcargo run -- -H localhost "echo hello"This project's SSH functionality is built using:
-
russh : A pure Rust implementation of the SSH protocol, providing a modern and safe foundation for SSH communications without relying on C libraries. This is the core SSH library used directly as a dependency.
-
Implementation patterns from async-ssh2-tokio : While not used as a direct dependency, portions of the implementation code and architectural patterns from async-ssh2-tokio have been adapted and integrated into this project to provide high-level async/await APIs that work seamlessly with the Tokio runtime.
This combination enables bssh to achieve high performance parallel SSH operations while maintaining memory safety and avoiding common security vulnerabilities associated with traditional C-based SSH implementations.
This project is licensed under the Apache License 2.0.
See the LICENSE file for details.
- v2.1.0 (2026年04月14日): Migrate to Rust 2024 edition, apply 2024 edition clippy improvements (guard clauses with
if let ... && condition), introduceEnvGuardRAII wrapper for safe environment variable handling in tests (#179, #181), and pinbytesto v1.11.1 - v2.0.1 (2026年04月13日): Add bssh-keygen to Debian package build pipeline, bump bssh-russh to 0.60.1 with security updates (RUSTSEC-2023-0071 RSA Marvin Attack fix), update RC dependencies to latest versions
- v2.0.0 (2026年04月13日): Major release — bssh-server SSH server for containers with SFTP/SCP, PTY/shell sessions, password + public-key auth; audit logging (file/OpenTelemetry/Logstash); IP access control, rate limiting, session management, file transfer filtering; bssh-keygen tool; SSH idle-disconnect fix via proper keepalive wiring (inactivity_timeout override + TCP SO_KEEPALIVE); bssh-russh fork synced with upstream russh 0.60.0 (rand 0.10 stable, updated RustCrypto chain); separate packaging for bssh and bssh-server
- v1.7.0 (2026年01月09日): Add SSH keepalive support with --server-alive-interval and --server-alive-count-max options to prevent idle connection timeouts (#122), update dependencies (russh 0.56, ratatui 0.30, whoami 2.0)
- v1.6.0 (2025年12月19日): Add jump_host field support in config.yaml (issue #115), fix SSH config ProxyJump directive application, fix jump host authentication with empty SSH agent (issues #116, #117)
- v1.5.1 (2025年12月18日): Fix SSH disconnect error handling during authentication for password fallback (issue #113)
- v1.5.0 (2025年12月18日): Add pdsh compatibility mode with -w/-x/-f/-N/-b/-k/-q options, pdsh-style hostlist expressions (node[1-5], rack[1-2]-node[1-3]), in-TUI log panel, --connect-timeout option, --fail-fast/-k and --batch/-b flags, fix --timeout 0 handling for unlimited execution
- v1.4.2 (2025年12月16日): Fix terminal escape sequence responses displayed on first prompt when starting tmux, fix paste not working in PTY sessions, bump dependencies
- v1.4.1 (2025年12月16日): Add comprehensive TUI/streaming tests (84 new tests), extend password fallback for SSH agent auth failures, add TUI module documentation
- v1.4.0 (2025年12月15日): Add --sudo-password flag for automated sudo authentication, password fallback with improved SSH debugging, developer tooling (githooks)
- v1.3.0 (2025年12月10日): Add interactive TUI with 4 view modes (Summary/Detail/Split/Diff), multi-node stream management, and fix terminal escape sequence filtering in PTY sessions
- v1.2.2 (2025年10月29日): Improve Backend.AI auto-detection with comprehensive host heuristics (localhost, IPv4, user@host, FQDN, IPv6)
- v1.2.1 (2025年10月28日): Fix password authentication fallback in interactive mode and test race condition with RankDetector
- v1.2.0 (2025年10月27日): Add exit code strategy with main rank exit code (matching MPI tools), comprehensive tests, and improved documentation
- v1.1.0 (2025年10月24日): Add macOS Keychain integration for SSH key passphrases (UseKeychain option) with automatic password fallback and ProxyUseFdpass support
- v1.0.0 (2025年10月24日): Major milestone release with comprehensive SSH configuration support (~71 options), certificate authentication, advanced security features, and modular parser architecture
- v0.9.1 (2025年10月14日): Complete PTY terminal modes implementation with Shift key input support
- v0.9.0 (2025年10月14日): Add SSH ProxyJump support for file transfers and interactive mode, update packages
- v0.8.0 (2025年09月12日): Add comprehensive SSH port forwarding (local/remote/dynamic), improve error messages and remove dangerous unwrap() calls
- v0.7.0 (2025年08月30日): Add SSH jump host (-J) infrastructure and CLI integration, improve Ubuntu PPA support and fix deprecated GitHub Actions
- v0.6.1 (2025年08月28日): Rebrand from 'Backend.AI SSH' to 'Broadcast SSH' to emphasize the tool's core broadcast/parallel functionality
- v0.6.0 (2025年08月28日): Add SSH config file support (-F), PTY allocation, security enhancements, performance improvements, and SSH-compatible command-line interface
- v0.5.4 (2025年08月27日): Fix parallel config value handling and align interactive mode authentication with exec mode
- v0.5.3 (2025年08月27日): Use Backend.AI cluster SSH key for auto-detected environments
- v0.5.2 (2025年08月27日): Fix config file loading priority, improve BACKENDAI environment handling, use cluster SSH key config
- v0.5.1 (2025年08月25日): Add configurable command timeout with support for unlimited execution (timeout=0), configurable via CLI and config file
- v0.5.0 (2025年08月22日): Add interactive mode with single-node and multiplex support, broadcast command, and improved Backend.AI cluster auto-detection
- v0.4.0 (2025年08月22日): Add password authentication, SSH key passphrase support, modern UI with colors, XDG config compliance, and Debian packaging
- v0.3.0 (2025年08月22日): Add native SFTP directory operations and recursive file transfer support
- v0.2.0 (2025年08月21日): Added Backend.AI multi-node session support with SSH authentication, host key verification, environment variable expansion, timeouts, and SCP file copy functionality.
- v0.1.0 (2025年08月21日): Initial release with parallel SSH execution using async-ssh2-tokio