AWS CloudFront + S3による静的サイトにてCloudFront Functionsを利用してインデックスドキュメント機能を実装してみる

2023.04.21

こんにちは、コンサルティング部の南です。

AWSに公式ホームページなどの静的サイトを構築する場合、AWS CloudFrontとS3を利用して構築するケースが多いのではないでしょうか?

後段で詳細を説明しますが、S3をオリジンとして設定する場合(オリジンタイプがS3の場合)サブドメインに対するインデックスドキュメントが対応していません。

本ブログではCloudFront Functionsを利用してインデックスドキュメント機能を実装してみます。

インデックスドキュメント機能とは?

インデックスドキュメント機能とは、Webサーバーが特定のフォルダへアクセスされた場合に、自動的に表示するファイルを設定する機能のことです。
例えば、ユーザーが https://example.com/ というURLにアクセスした場合に、index.html を表示するように設定することができます。

ApacheやNginxを利用したWebサーバーの場合だと設定ファイル(httpd.confやnginx.conf)を編集することで実装することが出来ます。

AWS CloudFront + S3を利用して静的サイトを実装する場合

AWS CloudFront + S3による静的サイトの場合、構成によってデフォルトでのインデックスドキュメント機能が少し異なります。

構成の種類についての詳細はこちらのブログを参照下さい。

それぞれの構成によってどのようにインデックスドキュメント機能が異なるのか?についての詳細についても弊社ブログで既にまとめられておりますので、こちらをご覧下さい。

めんどくさがり屋の方向けに簡単に説明しますと、
AWS CloudFront + S3を利用して静的サイトを実装する場合、S3の「静的ウェブサイトホスティング」の機能を使って、URLを発行し、そのURLをオリジンとして設定する方法CloudFrontのオリジンとして直接S3を指定する方法があります。

前者の方法の場合は「静的ウェブサイトホスティング」機能側でインデックスドキュメント機能があります。
こちらを設定することで対応が可能です。

問題は後者の場合になります。 CloudFrontのオリジンとして直接S3を指定した場合もディストリビューションの「一般」設定からデフォルトルートオブジェクトを設定する欄があります。
こちらを設定することで、ホームディレクトリに対するインデックスドキュメントは対応するのですが、サブディレクトリに対しては対応しないという問題があります。

(例)
開ける → https://example.com/
開ける → https://example.com/index.html
403エラー → https://example.com/test/
開ける → https://example.com/test/index.html

CloudFront Functionsを利用して実装してみる

CloudFrontのオリジンとして直接S3を指定した場合でもCloudFront Functionsを利用することで、サブディレクトリに対してもインデックスドキュメントを対応させることが出来ます。

CloudFront FunctionsとはCloudFrontのエッジロケーション上でJavaScriptコードを実行することが出来るサービスです。

CloudFront Functionsは2つの異なるタイプのイベントに対応する関数タイプがあります。 今回はCloudFrontがオリジンに送信する前にクライアントからのリクエストを変更することができる、「ビューワーリクエスト関数」を設定します。
クライアントからのリクエストがあった際に、末尾にスラッシュ(/)が含まれている場合とuriにドット(.)を含んでいない場合、つまりファイル拡張子が指定されていない場合に、デフォルトのindex.htmlファイルを返すことでインデックスドキュメント機能を実装します。

前提条件

前提条件としてCloudFrontディストリビューションがデプロイされ、オリジンとしてS3を設定している状態を想定します。
また、今回利用するコードはAWSが公式で配布しているサンプルコードを利用します。

実装

  1. CloudFrontのサービスページに移動し、「関数」からCloudFront Functionsを作成します。

  2. 任意の関数名を入力します。今回は「index-document-function」とします。

  3. 以下のサンプルコードを貼り付けます。貼り付けた後は、「変更を保存」をクリックして下さい。

    function handler(event) {
        var request = event.request;
        var uri = request.uri;
    
        // Check whether the URI is missing a file name.
        if (uri.endsWith('/')) {
            request.uri += 'index.html';
        } 
        // Check whether the URI is missing a file extension.
        else if (!uri.includes('.')) {
            request.uri += '/index.html';
        }
    
        return request;
    }

    こちらのコードではURIがファイル名を含まない場合に末尾にindex.htmlを追加し、またURIが拡張子を含まない場合はURIの末尾に/index.htmlを追加するコードとなっています。
    このようにすることで、リクエストされたURIがディレクトリの場合でも、index.htmlファイルを返すことができます。
    また、ファイル名や拡張子を省略している場合にも、適切なファイルを返すことができる訳です。

  4. 保存が完了したら、「関数を発行」をクリックして下さい。
    また関数を変更した場合は「関数の保存」→「関数の発行」の両方を行わないと、関数が更新されない為注意が必要です。

  5. 最後に関連付けを行います。
    CloudFrontのビヘイビア設定から関連付ける関数を選択することも可能ですが、今回はCloudFront Functionsのページから関連付けを行います。

  6. 関連付けたいディストリビューションを選択し、イベントタイプを「Viwer request」を選択します。キャッシュビヘイビア単位でCloudFront Functionsを関連付けることが出来ます。

  7. 「関連付けを追加」をクリックすると、関連付けが完了します。

最後に

今回はAWS CloudFront + S3を利用して静的サイトを構築する際、サブディレクトリに対するインデックスドキュメント機能を実装する方法を紹介しました。

この方法を利用すれば、CloudFrontのオリジンとして直接S3を指定している場合でも、簡単にサブディレクトリに対してインデックスドキュメント機能を実現できます。
ウェブサイトの構築や運用において、より効率的で柔軟な対応が可能になります。

今後もAWSやCloudFront Functionsなどの便利な機能を活用し、ウェブサイトの構築や運用に役立つ情報をお伝えしていきますので、ぜひ参考にしてください。