跳到主要內容
DevOps 與環境

跨儲存庫自動化:用 GitHub Actions 將 A 專案部署到 B 專案的 GitHub Pages (綁定自訂網域)

手把手教你如何使用 GitHub Actions 將 A 儲存庫的靜態網頁自動部署到 B 儲存庫的 GitHub Pages,並綁定 example.com 自訂網域。

你可能有一個私有專案放 A 儲存庫,裡面是 Astro、Hugo 之類的靜態網站原始程式碼。你不希望公開這些 code,但你又想把 build 出來的 HTML/CSS 推送到另一個公開的 B 儲存庫,用它來開 GitHub Pages。

每次改完 code 都要手動下 npm run build,然後把檔案複製到 B 專案再 push 上去,這流程重複幾次就會讓人想放棄。

其實你可以用 GitHub Actions 自動搞定這一切。

部署流程一覽

這套自動化流程的基本原理如下:

  1. 觸發 當你將原始程式碼 push 到 A 儲存庫(Repo A)時,GitHub Actions 會自動啟動工作流。
  2. 編譯 在 GitHub 的虛擬環境(Runner)中安裝專案相依性,並執行 npm run build 編譯出靜態網頁檔案(通常在 dist 資料夾)。
  3. 驗證與推送 根據你選擇的認證方案(方案一:SSH Deploy Key,或方案二:Fine-grained tokens),Actions 會自動設定連線驗證,並在 dist 底下建立 CNAME 網域檔,最後以「強制推送 (Force Push)」的方式將所有編譯好的網頁檔案推送到 B 儲存庫(Repo B)的部署分支。
  4. 釋出 B 儲存庫收到檔案後,GitHub Pages 就會自動抓取這些靜態檔案,並透過你的自訂網域 example.com 發布出去。

跨儲存庫自動部署流程


權限防線:選擇最安全的認證方式

跨專案推送檔案需要身分驗證。在動手之前,我們要先選好驗證方式。常見的有兩種:

認證方式權限範圍安全性過期機制缺點
Fine-grained tokens僅限選定的單一專案⚠️ 高可自訂(亦可設為不會過期)需注意 Token 生命週期,若無過期則風險較高
SSH Deploy Key僅限該儲存庫不會過期(除非手動撤銷)設定手續稍微多一些

該選哪一種?取決於你比較在意什麼:

  • 想要設定簡單、走 HTTPS 傳輸 → 選 Fine-grained tokens(細粒度個人存取權杖)
  • 想要最高安全性,且不想把個人帳號 Token 授權給 Actions 專案 → 選 Deploy Key(部署金鑰)

以下我們會先以 Deploy Key 為例進行設定,並在後面補充 Fine-grained tokens 的設定方式。


方案一:使用 SSH Deploy Key 部署

這是最安全且最不需要維護的方案。Deploy Key 本質上是一對 SSH keypair,你把私鑰給 Repo A(來源),公鑰給 Repo B(目標)。Repo A 的 Actions 就能憑藉私鑰把檔案推送到 Repo B。

步驟一:產生 SSH Key Pair

在你的電腦打開終端機,執行以下指令產生金鑰:

# 產生一組 ed25519 格式的 SSH 金鑰
ssh-keygen -t ed25519 -C "github-actions-deploy" -f ./id_deploy

你會在目錄下得到兩個檔案:

  • id_deploy:私鑰,千萬不能外流。
  • id_deploy.pub:公鑰,準備要放到 GitHub 上的。

步驟二:設定 Repo B 的部署金鑰

你要告訴 Repo B:拿著這支公鑰的人,擁有寫入檔案的權限。

  1. 開啟 Repo B 的 GitHub 頁面。
  2. 進入 Settings(設定)> Deploy keys(部署金鑰)。
  3. 點選 Add deploy key
    • Title 輸入 Repo A Deploy Action
    • Key 欄位貼上 id_deploy.pub 的完整內容。
    • Allow write access 一定要勾選,否則 Actions 沒辦法推 code 上來。

步驟三:設定 Repo A 的 Actions Secrets

接著你要把私鑰給 Repo A,讓它在跑 Workflow 時能透過身分驗證。

  1. 開啟 Repo A 的 GitHub 頁面。
  2. 進入 Settings > Secrets and variables > Actions。
  3. 點選 New repository secret
    • Name 填 ACTIONS_DEPLOY_KEY
    • Value 貼上 id_deploy(私鑰)的完整內容。

設定完之後,就可以把電腦裡暫存的 id_deployid_deploy.pub 刪掉了。

步驟四:撰寫 GitHub Actions Workflow

我們要在 Repo A 建立工作流檔案。當你 push 到 main 分支時,它會自動 build 專案,然後使用我們配置的 SSH 私鑰推送到 Repo B。

在 Repo A 建立 .github/workflows/deploy.yml 檔案:

name: Deploy Website

on:
  push:
    branches:
      - main  # 當 main 分支有 push 時觸發

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout source code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 24

      - name: Install dependencies and build
        run: |
          npm ci
          npm run build  # 產生靜態檔案,通常輸出到 dist 資料夾

      - name: Configure SSH
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.ACTIONS_DEPLOY_KEY }}" > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519
          ssh-keyscan github.com >> ~/.ssh/known_hosts  # 將 GitHub 加入信任主機,避免連線時詢問

      - name: Deploy to B repo
        run: |
          cd dist
          echo "example.com" > CNAME                     # 寫入自訂網域,防止網域設定被覆蓋
          git init -b main
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add .
          git commit -m "Deploy from Repo A Action"
          git branch -M main
          git push -f git@github.com:your-username/repo-b.git main:main  # 以 SSH 強制推送至目標儲存庫

這段 Workflow 做了三件事:

  1. 設定 SSH 連線 建立 ~/.ssh 目錄,將 Secrets 中的 ACTIONS_DEPLOY_KEY 私鑰寫入為 id_ed25519,並利用 ssh-keyscan 將 GitHub 的公鑰指紋寫入 known_hosts,避免 Git 連線時因為「未確認的主機」而中斷。
  2. 寫入 CNAME 網域檔這一步非常關鍵)進入 build 出來的 dist 目錄,寫入一個包含你網域的 CNAME 檔案。如果不手動在目錄中寫入 CNAME,每次 Actions 覆蓋 B 專案時,都會把你手動在 B 專案設定的自訂網域清空。
  3. 強制推送至 Repo B 在這個目錄中初始化一個臨時的 Git 儲存庫,並以強推(Force Push)的方式覆蓋 Repo B 的分支。

方案二:使用 Fine-grained tokens 部署

如果你覺得手動產生 SSH Key Pair 太麻煩,可以選擇用 GitHub 的 Fine-grained tokens。它能指定該 Token 只能存取特定的儲存庫,同樣能做到權限限縮。

步驟一:申請 Fine-grained tokens

  1. 點選你的 GitHub 頭像,進入 Settings。
  2. 拉到最下方,點選左側選單的 Developer settings。
  3. 選擇 Personal access tokens > Fine-grained tokens,點選 Generate new token。
  4. 設定 Token 內容:
    • Token name 輸入方便辨識的名字,例如 Deploy to Repo B
    • Expiration 選擇過期時間(可依需求設定,亦可選擇 No expiration 讓其不會過期)。
    • Repository access 選擇 Only select repositories,並在下拉選單中選定你的 Repo B
    • Permissions 展開 Repository permissions,找到 Contents 並將權限設為 Access: Read and write
  5. 點選 Generate token,並複製產生的 Token(只會顯示一次)。

步驟二:設定 Repo A 的 Secrets

  1. 開啟 Repo A 的 GitHub 頁面。
  2. 進入 Settings > Secrets and variables > Actions。
  3. 點選 New repository secret
    • Name 填 ACTIONS_PAT
    • Value 貼上剛才複製的 Fine-grained tokens。

步驟三:修改 Workflow 檔案

如果改用 Fine-grained tokens,你就不用在 Actions 裡面安裝與配置 SSH 金鑰了。你只需要在推送時將 Token 帶入 HTTPS 網址中。

將 Repo A 中的 .github/workflows/deploy.yml 內容修改為:

name: Deploy Website

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout source code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 24

      - name: Install dependencies and build
        run: |
          npm ci
          npm run build

      - name: Deploy to B repo
        run: |
          cd dist
          echo "example.com" > CNAME
          git init -b main
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add .
          git commit -m "Deploy from Repo A Action"
          git branch -M main
          # 使用 Fine-grained tokens 透過 HTTPS 方式強制推送
          git push -f https://x-access-token:${{ secrets.ACTIONS_PAT }}@github.com/your-username/repo-b.git main:main

這裡的關鍵在於這一行:

https://x-access-token:${{ secrets.ACTIONS_PAT }}@github.com/your-username/repo-b.git

這是 GitHub 官方推薦在 Actions 中使用 PAT(Personal Access Token)進行 HTTPS 驗證的方法。x-access-token 是固定的使用者名稱,密碼則帶入你的 Token,這樣 Git 就能安全地完成驗證並進行強推。


設定 DNS 網域解析(兩種方案皆適用)

最後,去你的網域託管商(例如 Cloudflare 或 Namecheap)設定 DNS,把 example.com 對接到 GitHub Pages。

如果是子網域(如 blog.example.com),新增一條 CNAME 紀錄:

  • Type(類型)CNAME
  • Name(名稱)blog
  • Target(目標)your-username.github.io

如果是頂級網域(如 example.com),你需要設定 A 紀錄,指向 GitHub Pages 的 IP:

  • 185.199.108.153
  • 185.199.109.153
  • 185.199.110.153
  • 185.199.111.153

結語

跨專案部署聽起來很繞,其實關鍵只有一個:建立兩個 Repo 之間的信任通道。

不論是透過 SSH Deploy Key 還是 Fine-grained tokens,都能在保證帳號安全的前提下完成自動化部署。這套流程設定好一次,以後你就只需要專心寫 code 了。