{"id":49758003,"url":"https://github.com/yamaiday/sshm","last_synced_at":"2026-05-17T07:10:22.587Z","repository":{"id":357005893,"uuid":"1234943815","full_name":"YaMaiDay/sshm","owner":"YaMaiDay","description":"Terminal SSH server manager for monitoring, login, file transfer, commands, and   deployments.","archived":false,"fork":false,"pushed_at":"2026-05-15T05:10:15.000Z","size":520,"stargazers_count":6,"open_issues_count":6,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-15T05:52:24.955Z","etag":null,"topics":["bubbletea","cli","devops","go","rsync","server-management","ssh","terminal","tui"],"latest_commit_sha":null,"homepage":"https://github.com/YaMaiDay/sshm/wiki","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/YaMaiDay.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","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":"2026-05-10T20:55:33.000Z","updated_at":"2026-05-15T05:10:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/YaMaiDay/sshm","commit_stats":null,"previous_names":["yamaiday/sshm"],"tags_count":50,"template":false,"template_full_name":null,"purl":"pkg:github/YaMaiDay/sshm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YaMaiDay%2Fsshm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YaMaiDay%2Fsshm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YaMaiDay%2Fsshm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YaMaiDay%2Fsshm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/YaMaiDay","download_url":"https://codeload.github.com/YaMaiDay/sshm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YaMaiDay%2Fsshm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33130272,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-17T06:27:06.342Z","status":"ssl_error","status_checked_at":"2026-05-17T06:26:59.432Z","response_time":107,"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":["bubbletea","cli","devops","go","rsync","server-management","ssh","terminal","tui"],"created_at":"2026-05-11T00:02:07.831Z","updated_at":"2026-05-17T07:10:22.581Z","avatar_url":"https://github.com/YaMaiDay.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003esshm\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eA terminal SSH server manager for monitoring, login, file transfer, commands, and deployments.\u003c/strong\u003e\n  \u003cbr\u003e\n  Local-first, agentless, and built on top of OpenSSH and rsync.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/YaMaiDay/sshm/releases\"\u003e\u003cimg alt=\"Release\" src=\"https://img.shields.io/github/v/release/YaMaiDay/sshm?style=for-the-badge\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/YaMaiDay/sshm/actions/workflows/release.yml\"\u003e\u003cimg alt=\"Release Build\" src=\"https://img.shields.io/github/actions/workflow/status/YaMaiDay/sshm/release.yml?label=release\u0026style=for-the-badge\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/YaMaiDay/sshm/actions/workflows/codeql.yml\"\u003e\u003cimg alt=\"CodeQL\" src=\"https://img.shields.io/github/actions/workflow/status/YaMaiDay/sshm/codeql.yml?label=codeql\u0026style=for-the-badge\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/YaMaiDay/sshm\"\u003e\u003cimg alt=\"Go\" src=\"https://img.shields.io/badge/Go-1.24-00ADD8?style=for-the-badge\u0026logo=go\u0026logoColor=white\"\u003e\u003c/a\u003e\n  \u003ca href=\"#-installation\"\u003e\u003cimg alt=\"Platform\" src=\"https://img.shields.io/badge/macOS%20%7C%20Linux%20%7C%20Windows-supported-2ea44f?style=for-the-badge\"\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg alt=\"License\" src=\"https://img.shields.io/badge/license-Apache--2.0-blue?style=for-the-badge\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"#-installation\"\u003eInstallation\u003c/a\u003e ·\n  \u003ca href=\"#-features\"\u003eFeatures\u003c/a\u003e ·\n  \u003ca href=\"docs/troubleshooting.md\"\u003eTroubleshooting\u003c/a\u003e ·\n  \u003ca href=\"https://github.com/YaMaiDay/sshm/releases\"\u003eDownloads\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/demo-v3.svg\" alt=\"sshm demo\" width=\"920\"\u003e\n\u003c/p\u003e\n\n---\n\n## ⚡ Installation\n\nmacOS / Linux:\n\n```sh\ncurl -fsSL https://raw.githubusercontent.com/YaMaiDay/sshm/main/install.sh | sh\n```\n\nWindows PowerShell:\n\n```powershell\nirm https://raw.githubusercontent.com/YaMaiDay/sshm/main/install.ps1 | iex\n```\n\nRun:\n\n```sh\nsshm\n```\n\nThe install script downloads the matching package from GitHub Releases and verifies it with the same-version `checksums.txt`.\n\n### Manual Download And Verification\n\nIf you do not want to use the install script, download the archive for your platform from [Releases](https://github.com/YaMaiDay/sshm/releases), then download the same release's `checksums.txt`.\n\nmacOS / Linux:\n\n```sh\nshasum -a 256 sshm_v*_darwin_arm64.tar.gz\ncat checksums.txt\n```\n\nWindows PowerShell:\n\n```powershell\nGet-FileHash .\\sshm_v*_windows_amd64.zip -Algorithm SHA256\ntype .\\checksums.txt\n```\n\nAfter the local SHA256 matches `checksums.txt`, extract and run the binary. Releases also include `sbom.spdx.json` and GitHub Artifact Attestations for build provenance.\n\n## ✨ Features\n\n|  |  |\n| --- | --- |\n| 🖥️ | TUI dashboard with card, group, category, and narrow-screen layouts |\n| 🌐 | English-first language setting, with Chinese available as a secondary language |\n| 📊 | CPU, memory, mounted disks, load, swap, inode, and uptime |\n| 🐳 | Docker containers, listening ports, health checks, and failed services |\n| 🔐 | Uses the system `ssh`, preserving the native terminal experience |\n| 🪜 | Bastion / jump host support with private keys kept on the local machine |\n| 🚀 | App deployment with Git, GitHub Releases, command stages, history, and rollback |\n| 🛡️ | Login summary and SSH risk hints |\n| 🧰 | Command templates, batch commands, and command history |\n| 📁 | File and directory upload/download with multi-select, task history, and progress |\n| 🗂️ | Categories, rename, pin, favorite, notes, expiration dates, and server copy |\n| 🔄 | Migration from OpenSSH config |\n\n## 🚀 Common Workflows\n\n|  |  |\n| --- | --- |\n| 🧑‍💻 | Manage many servers with categories, pins, favorites, and search |\n| 📊 | Check CPU, memory, mounted disks, containers, and basic health |\n| 🔐 | Press `Enter` to open SSH for the selected server |\n| 🧰 | Press `m` for command templates and `b` for batch commands |\n| 🚀 | Press `g` for Git or GitHub Release based deployment |\n| 📁 | Press `u` / `d` to upload or download files and `y` to view transfer jobs |\n| 🛡️ | Inspect failed logins and SSH risk information |\n\n## 📁 File Transfers\n\nsshm uses `rsync` for file transfers, which works well for large files and directories.\n\n|  | Description |\n| --- | --- |\n| ✅ | Create upload/download jobs from multiple selected files or directories |\n| 📊 | Transfer cards show status, direction, paths, progress, speed, and errors |\n| ⏸️ | Pause and resume interrupted jobs while preserving partial files |\n| 🧾 | Keep up to 100 completed, failed, or canceled transfer records |\n| 🧭 | Return to the dashboard while transfers continue in the background |\n| 🚪 | Running transfers are marked interrupted when sshm exits |\n\nIf a server uses a bastion host, upload, download, login, command execution, and monitoring all reuse the same SSH connection logic through that bastion.\n\n## 🚀 App Deployment\n\nsshm deployment is a lightweight release workflow: select a server, fetch a Git or GitHub Release resource, run command stages, record the result, and optionally roll back. It reuses the existing SSH, bastion, and rsync connection logic and does not install a remote agent.\n\nPress `g` to open the global deployment app list. Each app is bound to one target server; running that app only connects to its configured server. The list supports card/list views, category filtering, pins, favorites, multi-select queues, and last deploy/rollback status.\n\nFetch modes:\n\n| Fetch Mode | Description |\n| --- | --- |\n| Local fetch then upload | sshm accesses GitHub locally, then uploads the resource to the target server with rsync. GitHub credentials stay local |\n| Remote fetch | The target server accesses GitHub directly. GitHub credentials must exist on that server |\n\nResource sources:\n\n| Source | Description |\n| --- | --- |\n| Git | Run `git clone`, `git fetch`, and `git pull --ff-only` |\n| Release | Download a GitHub Release asset, extract it into a version directory, and switch `current` |\n\nRelease asset matching:\n\n| Value | Description |\n| --- | --- |\n| `app_linux_amd64.tar.gz` | Exact asset name. With an empty version or `latest`, sshm downloads this asset from the latest Release |\n| `freedex-trade-kernel-amd64-*` | Wildcard match for assets with dates, commits, or build numbers in the filename |\n\nIf a full download URL is configured, sshm uses it directly instead of building a GitHub Release URL.\n\nDeployment stages:\n\n| Stage | Description |\n| --- | --- |\n| Pre-update | Stop services, back up files, or prepare directories |\n| Fetch resource | Generated from source/fetch/repo/version/asset/path/credential settings, or customized in the app |\n| Update | Build, install dependencies, migrate databases, or switch services |\n| Post-update | Restart services or clean temporary files |\n| Health check | Run checks such as `curl http://127.0.0.1:8080/health` |\n| Rollback | Separate rollback command stage, executed only from the rollback flow |\n\nDeploy and rollback are separate confirmation flows. `Enter` opens deploy confirmation and only shows the deploy stages. After a deployment output page is open, `r` enters rollback confirmation and runs only the rollback commands.\n\nGitHub credentials are stored as references only; sshm does not store private key contents or token values.\n\n| Credential Type | Credential Parameter |\n| --- | --- |\n| SSH Key | Local fetch: local private key path. Remote fetch: target-server private key path |\n| Token | Local fetch: local environment variable name. Remote fetch: target-server environment variable name |\n\nFor private Git repositories, prefer a least-privilege GitHub Deploy Key. For private Release assets, use a minimal token.\n\nSee [Deployment](docs/deployment.md) for the full workflow.\n\n## 📊 Monitoring Model\n\nsshm does not install an agent on remote servers. Monitoring data is collected by running one SSH command on the target server.\n\n| Metric | Source |\n| --- | --- |\n| CPU | CPU time delta, core count, and model |\n| Memory | System memory, available memory, and swap |\n| Disk | Mounted real filesystems from `df -PT -B1` |\n| inode | Root filesystem inode data from `df -Pi /` |\n\nDisk data is based on mounted filesystems, not raw block device names. sshm shows real mount points such as `/`, `/boot`, `/data`, and `/mnt/xxx`, and filters temporary or system filesystems such as `tmpfs`, `devtmpfs`, `proc`, `sysfs`, and `overlay`. Unmounted partitions are not shown because they have no filesystem usage percentage.\n\nThe dashboard disk card highlights the real mounted filesystem with the highest usage. If that mount point is not `/`, it is shown as labels such as `disk/data` or `disk/mnt/xxx`. The detail page lists mount point, device, filesystem type, usage, capacity, and available space.\n\n## 🧭 Usage\n\n```text\n1. Run sshm\n2. Press a to add a server\n3. Press Enter to save\n4. Use the dashboard to monitor, log in, transfer files, and run commands\n```\n\nCommon keys:\n\n| Key | Action |\n| --- | --- |\n| `a` | Add server |\n| `e` | Edit server |\n| `x` | Delete server |\n| `Tab` / `←` / `→` | Switch category |\n| `Enter` | SSH into selected server |\n| `u` / `d` | Upload / download |\n| `m` | Command templates |\n| `b` | Batch commands |\n| `y` | Transfer jobs |\n| `g` | App deployments |\n| `.` | Settings |\n\n## 📚 Documentation\n\n| Document | Description |\n| --- | --- |\n| [Troubleshooting](docs/troubleshooting.md) | SSH, bastion hosts, rsync, GitHub, disks, and container status |\n| [Security Policy](SECURITY.md) | Security boundaries, sensitive data, and local files |\n| [Changelog](CHANGELOG.md) | User-visible changes |\n\n## 📦 Dependencies\n\n| Command | Purpose |\n| --- | --- |\n| `ssh` | Login and monitoring collection |\n| `rsync` | Upload/download and resumable transfers |\n| `sshpass` | Optional password-login automation |\n\nmacOS:\n\n```sh\nbrew install hudochenkov/sshpass/sshpass\n```\n\nDebian / Ubuntu:\n\n```sh\nsudo apt install openssh-client rsync sshpass\n```\n\nRemote servers also need `rsync` for file transfer and local-fetch deployment. If a remote server is missing `rsync`, sshm asks before attempting installation. Without permission, installation fails explicitly.\n\n## 📁 Configuration\n\n| File | Purpose |\n| --- | --- |\n| `~/.config/sshm/servers.toml` | Servers |\n| `~/.config/sshm/commands.toml` | Command templates |\n| `~/.config/sshm/history.toml` | Command history |\n| `~/.config/sshm/transfers.toml` | Transfer jobs and history |\n| `~/.config/sshm/deployments.toml` | Deployment apps and records |\n| `~/.config/sshm/config.toml` | App settings |\n\nPress `.` on the dashboard to open settings. Common settings can be edited in the TUI without manually editing `config.toml`.\n\n| Setting | Description |\n| --- | --- |\n| Language | `en` / `zh`. Default is English |\n| ASCII mode | Reserved for terminals that need plain ASCII display |\n| Refresh interval | Dashboard collection interval, for example `5s`, `30s`, or `1m` |\n| Connect timeout | SSH connection timeout, for example `2s` or `5s` |\n| Command timeout | Monitoring and remote-command timeout, for example `6s` or `30s` |\n| CPU / memory / disk thresholds | Warning and critical colors used by dashboard and detail pages |\n| Local roots | Local shortcut directories used by the transfer picker, comma-separated |\n| Remote roots | Remote shortcut directories used by the transfer picker, comma-separated |\n\n\u003cdetails\u003e\n\u003csummary\u003eMore Configuration Details\u003c/summary\u003e\n\nWindows config paths:\n\n```text\n%USERPROFILE%\\.config\\sshm\\servers.toml\n%USERPROFILE%\\.config\\sshm\\commands.toml\n%USERPROFILE%\\.config\\sshm\\history.toml\n%APPDATA%\\sshm\\config.toml\n```\n\nAuthentication behavior:\n\n- With `key_path`: use the server's configured key.\n- With `password`: allow password/PAM login through `sshpass`.\n- With both key and password: try key first, then password.\n- With neither: let OpenSSH / ssh-agent handle authentication.\n\nCategory behavior:\n\n- Normal categories can be created, renamed, and deleted when empty.\n- `Bastion` is a fixed category used for bastion / jump hosts.\n- The fixed bastion category cannot be renamed or deleted.\n- If a bastion server is referenced by another server, its name and category cannot be changed.\n\nCommon fields:\n\n```toml\ncategory = \"production\"\nname = \"demo-web\"\nhost = \"203.0.113.10\"\nuser = \"deploy\"\nport = 22\nkey_path = \"~/.ssh/id_ed25519\"\nnote = \"Production Web entry\"\nexpire_at = \"2026-08-31\"\nfavorite = true\npinned = true\npinned_order = 1\nhealth_ports = [80, 443, 8080]\n```\n\nA bastion is also a monitorable server. Internal servers reference the bastion by name. All private-key paths point to local private-key files; the bastion only forwards SSH connections and does not store target-server private keys.\n\nAfter configuration, selecting an internal server and pressing `Enter` opens SSH directly to that internal server. Monitoring, command templates, upload, and download also operate on the internal server, not on the bastion itself.\n\n```toml\ncategory = \"Bastion\"\nname = \"bastion-prod-01\"\nhost = \"203.0.113.10\"\nuser = \"deploy\"\nport = 22\nkey_path = \"~/.ssh/bastion_key\"\n\ncategory = \"production\"\nname = \"internal-web\"\nhost = \"10.0.2.21\"\nuser = \"deploy\"\nport = 22\nkey_path = \"~/.ssh/app_key\"\njump_host_ref = \"bastion-prod-01\"\n```\n\nEquivalent connection path:\n\n```text\nlocal machine --SSH--\u003e bastion --SSH--\u003e target server\n```\n\nBoth private keys stay on the local machine. sshm creates a temporary OpenSSH config and calls system `ssh` / `rsync`; it never copies target-server keys to the bastion.\n\n\u003c/details\u003e\n\n## 🔒 Security, Privacy, And Network Behavior\n\nsshm is a local SSH management tool. It has no telemetry, does not check for updates in the background, and does not report server data to project infrastructure.\n\n|  | Description |\n| --- | --- |\n| 🌐 | No runtime GitHub update checks |\n| 📊 | No telemetry, analytics, or crash reporting |\n| 🛰️ | No background calls to GitHub or project servers |\n| 📡 | No upload of server lists, IPs, usernames, paths, command history, or transfer history |\n| 🚫 | No remote agent installation |\n| 🧱 | Does not modify remote `sshd_config` |\n| 🔑 | Does not upload private keys |\n| 🪜 | In bastion mode, target-server keys still stay local |\n| 🗂️ | Does not scan `/root` by default |\n| 🔐 | Login directly calls the system `ssh` |\n| 📁 | File transfer runs directly between the local machine and target server through `rsync` |\n\nPasswords are stored locally in `servers.toml` with file permissions set to `600`.\n\nNetwork access only happens when:\n\n- The user runs `install.sh` / `install.ps1`, which downloads from GitHub Releases.\n- The user confirms remote `rsync` installation, which invokes the target server's package manager.\n- The user connects to their own servers, runs commands, uploads files, or downloads files.\n\n## 📄 License\n\nApache 2.0. See [LICENSE](LICENSE).\n\n---\n\n### ⭐ If sshm is useful to you, a star is appreciated.\n\n[Report a bug](https://github.com/YaMaiDay/sshm/issues/new) ·\n[Request a feature](https://github.com/YaMaiDay/sshm/issues/new) ·\n[Join discussions](https://github.com/YaMaiDay/sshm/discussions)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyamaiday%2Fsshm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyamaiday%2Fsshm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyamaiday%2Fsshm/lists"}