VercelからS3にサイトを移行した
2024/03/23 荒井 雄治朗Vercelで会社のサイトを動かしていたけど、動的な部分はないのでNext.jsを静的エクスポートしたものをS3に置いてCloudFront経由で配信する構成に変更した。
変更した時の作業メモ。
やりたいこと
- Next.jsで作成したサイトを静的エクスポートして正しく表示できるようにしたい
- CloudFront + S3で配信したい
- 同じURLで配信できるようにする(/を後ろにつけてもいいけど、index.htmlを指定しなくても良くしたい)
- Github Actionsでビルドして自動でS3にデプロイしたい
Next.js の静的出力設定
next.config.js
に以下の設定を追加する。
trailingSlash: true
は、URLの最後に /
をつける設定で、これをつけることで aaaaa.html じゃなくて、 aaaaa/index.html という形で出力されるようになる。
こうすることでなるべくVercelで動かしていた時と同じURLで配信できるようになる。
output: 'export',
は、静的出力するための設定。以前は next export
コマンドを使って静的出力していたが、このコマンドは非推奨になっていて、output
で設定するようになった。
この設定をすることで next build
を実行した時に静的出力されるようになる。
distDir
は出力先のディレクトリ設定。設定しなくても良い。
S3のバケットを作成する
静的出力したファイルを置くためのS3のバケットを作成する。大体の設定はデフォルトで、以下の設定を追加する。
CloudFrontからアクセスできるようにするためのバケットポリシーは、後から設定する。
- パブリックアクセスをすべてブロック
- 静的ウェブサイトホスティングを無効にする
CloudFront ディストリビューションを作成する
- オリジンを先ほど作成したS3に設定する
- S3バケットアクセス
- Origin access control settings (recommended)
- Origin access control > コントロール設定を作成 をクリック
- 署名リクエスト (推奨) を選択して、作成をクリック
S3のバケットポリシーを設定する
S3のバケットポリシーを更新して、CloudFrontからS3のオブジェクトにアクセスできるようにする。
S3のバケット > アクセス許可 > バケットポリシー
ここまでで、CloudFront経由でS3に静的ファイルを配信する準備ができた。
ドメインの設定
www.anytools.app をCloudFront+S3に設定する。ACMで証明書を作成する必要があるが、ここで問題が発生した。既存のドメインがVercelを向いていると証明書の作成に失敗してしまう。
失敗する理由を調べてみると、VirusTotalで問題と判定されるドメインの場合に証明書の作成に失敗するようだった。
解決方法は、ドメインを一度Vercelから外してから証明書を作成すること以外に思いつかなかったので、ドメインの向き先をCloudFrontに向けた。結果、次の日の朝に証明書を作成したら成功した。
DNSの設定
CNAME: www.anytools.app -> CloudFrontのドメイン名
証明書の作成
ACMで証明書をリクエストして、DNSにACMが指定したCNAMEレコードを作成する。
CloudFrontの設定
一般 > 設定 > 代替ドメイン名 (CNAME) - オプション
に、証明書を作成したドメイン名を設定する。
カスタム SSL 証明書 - オプション
に作成した証明書を設定する。
これで、ドメインの設定が完了した。
ディレクトリのURLを指定したら index.html を返すようにCloudFront Functions を設定する。
このサンプルコードを参考に(というかそのまま)、CloudFront Functions を設定する。
Github Actionsでビルドしてデプロイする
.github/workflows/deploy.yml
を作る。
デプロイ用のIAMユーザーを作成する
S3にデプロイするためのIAMユーザーを作成する。
- S3のバケットに対して
s3:PutObject
とs3:ListBucket
の権限を付与する - CloudFrontに対して
cloudfront:CreateInvalidation
の権限を付与する
Github Secrets に AWS のアクセスキーを設定する
AWS_ACCESS_KEY_ID
と AWS_SECRET_ACCESS_KEY
を設定する。
Variables にDISTRIBUTIONを指定する
DISTRIBUTION
は CloudFrontのディストリビューションIDを設定する。
完成!