Nuxt.js で作成した静的サイトを S3 + CloudFront でホスティングするパターン

Nuxt.js で SSR を使わない静的サイトを生成(`nuxt generate`)して S3 で安価にホスティングする場合、「各ページに対して index.html ファイルが生成されるが、リンクの URL では index.html は省略されるため、そのままでは Not Found になってしまう」という課題がある。通常の Web サーバーには、例えば Apache では `DocumentIndex`、nginx では `index` というように、ファイル名が省略された場合にデフォルトのファイル名を配信する設定があるが、それ相当の動作が必要となる。

実現方法にはいくつかパターンがあるようなので、詳細はそれぞれの解説ページに任せるとして、それらを整理してみた。

参考

- [CloudFront + S3 で静的サイトを運用する際の注意点 - Qiita](https://qiita.com/ooxif/items/d28b7caf72bf5290588c)

## 構成パターン

### 1. S3 で Static website hosting をおこなう

- 大量のアクセスが発生しない、かつ HTTP だけで良い場合はこれが最もシンプル。
- Static website hosting の「Index document」設定に「index.html」を設定する。
- カスタムドメインで公開する場合は、バケット名を FQDN にする必要がある。

![S3 で Static website hosting をおこなう](https://hirose-public.s3-ap-northeast-1.amazonaws.com/qiita/2020/06/21/963e1706-cdbc-445a-b96e-6eb643ba2d74.svg)

参考

- [Deploy a NUXT app to S3 in 5 minutes - freeCodeCamp](https://www.freecodecamp.org/news/deploy-a-nuxt-app-to-s3-in-5-minutes-515a161eb74f/)

### 2. S3 で Static website hosting をおこない、CloudFront 経由で公開する

- 1 に加えて、CloudFront から S3 で Static website hosting した URL を Origin とする。
- S3 の Static website hosting にも直接アクセスできてしまう。
- S3 への直接アクセスを制限する手段はあるが、弱い方法しかない? HTTP での直接アクセスを絶対にさせたくないといった場合は注意。
  - CloudFront からのリクエストに特定のカスタムヘッダを付与し、S3 でそれをチェックするなど。
  - CloudFront の Edge は多数あり変動するので IP 制限はあまり現実的ではない。

![S3 で Static website hosting をおこない、CloudFront 経由で公開する](https://hirose-public.s3-ap-northeast-1.amazonaws.com/qiita/2020/06/21/2746af96-186e-4179-ad47-5c282dc03b07.svg)

参考

- [How to Deploy on AWS w/ S3 and Cloudfront? - Nuxt.js 公式](https://nuxtjs.org/faq/deployment-aws-s3-cloudfront/)
- [S3+CloudFrondでNuxt.js(vue)のHTTPS静的サイトを構築・デプロイ](https://qiita.com/gakumac/items/7d2aca3a1748e1c5691c)

### 3. CloudFront のエラーページ設定で index.html を返す

- S3 での Static website hosting はおこなわず、CloudFront から S3 バケットを Origin とする。
- index.html が省略されて 403 となった場合に表示するエラーページとして、index.html を返すように設定する。
  - 余談) CloudFront に「Default Root Object」というそれっぽい設定はあるが、これは本当にルートにしか効かないので役に立たない。
- 意味的にはエラーページとして表示することになるので、少し気持ちが悪い。(個人の感想です)

![CloudFront のエラーページ設定で index.html を返す](https://hirose-public.s3-ap-northeast-1.amazonaws.com/qiita/2020/06/21/c8245f6e-67c9-495d-a46e-b85a7ba10cfa.svg)

参考

- [NuxtのSPAを S3＋CloudFrontでホストする。デプロイはCodeBuildで自動化 - アクトインディ開発者ブログ](https://tech.actindi.net/2018/10/19/083000)
- [Nuxt.jsで作った静的サイトをCloudFront + S3で配信するときのTips - @ryoheimorimoto](https://scrapbox.io/ryoheimorimoto/Nuxt.js%E3%81%A7%E4%BD%9C%E3%81%A3%E3%81%9F%E9%9D%99%E7%9A%84%E3%82%B5%E3%82%A4%E3%83%88%E3%82%92CloudFront_+_S3%E3%81%A7%E9%85%8D%E4%BF%A1%E3%81%99%E3%82%8B%E3%81%A8%E3%81%8D%E3%81%AETips)

### 4. Lambda@Edge で index.html への書き換えをおこなう

- CloudFront へのアクセスをフックして独自の処理を加えられる Lambda@Edge を使い、index.html を付与して Origin にリクエストする。
- 設定が比較的面倒で、Lambda のぶん追加コストがかかる。

![Lambda@Edge で index.html への書き換えをおこなう](https://hirose-public.s3-ap-northeast-1.amazonaws.com/qiita/2020/06/21/8a65fb15-80bf-4d7b-877e-8426542922ea.svg)

参考

- [Implementing Default Directory Indexes in Amazon S3-backed Amazon CloudFront Origins Using Lambda@Edge - AWS Compute Blog](https://aws.amazon.com/blogs/compute/implementing-default-directory-indexes-in-amazon-s3-backed-amazon-cloudfront-origins-using-lambdaedge/)
- [できた！S3 オリジンへの直接アクセス制限と、インデックスドキュメント機能を共存させる方法 - Developes.IO](https://dev.classmethod.jp/articles/directory-indexes-in-s3-origin-backed-cloudfront/)
- [nuxt generate + S3 + CloudFront + Lambda Edge で静的サイト構築＆ハマりポイントと解決法 - Qiita](https://qiita.com/GussieTech/items/3ae77dbcb1e79222a9bc)