Programming

git push したら勝手にデプロイされる仕組みを作った(GitHub Actions × S3)

git push したら勝手にデプロイされる仕組みを作った(GitHub Actions × S3)

やりたかったこと

ブログ記事を書いたら、あとは git push するだけで全世界に公開される。 FTPクライアントを開く必要もなければ、管理画面にログインする必要もない。 ターミナルで3行打ったら終わり、という状態にしたかった。

git add .
git commit -m "新しい記事追加"
git push  # ← これで全世界に公開される

結論から言うと、GitHub Actions + AWS S3 でこの仕組みが無料で実現できた。

最終的な構成

ローカルPC (VS Code)

    │  git push

GitHub リポジトリ (main ブランチ)

    │  push をトリガーに自動実行

GitHub Actions (ubuntu-latest)
    ├── npm ci
    ├── npm run build
    └── aws s3 sync ./dist → S3バケット


                          CloudFront (CDN)


                          全世界の読者 🌍

push してから約1分で、新しい記事が全世界からアクセス可能になる。

GitHub Actions のワークフローファイル

.github/workflows/deploy.yml の中身はこれだけ:

name: Deploy Astro site to S3

on:
  push:
    branches:
      - main

jobs:
  build_and_deploy:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci || npm install --legacy-peer-deps

      - run: npm run build

      - uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1

      - run: aws s3 sync ./dist s3://${{ secrets.AWS_S3_BUCKET }} --delete

たったこれだけのYAMLで、main ブランチに push するたびに自動ビルド&デプロイが走る。

セットアップでハマったポイント

1. GitHub Secrets の登録場所を間違える

GitHub リポジトリの Settings > Secrets and variables > Actions で3つのシークレットを登録する必要がある:

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • AWS_S3_BUCKET

最初、「Variables」タブに値を入れてしまい、「Credentials could not be loaded」エラーが出続けた。正しくは 「Secrets」タブの「Repository secrets」 に登録する。

さらに、3つの値を1つのフィールドにまとめて入力しようとしていたのもミスだった。それぞれ 「New repository secret」ボタンを3回押して、1つずつ登録する のが正解。

2. S3 の Access Denied 問題

デプロイ自体は成功しているのに、記事のリンクをクリックすると AccessDenied の XML が返ってくる。

これは Astro のビルド出力形式と S3 の仕様のミスマッチが原因だった。詳しくはこちらの記事に書いたけど、build.format: 'file' に変更して解決。

3. npm ci が失敗する

GitHub Actions の ubuntu 環境では npm ci が厳密に package-lock.json の整合性をチェックする。ローカルで --legacy-peer-deps を使っていると package-lock.json に不整合が残ることがある。

ワークフローでは npm ci || npm install --legacy-peer-deps としてフォールバックさせている。

ADVERTISEMENT
Google AdSense Placeholder
Ready for production insertion

実際のデプロイ結果

この記事自体が、上記の CI/CD パイプラインを通ってデプロイされている。

もしあなたがこの記事を読んでいるなら、それは以下が全て正常に動作している証拠:

  1. ✅ GitHub Actions がトリガーされた
  2. ✅ Astro のビルドが成功した
  3. ✅ S3 へのアップロードが成功した
  4. ✅ CloudFront 経由でHTMLが配信された
  5. ✅ MDX 内のカスタムコンポーネント(AdSense, AmazonLink)が正常にレンダリングされた

運用コスト

この CI/CD パイプライン自体のコストは 完全に無料

  • GitHub Actions: パブリックリポジトリなら無料。プライベートでも月2,000分の無料枠がある
  • 1回のデプロイにかかる時間は約1分 → 月に100記事書いても余裕

S3 + CloudFront の方のコストは月88円程度(アクセスがほぼない場合)。 つまり、ブログの運用コストがコンビニのおにぎり1個以下

まとめ

  • git push → 自動ビルド → S3デプロイの流れが GitHub Actions の YAML 1ファイル で完結する
  • GitHub Secrets の登録場所(Secrets タブ、1つずつ)に注意
  • Astro + S3 の組み合わせでは build.format: 'file' が重要
  • 全部合わせて 月88円 + 無料の CI/CD で個人ブログが運用できる

記事を書いて push するだけ。あとは全部自動でやってくれる。最高。