1. 実際に解決したかった問題

静的サイトとPHPフォームAPIを組み合わせた構成において、ローカルからFTPクライアント(FileZilla等)を用いた手動ファイル転送は、転送漏れ、不要な開発用ファイルの混入、およびサーバー側設定ファイルの誤上書きリスクがありました。また、問い合わせ宛先メールアドレスやSMTP認証情報をGitリポジトリにコミットせずに本番サーバーへ安全に同期する仕組みが必要でした。

2. 初期構成

SLEEP LATE LABのリポジトリ(sleeplatelab-static)では、Lolipopレンタルサーバー(ライトプラン/ハイスピードプラン)を本番ホスティングとして採用しています。初期はGitHub Actionsの汎用FTP Actionを検証しましたが、TLS暗号化の強制(Explicit FTPS)とパーミッション制御において安定性に課題がありました。

3. GitHub Actions workflow

リポジトリの .github/workflows/deploy-lolipop.yml にて、ubuntu-latest ランナー上で同期用一時ディレクトリ _site/ を組み立てる構成を導入しました。以下は実際に運用している rsync フィルタリング処理です。

- name: Prepare public files
  run: |
    mkdir -p _site
    rsync -av --delete \
      --exclude='.git*' \
      --exclude='.github*' \
      --exclude='_site*' \
      --exclude='scripts*' \
      --exclude='reports*' \
      --exclude='migration*' \
      --exclude='*.md' \
      --exclude='.DS_Store' \
      ./ _site/

4. FTPS同期(lftp)

Linuxパッケージの lftp を使用し、明示的FTPS (FTP over TLS) を強制する設定を適用しました。--reverse モードにより、ローカルの _site/ の内容を本番ディレクトリへ正確に反映します。

lftp -u "$LOLIPOP_FTP_USERNAME,$LOLIPOP_FTP_PASSWORD" "ftp://$LOLIPOP_FTP_HOST" <<LFTP
set ftp:ssl-auth TLS
set ftp:ssl-force true
set ftp:ssl-protect-data true
set ftp:passive-mode true
set ssl:verify-certificate true
set net:max-retries 2
set net:timeout 20
mirror --reverse --parallel=2 --verbose=1 --no-perms _site/ "$LOLIPOP_SERVER_DIR"
bye
LFTP

5. Secret管理とPHP設定の分離

問い合わせ受信先メールアドレスおよびSMTPログイン情報は、GitHub Repository Secrets(KOSHI_CONTACT_RECIPIENT, LOLIPOP_SMTP_PASS 等)へ格納。デプロイステップ内で runner の一時領域 $RUNNER_TEMP/contact-config.php に chmod 600 で動的生成し、単独で contact/contact-config.php へ転送する分離構成を採用しました。

6. 失敗した点

初期デプロイ時、checkout アクションのバージョン非互換(actions/checkout@v6 の誤記述)により構文エラーが発生したほか、rsync のインクルード指定が不完全で .htaccess が転送対象から漏れる失敗が発生しました(コミット a9a7bb1 で修正)。

7. 修正

actions/checkout@v4 への固定、rsync のワイルドカード排他ルールの単純化、および lftp の並列転送数 --parallel=2 への最適化により、転送エラーを解消しました。

8. Production検証

実際にGitHub Actions Run ID 31930268839 および 32229610860 でデプロイを実行した結果、合計所要時間 38秒(Job実行時間 48秒)で全静的ファイルおよび contact-config.php の同期完了を実測検証しました。

9. 現在の運用

main ブランチへの push により自動起動し、サイト構造検証スクリプト python3 scripts/check_site.py と PHP 構文検査 php -l contact/send.php が成功した場合のみ Lolipop へ安全に転送されます。

10. 学び

レンタルサーバー環境であっても、明示的FTPSとCLIツール(lftp)を組み合わせることで、SaaS型ホスティングと同等の安全かつ高速な CI/CD パイプラインをゼロコストで構築できることが実証されました。

Evidence

  • リポジトリ構成ファイル: .github/workflows/deploy-lolipop.yml
  • 主要修正コミット: eb4c0ab, a9a7bb1, 9ea05b2
  • 本番デプロイ実測値: Run ID 32229610860(転送時間 38秒)
  • 検証コマンド: gh run view 32229610860 --log

Sources