Argano の松田です。 この記事では Vite で作成したプロジェクトを AWS の S3 と CloudFront を使用して公開する方法について紹介します。 サンプルでは React を使用しますが、Vue や Svelte でも同様の手順で公開できます。

※ AWS アカウントが存在すること、Node.js がインストールされていることを前提としています。

Vite プロジェクトの作成

まずは Vite のプロジェクトを作成します。

npm create vite@latest my-react-app -- --template react-swc-ts
cd my-react-app
npm install
npm run dev # 開発サーバーを起動
npm run build # プロダクションビルド
npm run preview # プロダクションビルドしたものをローカルで確認

Git で管理します。後々 Github Actions を使用するため、Github にリポジトリを作成してください。

git init
git add .
git commit -m "Initial commit"

S3 バケットの作成

ビルド結果を格納する S3 バケットを作成します。

AWS のコンソールにログイン後、S3 サービスに移動し、「バケットを作成」をクリックします。

バケット名に任意の値を入力します。バケット名はグローバルで一意である必要があります。

バケット名以外の設定はデフォルトのままで問題ありません。S3 には CloudFront 経由でアクセスするため、直接アクセスすることはありません。そのため、「このバケットのブロックパブリックアクセス設定」セクションの、「パブリックアクセスをすべてブロック」にチェックが入っていることを確認してください。

「バケットを作成」をクリックします。

CloudFront ディストリビューションの作成

サイトを配信する CloudFront ディストリビューションを作成します。

CloudFront サービスに移動し、「CloudFront ディストリビューションを作成」をクリックします。

「Origin domain」に先ほど作成した S3 バケットを選択します。「オリジンアクセス」は「Origin access control settings」を選択、「Origin access control」は「Create new OAC」ボタンから作成します。 「ウェブアプリケーションファイアウォール (WAF)」は「セキュリティ保護を有効にする」にチェックを入れます。 「デフォルトルートオブジェクト」は「index.html」を設定します。他の設定はデフォルトのままで問題ありません。キャッシュの設定などは必要に応じて変更してください。

「ディストリビューションを作成」をクリックします。

作成が完了すると、ディストリビューションの詳細画面が表示されます。この画面にて「S3 バケットポリシーを更新する必要があります」というメッセージが表示されていると思いますので「ポリシーをコピー」をクリックします。

S3 バケットポリシーの設定

先ほどコピーしたポリシーを S3 バケットの「アクセス許可」タブの「バケットポリシー」に貼り付けます。バケット名、AWS アカウント ID、CloudFront ディストリビューション ID を適切な値に置き換えたら保存します。

{
  "Version": "2008-10-17",
  "Id": "PolicyForCloudFrontPrivateContent",
  "Statement": [
    {
      "Sid": "AllowCloudFrontServicePrincipal",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudfront.amazonaws.com"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::{バケット名}/*",
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "arn:aws:cloudfront::{AWSアカウントID}:distribution/{CloudFrontディストリビューションID}"
        }
      }
    }
  ]
}

CloudFront エラーページの設定

CloudFront ディストリビューションの「エラーページ」タブに移動し、「カスタムエラーレスポンスを作成」をクリックします。

「HTTP エラーコード」に 「403: Forbidden」 を選択します。また、「エラーレスポンスをカスタマイズ」で「はい」を選択し、「レスポンスページのパス」に 「/」、「HTTP レスポンスコード」に 「200: OK」を設定します。

「カスタムエラーレスポンスを作成」をクリックします。

この設定は React Router などを使用して、複数ページ表示する SPA の場合に有効です。この設定がないと、ユーザーが /about を直接開こうとした場合に、about.html が存在しないため 403 エラーが返されてしまいます。

GitHub Actions で OIDC を使用して AWS 認証する

Github Actions から Vite のビルド結果を S3 へアップロードするために必要な設定を行います。

ID プロバイダの作成

AWS コンソールの IAM > ID プロバイダ に移動し、「プロバイダを追加」をクリックします。

「プロバイダのタイプ」を「OpenID Connect」に、「プロバイダの URL」を「 https://token.actions.githubusercontent.com」 に設定します。入力後、 「サムプリントを取得」をクリックします。対象者は「sts.amazonaws.com」にします。

「プロバイダを追加」をクリックします。

IAM ポリシーの作成

IAM > ポリシー に移動し、「ポリシーの作成」をクリックします。

ポリシーエディタで JSON を選択し、以下の JSON を貼り付けます。バケット名、AWS アカウント ID、CloudFront ディストリビューション ID を適切な値に置き換えたら「次へ」をクリックします。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VisualEditor0",
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:ListBucket",
        "s3:DeleteObject",
        "cloudfront:CreateInvalidation"
      ],
      "Resource": [
        "arn:aws:s3:::{バケット名}",
        "arn:aws:s3:::{バケット名}/*",
        "arn:aws:cloudfront::{AWSアカウントID}:distribution/{CloudFrontディストリビューションID}"
      ]
    }
  ]
}

ポリシー名に任意の値を入力し、「ポリシーの作成」をクリックします。

IAM ロールの作成

IAM > ロール に移動し、「ロールを作成」をクリックします。

信頼されたエンティティタイプで「カスタム信頼ポリシー」を選択します。

カスタム信頼ポリシーには、以下の JSON を貼り付けます。AWS アカウント ID、GitHub ユーザー名、GitHub リポジトリ名を適切な値に置き換えたら「次へ」をクリックします。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::<AWSアカウントID>:oidc-provider/token.actions.githubusercontent.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
        },
        "StringLike": {
          "token.actions.githubusercontent.com:sub": "repo:<GitHubユーザー名>/<GitHubリポジトリ名>:*"
        }
      }
    }
  ]
}

許可ポリシーには、先ほど作成した IAM ポリシーを選択します。

ロールの名前に任意の値を入力し、「ロールの作成」をクリックします。

Github Actions ワークフローの作成

Vite のビルド結果を S3 にアップロードする Github Actions ワークフローを作成します。アップロード後、CloudFront のキャッシュを削除することで、最新のビルド結果を反映させます。

.github/workflows/deploy.yml ファイルを作成します。AWS アカウント ID、IAM ロール名、バケット名、CloudFront ディストリビューション ID を適切な値に置き換えたら保存します。

name: Deploy

on:
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest

    permissions:
      id-token: write
      contents: read

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: "npm"

      - run: npm ci
      - run: npm run build

      - uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: ap-northeast-1
          role-to-assume: arn:aws:iam::{AWSアカウントID}:role/{IAMロール名}

      - name: Deploy
        run: |
                    aws s3 sync --exact-timestamps --delete dist s3://{バケット名}

      - name: Clear Cache
        run: |
                    aws cloudfront create-invalidation --distribution-id {CloudFrontディストリビューションID} --paths '/*'

デプロイ

作成した Github Actions のワークフローは main ブランチへのプッシュや手動で実行できます。

git add .
git commit -m "Deploy"
git push origin main

動作確認

CloudFront ディストリビューションの「ディストリビューションドメイン名」にアクセスすると、Vite プロジェクトが公開されていることを確認できます。