{"id":13474655,"url":"https://github.com/appleboy/ssh-action","last_synced_at":"2026-01-28T04:58:31.566Z","repository":{"id":37405989,"uuid":"186202082","full_name":"appleboy/ssh-action","owner":"appleboy","description":"GitHub Actions for executing remote ssh commands.","archived":false,"fork":false,"pushed_at":"2025-04-27T04:35:16.000Z","size":620,"stargazers_count":5354,"open_issues_count":26,"forks_count":620,"subscribers_count":35,"default_branch":"master","last_synced_at":"2025-05-07T23:38:13.464Z","etag":null,"topics":["github-actions","ssh","ssh-client"],"latest_commit_sha":null,"homepage":"https://github.com/marketplace/actions/ssh-remote-commands","language":"Shell","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/appleboy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":null,"patreon":null,"open_collective":"ssh-action","ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":["https://www.paypal.me/appleboy46"]}},"created_at":"2019-05-12T02:28:18.000Z","updated_at":"2025-05-07T11:27:34.000Z","dependencies_parsed_at":"2023-12-15T22:00:49.447Z","dependency_job_id":"ff42be1c-2d6b-43d0-8e13-fce6e6adfcd7","html_url":"https://github.com/appleboy/ssh-action","commit_stats":{"total_commits":164,"total_committers":16,"mean_commits":10.25,"dds":0.09146341463414631,"last_synced_commit":"d732991ab09097d8c8f390d91385b0386e619598"},"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appleboy%2Fssh-action","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appleboy%2Fssh-action/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appleboy%2Fssh-action/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appleboy%2Fssh-action/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/appleboy","download_url":"https://codeload.github.com/appleboy/ssh-action/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253602043,"owners_count":21934431,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["github-actions","ssh","ssh-client"],"created_at":"2024-07-31T16:01:13.863Z","updated_at":"2026-01-28T04:58:31.545Z","avatar_url":"https://github.com/appleboy.png","language":"Shell","funding_links":["https://opencollective.com/ssh-action","https://www.paypal.me/appleboy46"],"categories":["Dockerfile","Community Resources","Shell","Deployment","github-actions","网络信息服务"],"sub_categories":["Deployment","网络服务_其他"],"readme":"# 🚀 SSH for GitHub Actions\n\nEnglish | [繁體中文](./README.zh-tw.md) | [简体中文](./README.zh-cn.md)\n\n## Table of Contents\n\n- [🚀 SSH for GitHub Actions](#-ssh-for-github-actions)\n  - [Table of Contents](#table-of-contents)\n  - [📖 Introduction](#-introduction)\n  - [🧩 Core Concepts \\\u0026 Input Parameters](#-core-concepts--input-parameters)\n    - [🔌 Connection Settings](#-connection-settings)\n    - [🛠️ SSH Command Settings](#️-ssh-command-settings)\n    - [🌐 Proxy Settings](#-proxy-settings)\n  - [📤 Output Variables](#-output-variables)\n  - [⚡ Quick Start](#-quick-start)\n  - [🔑 SSH Key Setup \\\u0026 OpenSSH Compatibility](#-ssh-key-setup--openssh-compatibility)\n    - [Setting Up SSH Keys](#setting-up-ssh-keys)\n      - [Generate RSA key](#generate-rsa-key)\n      - [Generate ED25519 key](#generate-ed25519-key)\n    - [OpenSSH Compatibility](#openssh-compatibility)\n  - [🛠️ Usage Scenarios \\\u0026 Advanced Examples](#️-usage-scenarios--advanced-examples)\n    - [Using password authentication](#using-password-authentication)\n    - [Using private key authentication](#using-private-key-authentication)\n    - [Multiple commands](#multiple-commands)\n    - [Run commands from a file](#run-commands-from-a-file)\n    - [Multiple hosts](#multiple-hosts)\n    - [Multiple hosts with different ports](#multiple-hosts-with-different-ports)\n    - [Synchronous execution on multiple hosts](#synchronous-execution-on-multiple-hosts)\n    - [Pass environment variables to shell script](#pass-environment-variables-to-shell-script)\n    - [Capturing command output](#capturing-command-output)\n  - [🌐 Proxy \\\u0026 Jump Host Usage](#-proxy--jump-host-usage)\n  - [🛡️ Security Best Practices](#️-security-best-practices)\n    - [Protecting Your Private Key](#protecting-your-private-key)\n    - [Host Fingerprint Verification](#host-fingerprint-verification)\n  - [🚨 Error Handling \\\u0026 Troubleshooting](#-error-handling--troubleshooting)\n    - [Q\\\u0026A](#qa)\n      - [Command not found (npm or other command)](#command-not-found-npm-or-other-command)\n  - [🤝 Contributing](#-contributing)\n  - [📝 License](#-license)\n\n---\n\n## 📖 Introduction\n\n**SSH for GitHub Actions** is a powerful [GitHub Action](https://github.com/features/actions) for executing remote SSH commands easily and securely in your CI/CD workflows.  \nBuilt with [Golang](https://go.dev) and [drone-ssh](https://github.com/appleboy/drone-ssh), it supports a wide range of SSH scenarios, including multi-host, proxy, and advanced authentication.\n\n![ssh workflow](./images/ssh-agent.png)\n\n[![testing main branch](https://github.com/appleboy/ssh-action/actions/workflows/main.yml/badge.svg)](https://github.com/appleboy/ssh-action/actions/workflows/main.yml)\n[![Trivy Security Scan](https://github.com/appleboy/ssh-action/actions/workflows/trivy-scan.yml/badge.svg)](https://github.com/appleboy/ssh-action/actions/workflows/trivy-scan.yml)\n\n**Slides:** [SSH for GitHub Actions](https://speakerdeck.com/appleboy/ssh-for-github-actions)\n\n---\n\n## 🧩 Core Concepts \u0026 Input Parameters\n\nThis action provides flexible SSH command execution with a rich set of configuration options.\n\nFor full details, see [action.yml](./action.yml).\n\n### 🔌 Connection Settings\n\nThese parameters control how the action connects to your remote host.\n\n| Parameter           | Description                                                       | Default |\n| ------------------- | ----------------------------------------------------------------- | ------- |\n| host                | SSH host address                                                  |         |\n| port                | SSH port number                                                   | 22      |\n| username            | SSH username                                                      |         |\n| password            | SSH password                                                      |         |\n| protocol            | SSH protocol version (`tcp`, `tcp4`, `tcp6`)                      | tcp     |\n| sync                | Run synchronously if multiple hosts are specified                 | false   |\n| timeout             | Timeout for SSH connection to host                                | 30s     |\n| key                 | Content of SSH private key (e.g., raw content of `~/.ssh/id_rsa`) |         |\n| key_path            | Path to SSH private key                                           |         |\n| passphrase          | Passphrase for the SSH private key                                |         |\n| fingerprint         | SHA256 fingerprint of the host public key                         |         |\n| use_insecure_cipher | Allow additional (less secure) ciphers                            | false   |\n| cipher              | Allowed cipher algorithms. Uses sensible defaults if unspecified  |         |\n\n---\n\n### 🛠️ SSH Command Settings\n\nThese parameters control the commands executed on the remote host and related behaviors.\n\n| Parameter       | Description                                                                       | Default |\n| --------------- | --------------------------------------------------------------------------------- | ------- |\n| script          | Commands to execute remotely                                                      |         |\n| script_path     | Path to a file in the repository containing commands to execute remotely          |         |\n| envs            | Environment variables to pass to the shell script                                 |         |\n| envs_format     | Flexible configuration for environment variable transfer                          |         |\n| allenvs         | Pass all environment variables with `GITHUB_` and `INPUT_` prefixes to the script | false   |\n| command_timeout | Timeout for SSH command execution                                                 | 10m     |\n| debug           | Enable debug mode                                                                 | false   |\n| request_pty     | Request a pseudo-terminal from the server                                         | false   |\n| curl_insecure   | Allow curl to connect to SSL sites without certificates                           | false   |\n| capture_stdout  | Capture standard output from commands as action output                            | false   |\n| version         | drone-ssh binary version. If not specified, the latest version will be used.      |         |\n\n---\n\n### 🌐 Proxy Settings\n\nThese parameters control the use of a proxy (jump host) for connecting to your target host.\n\n| Parameter                 | Description                                     | Default |\n| ------------------------- | ----------------------------------------------- | ------- |\n| proxy_host                | SSH proxy host                                  |         |\n| proxy_port                | SSH proxy port                                  | 22      |\n| proxy_username            | SSH proxy username                              |         |\n| proxy_password            | SSH proxy password                              |         |\n| proxy_passphrase          | SSH proxy key passphrase                        |         |\n| proxy_protocol            | SSH proxy protocol version                      | tcp     |\n| proxy_timeout             | Timeout for SSH connection to proxy host        | 30s     |\n| proxy_key                 | Content of SSH proxy private key                |         |\n| proxy_key_path            | Path to SSH proxy private key                   |         |\n| proxy_fingerprint         | SHA256 fingerprint of the proxy host public key |         |\n| proxy_cipher              | Allowed cipher algorithms for the proxy         |         |\n| proxy_use_insecure_cipher | Allow insecure ciphers for the proxy            | false   |\n\n\u003e **Note:** To mimic the removed `script_stop` option, add `set -e` at the top of your shell script.\n\n---\n\n## 📤 Output Variables\n\nThis action provides the following outputs that you can use in subsequent steps:\n\n| Output | Description                                                                |\n| ------ | -------------------------------------------------------------------------- |\n| stdout | Standard output of the executed commands (requires `capture_stdout: true`) |\n\n---\n\n## ⚡ Quick Start\n\nRun remote SSH commands in your workflow with minimal configuration:\n\n```yaml\nname: Remote SSH Command\non: [push]\njobs:\n  build:\n    name: Build\n    runs-on: ubuntu-latest\n    steps:\n      - name: Execute remote SSH commands using password\n        uses: appleboy/ssh-action@v1\n        with:\n          host: ${{ secrets.HOST }}\n          username: ${{ secrets.USERNAME }}\n          password: ${{ secrets.PASSWORD }}\n          port: ${{ secrets.PORT }}\n          script: whoami\n```\n\n**Output:**\n\n```sh\n======CMD======\nwhoami\n======END======\nout: your_username\n===============================================\n✅ Successfully executed commands to all hosts.\n===============================================\n```\n\n---\n\n## 🔑 SSH Key Setup \u0026 OpenSSH Compatibility\n\n### Setting Up SSH Keys\n\nIt is best practice to create SSH keys on your local machine (not on a remote server). Log in with the username specified in GitHub Secrets and generate a key pair:\n\n#### Generate RSA key\n\n```bash\nssh-keygen -t rsa -b 4096 -C \"your_email@example.com\"\n```\n\n#### Generate ED25519 key\n\n```bash\nssh-keygen -t ed25519 -a 200 -C \"your_email@example.com\"\n```\n\nAdd the new public key to the authorized keys on your server. [Learn more about authorized keys.](https://www.ssh.com/ssh/authorized_keys/)\n\n```bash\n# Add RSA key\ncat .ssh/id_rsa.pub | ssh user@host 'cat \u003e\u003e .ssh/authorized_keys'\n\n# Add ED25519 key\ncat .ssh/id_ed25519.pub | ssh user@host 'cat \u003e\u003e .ssh/authorized_keys'\n```\n\nCopy the private key content and paste it into GitHub Secrets.\n\n```bash\n# macOS\npbcopy \u003c ~/.ssh/id_rsa\n# Ubuntu\nxclip \u003c ~/.ssh/id_rsa\n```\n\n\u003e **Tip:** Copy from `-----BEGIN OPENSSH PRIVATE KEY-----` to `-----END OPENSSH PRIVATE KEY-----` (inclusive).\n\nFor ED25519:\n\n```bash\n# macOS\npbcopy \u003c ~/.ssh/id_ed25519\n# Ubuntu\nxclip \u003c ~/.ssh/id_ed25519\n```\n\nSee more: [SSH login without a password](http://www.linuxproblem.org/art_9.html).\n\n\u003e **Note:** Depending on your SSH version, you may also need to:\n\u003e\n\u003e - Place the public key in `.ssh/authorized_keys2`\n\u003e - Set `.ssh` permissions to 700\n\u003e - Set `.ssh/authorized_keys2` permissions to 640\n\n### OpenSSH Compatibility\n\nIf you see this error:\n\n```bash\nssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey]\n```\n\nOn Ubuntu 20.04+ you may need to explicitly allow the `ssh-rsa` algorithm. Add this to your OpenSSH daemon config (`/etc/ssh/sshd_config` or a drop-in under `/etc/ssh/sshd_config.d/`):\n\n```text\nCASignatureAlgorithms +ssh-rsa\n```\n\nAlternatively, use ED25519 keys (supported by default):\n\n```bash\nssh-keygen -t ed25519 -a 200 -C \"your_email@example.com\"\n```\n\n---\n\n## 🛠️ Usage Scenarios \u0026 Advanced Examples\n\nThis section covers common and advanced usage patterns, including multi-host, proxy, and environment variable passing.\n\n### Using password authentication\n\n```yaml\n- name: Execute remote SSH commands using password\n  uses: appleboy/ssh-action@v1\n  with:\n    host: ${{ secrets.HOST }}\n    username: ${{ secrets.USERNAME }}\n    password: ${{ secrets.PASSWORD }}\n    port: ${{ secrets.PORT }}\n    script: whoami\n```\n\n### Using private key authentication\n\n```yaml\n- name: Execute remote SSH commands using SSH key\n  uses: appleboy/ssh-action@v1\n  with:\n    host: ${{ secrets.HOST }}\n    username: ${{ secrets.USERNAME }}\n    key: ${{ secrets.KEY }}\n    port: ${{ secrets.PORT }}\n    script: whoami\n```\n\n### Multiple commands\n\n```yaml\n- name: Multiple commands\n  uses: appleboy/ssh-action@v1\n  with:\n    host: ${{ secrets.HOST }}\n    username: ${{ secrets.USERNAME }}\n    key: ${{ secrets.KEY }}\n    port: ${{ secrets.PORT }}\n    script: |\n      whoami\n      ls -al\n```\n\n![result](./images/output-result.png)\n\n### Run commands from a file\n\n```yaml\n- name: File commands\n  uses: appleboy/ssh-action@v1\n  with:\n    host: ${{ secrets.HOST }}\n    username: ${{ secrets.USERNAME }}\n    key: ${{ secrets.KEY }}\n    port: ${{ secrets.PORT }}\n    script_path: scripts/script.sh\n```\n\n### Multiple hosts\n\n```diff\n  - name: Multiple hosts\n    uses: appleboy/ssh-action@v1\n    with:\n-     host: \"foo.com\"\n+     host: \"foo.com,bar.com\"\n      username: ${{ secrets.USERNAME }}\n      key: ${{ secrets.KEY }}\n      port: ${{ secrets.PORT }}\n      script: |\n        whoami\n        ls -al\n```\n\nDefault `port` is `22`.\n\n### Multiple hosts with different ports\n\n```diff\n  - name: Multiple hosts\n    uses: appleboy/ssh-action@v1\n    with:\n-     host: \"foo.com\"\n+     host: \"foo.com:1234,bar.com:5678\"\n      username: ${{ secrets.USERNAME }}\n      key: ${{ secrets.KEY }}\n      script: |\n        whoami\n        ls -al\n```\n\n### Synchronous execution on multiple hosts\n\n```diff\n  - name: Multiple hosts\n    uses: appleboy/ssh-action@v1\n    with:\n      host: \"foo.com,bar.com\"\n+     sync: true\n      username: ${{ secrets.USERNAME }}\n      key: ${{ secrets.KEY }}\n      port: ${{ secrets.PORT }}\n      script: |\n        whoami\n        ls -al\n```\n\n### Pass environment variables to shell script\n\n```diff\n  - name: Pass environment\n    uses: appleboy/ssh-action@v1\n+   env:\n+     FOO: \"BAR\"\n+     BAR: \"FOO\"\n+     SHA: ${{ github.sha }}\n    with:\n      host: ${{ secrets.HOST }}\n      username: ${{ secrets.USERNAME }}\n      key: ${{ secrets.KEY }}\n      port: ${{ secrets.PORT }}\n+     envs: FOO,BAR,SHA\n      script: |\n        echo \"I am $FOO\"\n        echo \"I am $BAR\"\n        echo \"sha: $SHA\"\n```\n\n\u003e _All environment variables in the `env` object must be strings. Using integers or other types may cause unexpected results._\n\n### Capturing command output\n\nYou can capture the standard output of remote commands and use it in subsequent steps:\n\n```yaml\n- name: Execute and capture output\n  id: ssh\n  uses: appleboy/ssh-action@v1\n  with:\n    host: ${{ secrets.HOST }}\n    username: ${{ secrets.USERNAME }}\n    key: ${{ secrets.KEY }}\n    port: ${{ secrets.PORT }}\n    capture_stdout: true\n    script: |\n      echo \"Hello World\"\n      hostname\n\n- name: Use captured output\n  run: echo \"SSH output was ${{ steps.ssh.outputs.stdout }}\"\n```\n\n---\n\n## 🌐 Proxy \u0026 Jump Host Usage\n\nYou can connect to remote hosts via a proxy (jump host) for advanced network topologies.\n\n```bash\n+--------+       +----------+      +-----------+\n| Laptop | \u003c--\u003e  | Jumphost | \u003c--\u003e | FooServer |\n+--------+       +----------+      +-----------+\n```\n\nExample `~/.ssh/config`:\n\n```text\nHost Jumphost\n  HostName Jumphost\n  User ubuntu\n  Port 22\n  IdentityFile ~/.ssh/keys/jump_host.pem\n\nHost FooServer\n  HostName FooServer\n  User ubuntu\n  Port 22\n  ProxyCommand ssh -q -W %h:%p Jumphost\n```\n\n**GitHub Actions YAML:**\n\n```diff\n  - name: SSH proxy command\n    uses: appleboy/ssh-action@v1\n    with:\n      host: ${{ secrets.HOST }}\n      username: ${{ secrets.USERNAME }}\n      key: ${{ secrets.KEY }}\n      port: ${{ secrets.PORT }}\n+     proxy_host: ${{ secrets.PROXY_HOST }}\n+     proxy_username: ${{ secrets.PROXY_USERNAME }}\n+     proxy_key: ${{ secrets.PROXY_KEY }}\n+     proxy_port: ${{ secrets.PROXY_PORT }}\n      script: |\n        mkdir abc/def\n        ls -al\n```\n\n---\n\n## 🛡️ Security Best Practices\n\n### Protecting Your Private Key\n\nA passphrase encrypts your private key, making it useless to attackers if leaked. Always store your private key securely.\n\n```diff\n  - name: SSH key passphrase\n    uses: appleboy/ssh-action@v1\n    with:\n      host: ${{ secrets.HOST }}\n      username: ${{ secrets.USERNAME }}\n      key: ${{ secrets.KEY }}\n      port: ${{ secrets.PORT }}\n+     passphrase: ${{ secrets.PASSPHRASE }}\n      script: |\n        whoami\n        ls -al\n```\n\n### Host Fingerprint Verification\n\nVerifying the SSH host fingerprint helps prevent man-in-the-middle attacks. To get your host's fingerprint (replace `ed25519` with your key type and `example.com` with your host):\n\n```sh\nssh example.com ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub | cut -d ' ' -f2\n```\n\nUpdate your config:\n\n```diff\n  - name: SSH key passphrase\n    uses: appleboy/ssh-action@v1\n    with:\n      host: ${{ secrets.HOST }}\n      username: ${{ secrets.USERNAME }}\n      key: ${{ secrets.KEY }}\n      port: ${{ secrets.PORT }}\n+     fingerprint: ${{ secrets.FINGERPRINT }}\n      script: |\n        whoami\n        ls -al\n```\n\n---\n\n## 🚨 Error Handling \u0026 Troubleshooting\n\n### Q\u0026A\n\n#### Command not found (npm or other command)\n\nIf you encounter \"command not found\" errors, see [this issue comment](https://github.com/appleboy/ssh-action/issues/31#issuecomment-1006565847) about interactive vs non-interactive shells.\n\nOn many Linux distros, `/etc/bash.bashrc` contains:\n\n```sh\n# If not running interactively, don't do anything\n[ -z \"$PS1\" ] \u0026\u0026 return\n```\n\nComment out this line or use absolute paths for your commands.\n\n---\n\n## 🤝 Contributing\n\nContributions are welcome! Please submit a pull request to help improve `appleboy/ssh-action`.\n\n---\n\n## 📝 License\n\nThis project is licensed under the [MIT License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fappleboy%2Fssh-action","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fappleboy%2Fssh-action","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fappleboy%2Fssh-action/lists"}