Run commands across multiple servers over SSH — parallel, with jump host support and broadcast shell.
Project description
sshrunner 🚀
A lightweight Python module for running commands across multiple servers simultaneously over SSH — with parallel execution, jump host support, per-host log saving, and an interactive broadcast shell.
Features
- ⚡ Parallel execution — runs commands on all hosts concurrently via threads
- 🔐 SSH key & jump host support — works with bastion/proxy servers
- 📁 Per-host log files — timestamped output saved automatically
- 🖥️ Interactive broadcast mode — type once, runs everywhere
- 🔧 Per-host port override — perfect for Docker/local testing
Installation
pip install sshrunner
paramiko>=3.0 is installed automatically as a dependency.
Quick Start
from sshrunner import SSHRunner
runner = SSHRunner(
hosts=["web1.example.com", "web2.example.com", "db1.example.com"],
username="deploy",
key_path="~/.ssh/id_rsa",
output_dir="./ssh_logs",
)
results = runner.run("uptime")
runner.print_results(results)
runner.run() returns a list of HostResult objects, one per host. Each result exposes:
| Attribute | Type | Description |
|---|---|---|
host |
str |
Host address (and port if non-default) |
stdout |
str |
Standard output from the command |
stderr |
str |
Standard error from the command |
exit_code |
int | None |
Exit code returned by the remote command |
error |
str | None |
Connection or execution error message, if any |
duration |
float |
Time taken in seconds |
ok |
bool |
True if no error and exit_code == 0 |
Docker Testing
Spin up local SSH containers for testing without real servers:
docker-compose -f docker-compose.test.yml up -d
python examples/test_docker.py
See docker-compose.test.yml and examples/test_docker.py for full details.
Per-host port support
from sshrunner import SSHRunner, Host
runner = SSHRunner(
hosts=[
Host("localhost", port=2221),
Host("localhost", port=2222),
Host("localhost", port=2223),
],
username="testuser",
password="testpass",
)
Jump host (bastion)
runner = SSHRunner(
hosts=["10.0.1.10", "10.0.1.11"],
username="deploy",
key_path="~/.ssh/id_rsa",
jump_host="bastion.mycompany.com",
jump_username="bastion-user", # defaults to username if omitted
jump_key_path="~/.ssh/bastion_rsa", # defaults to key_path if omitted
jump_port=22, # defaults to 22
)
Interactive broadcast mode
runner.interactive()
# all> tail -f /var/log/app.log ← runs on every host simultaneously
Type exit or press Ctrl-C to close all sessions.
Configuration Reference
SSHRunner
| Parameter | Default | Description |
|---|---|---|
hosts |
— | List of hostnames, IPs, or Host(addr, port) objects |
username |
— | SSH username |
key_path |
None |
Path to private key (~ expanded) |
password |
None |
Password auth (key preferred) |
port |
22 |
Default SSH port for all hosts |
jump_host |
None |
Bastion/jump host address |
jump_username |
username |
SSH username for the jump host |
jump_key_path |
key_path |
Private key for the jump host |
jump_port |
22 |
SSH port for the jump host |
output_dir |
None |
Directory to save per-host log files |
connect_timeout |
10 |
Connection timeout in seconds |
max_workers |
20 |
Max parallel threads |
print_results(results, show_stderr=True)
| Parameter | Default | Description |
|---|---|---|
results |
— | List of HostResult objects returned by run() |
show_stderr |
True |
Whether to print stderr output for each host |
Roadmap
- YAML/JSON host inventory file support
- CLI interface (
sshrunner --hosts-file servers.yml "uptime") - Colored terminal output
- Retry logic for flaky connections
- Async backend option (
asyncssh)
Requirements
- Python 3.10+
- paramiko >= 3.0
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sshrunner-0.1.0.tar.gz.
File metadata
- Download URL: sshrunner-0.1.0.tar.gz
- Upload date:
- Size: 6.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f4ed741be2af0cfe2a8821fb9dd780ff6ea5a28f9f83ebfd13e37efe051affa8
|
|
| MD5 |
d37093fa04b729882ecd28bf309bd515
|
|
| BLAKE2b-256 |
0d3d03a30918ab43b5182a954774537e81195dfd0d602353ae545b4311380735
|
File details
Details for the file sshrunner-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sshrunner-0.1.0-py3-none-any.whl
- Upload date:
- Size: 7.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5af8edb0c8d628f67f52b3adfaedb8ab7d8305dace5c0faf1d7e5c5c5e81ffef
|
|
| MD5 |
85a5adb2810abce25799144319f30dc1
|
|
| BLAKE2b-256 |
3c223aeb183a60c41fce15bb50d7021be95a38263c5c0befd4ae69725f465ebc
|