{"id":47516125,"url":"https://github.com/Blackmamoth/sshsync","last_synced_at":"2026-04-01T07:00:44.310Z","repository":{"id":291841458,"uuid":"975711238","full_name":"Blackmamoth/sshsync","owner":"Blackmamoth","description":null,"archived":false,"fork":false,"pushed_at":"2025-06-18T15:42:44.000Z","size":667,"stargazers_count":160,"open_issues_count":3,"forks_count":7,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-03-05T11:38:25.385Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Blackmamoth.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-04-30T19:10:38.000Z","updated_at":"2025-12-01T04:55:34.000Z","dependencies_parsed_at":"2025-06-11T09:35:50.984Z","dependency_job_id":"56fcee42-f188-4300-8b30-a87294f5fb17","html_url":"https://github.com/Blackmamoth/sshsync","commit_stats":null,"previous_names":["blackmamoth/sshsync"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Blackmamoth/sshsync","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Blackmamoth%2Fsshsync","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Blackmamoth%2Fsshsync/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Blackmamoth%2Fsshsync/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Blackmamoth%2Fsshsync/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Blackmamoth","download_url":"https://codeload.github.com/Blackmamoth/sshsync/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Blackmamoth%2Fsshsync/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31269179,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T06:57:45.811Z","status":"ssl_error","status_checked_at":"2026-04-01T06:57:42.389Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-03-27T13:00:30.248Z","updated_at":"2026-04-01T07:00:44.305Z","avatar_url":"https://github.com/Blackmamoth.png","language":"Python","funding_links":[],"categories":["\u003ca name=\"networking\"\u003e\u003c/a\u003eNetworking"],"sub_categories":[],"readme":"# sshsync ⚡🔐\n\n**sshsync** is a fast, minimal CLI tool to run shell commands across multiple remote servers via SSH. Easily target all servers or just a specific group, great for sysadmins, developers, and automation workflows.\n\n\u003e **IMPORTANT**:\n\u003e \n\u003e 1. sshsync uses asyncssh for SSH connections. If you use passphrase-protected SSH keys, you MUST have your ssh-agent running with the keys added via ssh-add. sshsync will rely on SSH agent forwarding to authenticate with protected keys.\n\u003e 2. Throughout this documentation, whenever \"host\" is mentioned, it refers to the SSH alias defined by the `Host` directive in your `~/.ssh/config` file, not the actual hostname (`HostName` directive). sshsync uses these aliases for all operations.\n\n## Features ✨\n\n- 🔁 Run shell commands on **all hosts** or **specific groups**\n- 🚀 Executes commands **concurrently** across servers\n- 🧠 Group-based configuration for easy targeting\n- 🕒 Adjustable SSH timeout settings\n- 📁 **Push/pull files** between local and remote hosts\n- 📊 Operation history and logging\n- 🔍 **Dry-run mode** to preview actions before execution\n\n## Demo 📽️\n\n![Demo](./demo.gif)\n\n## Installation 📦\n\n### Requirements\n\n- Python 3.10 or higher\n\n### Install with pip\n\n```bash\npip install sshsync\n```\n\n### Manual Installation\n\nClone and install manually:\n\n```bash\ngit clone https://github.com/Blackmamoth/sshsync.git\ncd sshsync\npipx install .\n```\n\n## Usage 🚀\n\n```bash\nsshsync [OPTIONS] COMMAND [ARGS]...\n```\n\n**Global Options:**\n\n- `--install-completion` - Install completion for the current shell\n- `--show-completion` - Show completion for the current shell\n- `--help` - Show help message and exit\n\n## Commands \u0026 Usage 🛠️\n\n```bash\nsshsync [OPTIONS] COMMAND [ARGS]...\n```\n\n### Running Commands on Servers\n\n#### Execute on All Hosts\n\n```bash\nsshsync all [OPTIONS] CMD\n```\n\n**Options:**\n\n- `--timeout INTEGER` - Timeout in seconds for SSH command execution (default: 10)\n- `--dry-run` - Show command and host info without executing\n\n**Examples:**\n\n```bash\n# Check disk space on all servers with a 20 second timeout\nsshsync all --timeout 20 \"df -h\"\n\n# Preview which hosts would receive the command without executing\nsshsync all --dry-run \"systemctl restart nginx\"\n```\n\n#### Execute on a Specific Group\n\n```bash\nsshsync group [OPTIONS] NAME CMD\n```\n\n**Options:**\n\n- `--timeout INTEGER` - Timeout in seconds for SSH command execution (default: 10)\n- `--dry-run` - Show command and host info without executing\n- `--regex` - Filter group members by matching alias with a regex pattern\n\n**Examples:**\n\n```bash\n# Restart web services on production servers\nsshsync group web-servers \"sudo systemctl restart nginx\"\n\n# Preview the command execution on database servers without executing\nsshsync group db-servers --dry-run \"service postgresql restart\"\n```\n\n### File Transfer Operations\n\n#### Push Files to Remote Hosts\n\n```bash\nsshsync push [OPTIONS] LOCAL_PATH REMOTE_PATH\n```\n\n**Options:**\n\n- `--all` - Push to all configured hosts\n- `--group TEXT` - Push to a specific group of hosts\n- `--regex` - Filter group members by matching alias with a regex pattern (can only be used with `--group`)\n- `--host TEXT` - Push to a single specific host\n- `--recurse` - Recursively push a directory and its contents\n- `--dry-run` - Show transfer and host info without executing\n\n**Examples:**\n\n```bash\n# Push configuration file to all hosts\nsshsync push --all ./config.yml /etc/app/config.yml\n\n# Push directory to web-servers group recursively\nsshsync push --group web-servers --recurse ./app/ /var/www/app/\n\n# Preview file transfer to a specific host without executing\nsshsync push --host staging-db --dry-run ./db-config.json /etc/postgres/conf.d/\n```\n\n#### Pull Files from Remote Hosts\n\n```bash\nsshsync pull [OPTIONS] REMOTE_PATH LOCAL_PATH\n```\n\n**Options:**\n\n- `--all` - Pull from all configured hosts\n- `--group TEXT` - Pull from a specific group of hosts\n- `--regex` - Filter group members by matching alias with a regex pattern (can only be used with `--group`)\n- `--host TEXT` - Pull from a single specific host\n- `--recurse` - Recursively pull a directory and its contents\n- `--dry-run` - Show transfer and host info without executing\n\n**Examples:**\n\n```bash\n# Pull log files from all database servers\nsshsync pull --group db-servers /var/log/mysql/error.log ./logs/\n\n# Pull configuration directory from a specific host\nsshsync pull --host prod-web-01 --recurse /etc/nginx/ ./backups/nginx-configs/\n\n# Preview which files would be pulled without executing\nsshsync pull --group web-servers --dry-run /var/log/nginx/access.log ./logs/\n```\n\n### Configuration Management\n\n#### Add Hosts to Groups\n\n```bash\nsshsync gadd [OPTIONS] GROUP\n```\n\n**Arguments:**\n\n- `GROUP` - The group to add hosts to (required)\n\n**Example:**\n\n```bash\n# Add hosts to the 'web' group\nsshsync gadd web\n```\n\n#### Add a Host to SSH Config\n\n```bash\nsshsync hadd [OPTIONS]\n```\n\nThis command interactively adds a new host to your SSH config file.\n\n**Example:**\n\n```bash\n# Add a new host to your SSH configuration\nsshsync hadd\n```\n\n#### Synchronize Ungrouped Hosts\n\n```bash\nsshsync sync [OPTIONS]\n```\n\nThis command prompts for group assignments for all ungrouped hosts and updates the config.\n\n**Example:**\n\n```bash\n# Assign groups to all ungrouped hosts\nsshsync sync\n```\n\n#### List Configured Hosts and Groups\n\n```bash\nsshsync ls [OPTIONS]\n```\n\n**Options:**\n\n- `--with-status` - Show whether a host is reachable\n\n**Example:**\n\n```bash\n# List all hosts with their connection status\nsshsync ls --with-status\n```\n\n#### Show Version\n\n```bash\nsshsync version\n```\n\n## Configuration 🔧\n\n\u003e sshsync stores its configuration in a YAML file located at `~/.config/sshsync/config.yaml`. It uses your existing SSH configuration from `~/.ssh/config` for host connection details and stores only group information in its own config file. Before running other commands, it's recommended to run `sshsync sync` to assign hosts to groups for easier targeting.\n\u003e \n\u003e **Note about hosts**: sshsync uses the SSH alias (the `Host` directive) from your `~/.ssh/config` file, not the actual hostname. This means when you specify a host in any sshsync command, you're referring to the SSH alias that you've defined in your SSH config.\n\n### Configuration File Structure\n\n```yaml\ngroups:\n  dev:\n  - example.site\n  work:\n  - work.dev\n  - ssh.work.dev\n  web:\n  - cloudmesh\n  - example.com\n```\n\nYou can edit this file manually or use the built-in commands to manage groups and hosts.\n\n\u003e **Note**: sshsync leverages your existing SSH configuration for host details, making it easier to maintain a single source of truth for SSH connections.\n\n## Logging 📝\n\nsshsync now includes operation history and logging functionality. Logs are stored in platform-specific locations:\n\n- **Windows**: `%LOCALAPPDATA%\\sshsync\\logs`\n- **macOS**: `~/Library/Logs/sshsync`\n- **Linux**: `~/.local/state/sshsync`\n\nThese logs track command executions, file transfers, and any errors that occur during operations.\n\n## Examples 🧪\n\n```bash\n# Check disk space on all servers\nsshsync all \"df -h\"\n\n# View memory usage on all database servers with increased timeout\nsshsync group db-servers --timeout 30 \"free -m\"\n\n# Preview a potentially destructive command without execution\nsshsync all --dry-run \"sudo apt update \u0026\u0026 sudo apt upgrade -y\"\n\n# Push configuration files to production servers recursively\nsshsync push --group production --recurse ./configs/ /etc/app/configs/\n\n# Pull log files from all web servers\nsshsync pull --group web-servers /var/log/nginx/error.log ./logs/\n\n# Preview file transfers to validate paths before execution\nsshsync push --all --dry-run ./sensitive-config.json /etc/app/config.json\n\n# Add hosts to the dev group\nsshsync gadd dev\n\n# Add a new host to your SSH configuration\nsshsync hadd\n\n# Assign groups to all ungrouped hosts\nsshsync sync\n\n# Check if hosts are reachable\nsshsync ls --with-status\n```\n\n## Upcoming Features 🛣️\n\n- Live results display (--live flag) to show command outputs as they complete\n- Performance optimizations for large server fleets\n- Support for additional authentication methods\n- Automated versioning using release-please for streamlined releases\n\n## License 📄\n\nMIT License\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FBlackmamoth%2Fsshsync","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FBlackmamoth%2Fsshsync","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FBlackmamoth%2Fsshsync/lists"}