Skip to content
sakura86.com
戻る

WordPressからAstroへ移行した話(4)GitHub ActionsでFTP自動デプロイ

はじめに

前回は331件の記事を移行スクリプトで変換しました。
今回はGitHubにpushするだけでAstroのビルドからサーバーへのデプロイまで自動化するCI/CDを構築します。

コアサーバーの制約

コアサーバーはSSH接続に「接続元IPアドレスの事前承認制」を採用しています。
GitHub ActionsのランナーはIPが動的に変わるため、SSH/SFTPは使用不可です。FTP一択になります。

GitHub Secrets の登録

リポジトリの Settings → Secrets and variables → Actions → New repository secret から以下を登録します。

シークレット名内容
FTP_SERVERFTPサーバーのホスト名
FTP_USERNAMEFTPユーザー名
FTP_PASSWORDFTPパスワード
FTP_SERVER_DIRアップロード先ディレクトリ(末尾に/必須

ワークフローファイル

.github/workflows/deploy.yml を作成します。

name: Build and Deploy to Coreserver

on:
  push:
    branches:
      - main

concurrency:
  group: deploy
  cancel-in-progress: true

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4.2.2

      - name: Setup Node.js
        uses: actions/setup-node@v4.4.0
        with:
          node-version: '22'
          cache: 'npm'

      - name: Cache Astro build
        uses: actions/cache@v4
        with:
          path: .astro
          key: ${{ runner.os }}-astro-${{ hashFiles('src/data/blog/**', 'src/pages/**', 'src/layouts/**', 'src/components/**') }}
          restore-keys: |
            ${{ runner.os }}-astro-

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npx astro build

      - name: Deploy HTML/CSS/JS via FTP (differential)
        uses: SamKirkland/FTP-Deploy-Action@v4.3.5
        with:
          server: ${{ secrets.FTP_SERVER }}
          username: ${{ secrets.FTP_USERNAME }}
          password: ${{ secrets.FTP_PASSWORD }}
          server-dir: ${{ secrets.FTP_SERVER_DIR }}
          local-dir: ./dist/
          exclude: |
            **/posts/**

      - name: Deploy new images via FTP
        env:
          FTP_SERVER: ${{ secrets.FTP_SERVER }}
          FTP_USERNAME: ${{ secrets.FTP_USERNAME }}
          FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
          FTP_SERVER_DIR: ${{ secrets.FTP_SERVER_DIR }}
        run: |
          sudo apt-get install -y lftp
          lftp -u "$FTP_USERNAME,$FTP_PASSWORD" \
            -e "set ftp:ssl-allow no; set net:timeout 60; mirror -R --only-missing ./dist/posts/ ${FTP_SERVER_DIR}posts/; quit" \
            ftp://$FTP_SERVER

設計のポイント

デプロイを2ステップに分けた理由

ステップ対象方式理由
ステップ1HTML/CSS/JS差分転送(FTP-Deploy-Action)記事を更新するたびに変わるので差分のみ送る
ステップ2画像(posts/)未存在ファイルのみ転送(lftp --only-missing一度アップした画像は変わらないため毎回再送しない

画像を差分転送に含めると、331件分の大量ファイルが毎回転送対象になってしまいます。
--only-missing で「サーバーにまだないファイルだけ」送ることで効率化しています。

concurrency の設定

連続でpushした場合に複数のワークフローが同時実行されると、FTP転送が競合してサーバー上の状態が壊れる可能性があります。
cancel-in-progress: true にすることで新しいpushが来たら古いビルドをキャンセルし、常に最新のコードだけがデプロイされます。

lftpを使う理由

FTP-Deploy-Actionはコアサーバーとの相性が悪く、大量ファイル転送時に ECONNRESET エラーが頻発しました。
画像転送には安定性の高い lftp を使うことで解消しました。

ハマりポイント

  • FTP_SERVER_DIR の末尾に / がないと転送先パスがずれてエラーになります。必ず末尾に / を付けてください
  • FTP-Deploy-Action は .ftp-deploy-sync-state.json をサーバーに保存して差分管理するため、初回は全ファイルが転送されます

まとめ

コアサーバーのSSH制約があってもFTPで問題なく自動デプロイできます。
2ステップデプロイとlftpの組み合わせで安定した運用が実現できました。

次回はGoogle AdSenseの設置方法を紹介します。