Skip to content

Repository files navigation

ssherd

Run commands on many servers at once — one Python file, zero dependencies, powered by your OpenSSH client.

CI License: MIT Python

English | 简体中文

ssherd is a small batch-SSH CLI for server fleets. Your ~/.ssh/config (or a project-local .ssh/config) is the inventory: ssherd reads the Host aliases, fans out commands in parallel, and lets the real ssh client handle everything it already does best — addresses, jump hosts (ProxyJump), users, keys, host keys.

Works on Linux, macOS, and Windows (Git-Bash / PowerShell).

ssherd running whoami on 16 servers at once, grouping identical output into one block

Features

  • Single file, zero dependencies — copy ssherd.py anywhere, needs only Python 3.9+ and ssh
  • SSH config as inventory — selectors by name, comma list, or range (web-01..web-16, all)
  • Parallel execution with a live per-device progress bar
  • Smart grouped output — identical results collapse into one block, outliers shown as compact diffs (--diff)
  • Jump hosts / keys / users — all resolved natively by OpenSSH, never re-implemented
  • Password auth support via OpenSSH's official SSH_ASKPASS_REQUIRE=force (no sshpass, never touches your tty)
  • Sudo fan-outsudo -S wrapping with one local password prompt
  • add-user — generates plain, auditable bash commands by default (--exec to run them)

Installation

pipx install ssherd    # isolated venv + global command (recommended)
pip install ssherd     # or plain pip — works on any OS

Requirements: Python 3.9+ and the OpenSSH client (ssh) you already have.

Prefer no installer at all? It's one self-contained file — grab it, read it, hack it:

curl -fsSL https://raw.githubusercontent.com/trdthg/ssherd/master/ssherd.py \
  -o ~/.local/bin/ssherd && chmod +x ~/.local/bin/ssherd

Uninstall: pipx uninstall ssherd or pip uninstall ssherd.

Quick start

# the inventory is just your ssh config Host aliases
python -m ssherd list

# run in parallel across a range
python -m ssherd run web-01..web-16 -- whoami

# comma lists and single hosts work too
python -m ssherd run web-01,web-05,db-01 -- hostname

# sudo: prompts once, wraps remotely with sudo -S
python -m ssherd run --sudo db-01..db-32 -- apt update

# scriptable: pass passwords inline (note: lands in shell history)
python -m ssherd run --sudo=SUDOPASS db-01 -- systemctl restart nginx

# group identical outputs, show only the differences
python -m ssherd run all --diff -- 'cat /etc/os-release'

Inventory

Devices are the Host entries in your SSH config (Host * wildcards are skipped):

Host web-01
    HostName 192.0.2.10
    User deploy
    # ProxyJump jumpbox   ← jump hosts just work, ssh handles them

A .ssh/config in the current directory takes precedence over ~/.ssh/config, so a fleet per project is one folder away. Put .ssh/ in .gitignore and real IPs never get committed. Selectors accept aliases, comma lists, ranges (web-01..web-16), and all / *.

Creating users

add-user prints the plain bash commands (useradd / usermod / chpasswd) for you to audit and paste, or to wrap in your own loop. Add --exec to fan them out through the same parallel channel:

python -m ssherd add-user web-01..web-16 deploy
python -m ssherd add-user web-01..web-16 deploy --sudo --password 'TempPass-123' --exec

Why not Ansible / pssh / fabric?

They are great; this is for the other 90% of ops work: one-off fleet commands where you refuse to install anything, write a playbook, or learn a DSL. ssherd delegates all connection semantics to OpenSSH, so anything your ssh can reach, ssherd can reach — including bastion hosts.

Tests

python -m unittest discover -v

License

MIT

About

Run commands on many servers at once — one Python file, zero dependencies, powered by your OpenSSH client.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages