S3 × CloudFrontでNext.jsの特定のページにアクセスできない問題の解決

S3 × CloudFrontでNext.jsの特定のページにアクセスできない問題の解決

2023/05/17

2024/06/13

Next.js × microCMSで作成したブログをS3 × CloudFrontでデプロイしたところ、トップページ以外のページを別タブや直接URLを指定してアクセスするとAccess Deniedのエラーが発生する問題が発生しました。

原因

CloudFrontのディストリビューション作成時にデフォルトルートオブジェクトを「index.html」に設定することでトップページにはアクセスできますが、それ以外のページのURL直接アクセスに関しては問題が起きるようです。

S3にデプロイしているフォルダ構成は以下のようになっており、CloudFrontからS3へのリクエスト時に各フォルダの下にあるindex.htmlファイルを参照する必要があるといった内容でした。
(例えば、https://tukkytech.com/blog/dayjs/のURLは以下フォルダのblog/dayjs/index.htmlを表示する必要があります。)

※なお、ビルド&エクスポート処理後に「ディレクトリ/index.html」の形にするには、next.config.jsにtrailingSlash: true を設定しておく必要があります。

├── 404
│   └── index.html
├── 404.html
├── _next
│   ├── aUtxxxxxxxx
│   └── static
│       ├── aUtxxxxxxxx
│       ├── xxxxxx
│       ....
├── blog
│   ├── aws-acm
│   │   └── index.html
│   ├── dayjs
│   │   └── index.html
│   ....
│
├── components
│   ├── Container
│   │   └── index.html
│   ├── Footer
│   │   └── index.html
│   ├── Header
│   │   └── index.html
│   └── TableOfContents
│       └── index.html
├── favicon.ico
├── index.html
├── next.svg
├── robots.txt
├── sitemap-0.xml
├── sitemap.xml
├── thirteen.svg
├── tukkytech.png
└── vercel.svg


CloudFront Functionsで対応する

上記の原因を解決するために、CloudFront Functionsを設定します。

AWSのコンソールからCloudFront > 「関数」にアクセスし、「関数を作成」をクリックして適当な関数名を設定して関数を作成します。


「構築」タブでコードを書きます。


コードが書けたら「発行」タブで「関数を発行」をクリックします。
その後、下部の設定からディストリビューションに関連付けします。(ディストリビューションの設定画面からも関連付け可能です。)


以下が書いたコードです。

function handler(event) {
    var request = event.request;
    var uri = request.uri;

    if (uri.startsWith('/')) {
        request.uri = uri + 'index.html';
    }

    return request;
}

上記の設定は、クライアントからリクエストが来たら'index.html'を追加することにしました。

・CloudFrontにhttps://tukkytech.com/blog/dayjs/とリクエストが来る

・uriは「blog/dayjs/」になるため、S3の「blog/dayjs/index.html」を参照するようuriを書き換え

といった具合です。
これでS3にデプロイしている各ディレクトリのindex.htmlを参照してくれるようになりました。
(コードはかなり簡単に書いたので想定漏れがあることはご了承ください)

参考資料

CloudFront Functions を使用したエッジでのカスタマイズ
CloudFront Functions で Next.js のパス解決の真似をする
Determine your function's purpose