CloudFront + S3の構成で、Nuxtで静的化したコンテンツのページをリロードすると404エラーが発生する
事象
Amazon S3 + Amazon CloudFrontの構成で、Nuxtで静的化したコンテンツをS3に配置した際に、 ルート(/index.html)以外のページで、更新すると404エラー「NoSuchKey」が発生する。
構成
前提
Nuxtで静的化を行うと、以下のようなフォルダ構成となる。
- /pages/index.vue
↓
/index.html - /pages/test.vue
↓
/test/index.html
CloudFrontの設定で、Origin Domain NameにS3のバケット名を指定している。
原因
CloudFrontの設定で、Default Root Objectを「index.html」とすると以下のような動作となる。
- https://xxxxxxxxxx.cloudfront.net/
↓
https://xxxxxxxxxx.cloudfront.net/index.html - https://xxxxxxxxxx.cloudfront.net/test/
↓
https://xxxxxxxxxx.cloudfront.net/test/
そのため、ルート以外では「index.html」を返さないので、ファイルが存在せずにエラーとなってしまう。
解決方法
解決方法としては、以下の2つの方法がある。
1つ目
Lambda@Edgeを使用して、CloudFront がリクエストをS3オリジンに転送する前にURLを書き換えてサブディレクトリにも「index.html」を付与した状態で、S3オリジンにリクエストするようにする。
2つ目
CloudFrontの設定で、Origin Domain NameにS3のバケット名を指定するのではなく、S3バケットのStatic website hostingのエンドポイントを指定する。
それぞれの解決策での特徴
1つ目
S3をパブリック公開としなくても良いため、直接アクセスされてしまうことを防げる。
CloudFrontにキャッシュが存在しない場合のみ、Lambda@Edge が実行される。
2つ目
S3をパブリック公開の設定をしなければいけないため、S3のバケット名が分かると直接アクセスされてしまう。
S3でStatic website hostingの設定をしなければいけない。
※インデックスドキュメントの設定を「index.html」とする。CloudFrontに対して AWS WAFでIPアドレス制御をしてもS3まで制御することが出来ないため、 S3でも同様の制御を行わないといけない。
サブディレクトリでも「index.html」を返す。
【追記:2021年6月13日】
CloudFront Functionsがリリースされたため、パス書き換えにはLambda@EdgeよりもCloudFront Functionsが適している。