🚀 GitHub Actions 的 SSH

December 22, 2025 · View on GitHub

English | 繁體中文 | 简体中文

目錄


📖 簡介

SSH for GitHub Actions 是一個強大的 GitHub Action,可讓你在 CI/CD 工作流程中輕鬆且安全地執行遠端 SSH 指令。
本專案以 Golangdrone-ssh 建立,支援多主機、代理、進階認證等多種 SSH 場景。

ssh workflow

testing main branch Trivy Security Scan

簡報: SSH for GitHub Actions


🧩 核心概念與輸入參數

本 Action 提供彈性的 SSH 指令執行能力,並具備豐富的設定選項。

完整參數請參閱 action.yml

🔌 連線設定

這些參數用於控制如何連線到遠端主機。

參數說明預設值
hostSSH 主機位址
portSSH 埠號22
usernameSSH 使用者名稱
passwordSSH 密碼
protocolSSH 協議版本(tcptcp4tcp6tcp
sync指定多個主機時同步執行false
timeoutSSH 連線主機的逾時時間30s
keySSH 私鑰內容(如 ~/.ssh/id_rsa 的原始內容)
key_pathSSH 私鑰路徑
passphraseSSH 私鑰密碼
fingerprint主機公鑰的 SHA256 指紋
use_insecure_cipher允許額外(不安全)的加密演算法false
cipher允許的加密演算法,未指定時使用預設值

🛠️ 指令設定

這些參數用於控制在遠端主機上執行的指令及相關行為。

參數說明預設值
script遠端執行的指令
script_path儲存庫中包含要遠端執行指令的檔案路徑
envs傳遞給 shell 腳本的環境變數
envs_format環境變數傳遞的彈性設定
allenvs傳遞所有帶 GITHUB_INPUT_ 前綴的環境變數到腳本false
command_timeoutSSH 指令執行逾時時間10m
debug啟用除錯模式false
request_pty向伺服器請求偽終端false
curl_insecure允許 curl 連線無憑證的 SSL 網站false
capture_stdout擷取指令的標準輸出作為 Action 輸出false
versiondrone-ssh 執行檔版本,未指定時使用最新版本

🌐 代理設定

這些參數用於透過代理(跳板機)連線到目標主機。

參數說明預設值
proxy_hostSSH 代理主機
proxy_portSSH 代理埠號22
proxy_usernameSSH 代理使用者名稱
proxy_passwordSSH 代理密碼
proxy_passphraseSSH 代理私鑰密碼
proxy_protocolSSH 代理協議版本(tcptcp4tcp6tcp
proxy_timeoutSSH 連線代理主機的逾時時間30s
proxy_keySSH 代理私鑰內容
proxy_key_pathSSH 代理私鑰路徑
proxy_fingerprint代理主機公鑰的 SHA256 指紋
proxy_cipher代理允許的加密演算法
proxy_use_insecure_cipher代理允許額外(不安全)的加密演算法false

注意: 如需實現已移除的 script_stop 功能,請在 shell 腳本最上方加上 set -e


📤 輸出變數

本 Action 提供以下輸出,可在後續步驟中使用:

輸出說明
stdout執行指令的標準輸出(需設定 capture_stdout: true

⚡ 快速開始

只需簡單設定,即可在工作流程中執行遠端 SSH 指令:

name: Remote SSH Command
on: [push]
jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: 執行遠端 SSH 指令(密碼認證)
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          password: ${{ secrets.PASSWORD }}
          port: ${{ secrets.PORT }}
          script: whoami

輸出:

======CMD======
whoami
======END======
out: your_username
===============================================
 Successfully executed commands to all hosts.
===============================================

🔑 SSH 金鑰設定與 OpenSSH 相容性

設定 SSH 金鑰

建議於本地端(非遠端伺服器)產生 SSH 金鑰。請以 GitHub Secrets 指定的使用者名稱登入並產生金鑰對:

產生 RSA 金鑰

ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

產生 ED25519 金鑰

ssh-keygen -t ed25519 -a 200 -C "your_email@example.com"

將新產生的公鑰加入伺服器的 authorized_keys。 了解更多 authorized_keys

# 加入 RSA 公鑰
cat .ssh/id_rsa.pub | ssh user@host 'cat >> .ssh/authorized_keys'

# 加入 ED25519 公鑰
cat .ssh/id_ed25519.pub | ssh user@host 'cat >> .ssh/authorized_keys'

複製私鑰內容並貼到 GitHub Secrets。

# macOS
pbcopy < ~/.ssh/id_rsa
# Ubuntu
xclip < ~/.ssh/id_rsa

提示: 複製內容需包含 -----BEGIN OPENSSH PRIVATE KEY----------END OPENSSH PRIVATE KEY-----(含)。

ED25519 同理:

# macOS
pbcopy < ~/.ssh/id_ed25519
# Ubuntu
xclip < ~/.ssh/id_ed25519

更多資訊:SSH 免密碼登入

注意: 根據 SSH 版本,可能還需:

  • 將公鑰放入 .ssh/authorized_keys2
  • 設定 .ssh 權限為 700
  • 設定 .ssh/authorized_keys2 權限為 640

OpenSSH 相容性

若出現以下錯誤:

ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey]

在 Ubuntu 20.04+,你可能需明確允許 ssh-rsa 演算法。請於 OpenSSH 設定檔(/etc/ssh/sshd_config/etc/ssh/sshd_config.d/ 下的 drop-in 檔案)加入:

CASignatureAlgorithms +ssh-rsa

或直接使用預設支援的 ED25519 金鑰:

ssh-keygen -t ed25519 -a 200 -C "your_email@example.com"

🛠️ 用法場景與進階範例

本節涵蓋常見與進階用法,包括多主機、代理、環境變數傳遞等。

使用密碼認證

- name: 執行遠端 SSH 指令(密碼認證)
  uses: appleboy/ssh-action@v1
  with:
    host: ${{ secrets.HOST }}
    username: ${{ secrets.USERNAME }}
    password: ${{ secrets.PASSWORD }}
    port: ${{ secrets.PORT }}
    script: whoami

使用私鑰認證

- name: 執行遠端 SSH 指令(私鑰認證)
  uses: appleboy/ssh-action@v1
  with:
    host: ${{ secrets.HOST }}
    username: ${{ secrets.USERNAME }}
    key: ${{ secrets.KEY }}
    port: ${{ secrets.PORT }}
    script: whoami

多條指令

- name: 多條指令
  uses: appleboy/ssh-action@v1
  with:
    host: ${{ secrets.HOST }}
    username: ${{ secrets.USERNAME }}
    key: ${{ secrets.KEY }}
    port: ${{ secrets.PORT }}
    script: |
      whoami
      ls -al

result

從檔案執行指令

- name: 檔案指令
  uses: appleboy/ssh-action@v1
  with:
    host: ${{ secrets.HOST }}
    username: ${{ secrets.USERNAME }}
    key: ${{ secrets.KEY }}
    port: ${{ secrets.PORT }}
    script_path: scripts/script.sh

多主機

  - name: 多主機
    uses: appleboy/ssh-action@v1
    with:
-     host: "foo.com"
+     host: "foo.com,bar.com"
      username: ${{ secrets.USERNAME }}
      key: ${{ secrets.KEY }}
      port: ${{ secrets.PORT }}
      script: |
        whoami
        ls -al

預設 port22

多主機不同埠號

  - name: 多主機
    uses: appleboy/ssh-action@v1
    with:
-     host: "foo.com"
+     host: "foo.com:1234,bar.com:5678"
      username: ${{ secrets.USERNAME }}
      key: ${{ secrets.KEY }}
      script: |
        whoami
        ls -al

多主機同步執行

  - name: 多主機
    uses: appleboy/ssh-action@v1
    with:
      host: "foo.com,bar.com"
+     sync: true
      username: ${{ secrets.USERNAME }}
      key: ${{ secrets.KEY }}
      port: ${{ secrets.PORT }}
      script: |
        whoami
        ls -al

傳遞環境變數到 shell 腳本

  - name: 傳遞環境變數
    uses: appleboy/ssh-action@v1
+   env:
+     FOO: "BAR"
+     BAR: "FOO"
+     SHA: ${{ github.sha }}
    with:
      host: ${{ secrets.HOST }}
      username: ${{ secrets.USERNAME }}
      key: ${{ secrets.KEY }}
      port: ${{ secrets.PORT }}
+     envs: FOO,BAR,SHA
      script: |
        echo "I am $FOO"
        echo "I am $BAR"
        echo "sha: $SHA"

env 物件中的所有環境變數必須為字串。傳遞整數或其他型別可能導致非預期結果。

擷取指令輸出

你可以擷取遠端指令的標準輸出,並在後續步驟中使用:

- name: 執行並擷取輸出
  id: ssh
  uses: appleboy/ssh-action@v1
  with:
    host: ${{ secrets.HOST }}
    username: ${{ secrets.USERNAME }}
    key: ${{ secrets.KEY }}
    port: ${{ secrets.PORT }}
    capture_stdout: true
    script: |
      echo "Hello World"
      hostname

- name: 使用擷取的輸出
  run: echo "SSH 輸出為 ${{ steps.ssh.outputs.stdout }}"

🌐 代理與跳板機用法

你可以透過代理(跳板機)連線到遠端主機,適用於進階網路拓撲。

+--------+       +----------+      +-----------+
| Laptop | <-->  | Jumphost | <--> | FooServer |
+--------+       +----------+      +-----------+

範例 ~/.ssh/config

Host Jumphost
  HostName Jumphost
  User ubuntu
  Port 22
  IdentityFile ~/.ssh/keys/jump_host.pem

Host FooServer
  HostName FooServer
  User ubuntu
  Port 22
  ProxyCommand ssh -q -W %h:%p Jumphost

GitHub Actions YAML:

  - name: SSH 代理指令
    uses: appleboy/ssh-action@v1
    with:
      host: ${{ secrets.HOST }}
      username: ${{ secrets.USERNAME }}
      key: ${{ secrets.KEY }}
      port: ${{ secrets.PORT }}
+     proxy_host: ${{ secrets.PROXY_HOST }}
+     proxy_username: ${{ secrets.PROXY_USERNAME }}
+     proxy_key: ${{ secrets.PROXY_KEY }}
+     proxy_port: ${{ secrets.PROXY_PORT }}
      script: |
        mkdir abc/def
        ls -al

🛡️ 安全最佳實踐

保護你的私鑰

密碼短語會加密你的私鑰,即使外洩也無法被攻擊者直接利用。請務必妥善保管私鑰。

  - name: SSH 私鑰密碼
    uses: appleboy/ssh-action@v1
    with:
      host: ${{ secrets.HOST }}
      username: ${{ secrets.USERNAME }}
      key: ${{ secrets.KEY }}
      port: ${{ secrets.PORT }}
+     passphrase: ${{ secrets.PASSPHRASE }}
      script: |
        whoami
        ls -al

主機指紋驗證

驗證 SSH 主機指紋有助於防止中間人攻擊。取得主機指紋(將 ed25519 換成你的金鑰型別,example.com 換成你的主機):

ssh example.com ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub | cut -d ' ' -f2

更新設定:

  - name: SSH 私鑰密碼
    uses: appleboy/ssh-action@v1
    with:
      host: ${{ secrets.HOST }}
      username: ${{ secrets.USERNAME }}
      key: ${{ secrets.KEY }}
      port: ${{ secrets.PORT }}
+     fingerprint: ${{ secrets.FINGERPRINT }}
      script: |
        whoami
        ls -al

🚨 錯誤處理與疑難排解

常見問題

指令找不到(npm 或其他指令)

若遇到 "command not found" 錯誤,請參考 此討論 了解互動式與非互動式 shell 差異。

許多 Linux 發行版的 /etc/bash.bashrc 包含如下內容:

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

請將該行註解掉或使用指令的絕對路徑。


🤝 貢獻

歡迎貢獻!請提交 Pull Request 改善 appleboy/ssh-action


📝 授權

本專案採用 MIT License 授權。