Cloudfrontで静的にホストされているウェブサイトのサブディレクトリのデフォルトルートオブジェクトをどのように設定しますか?


96

Cloudfrontで静的にホストされているウェブサイトのサブディレクトリにデフォルトのルートオブジェクトをどのように設定しますか?具体的にはwww.example.com/subdir/index.html、ユーザーがを要求するたびにサービスを提供したいと考えていますwww.example.com/subdir。これは、S3バケットに保持されている静的なWebサイトを配信するためのものであることに注意してください。さらに、S3バケットへのアクセスをCloudfrontのみに制限するために、オリジンアクセスIDを使用したいと思います。

現在、Cloudfrontの動作はS3およびAmazonの状態とは異なっていることを認識しています

CloudFrontデフォルトルートオブジェクトの動作は、Amazon S3インデックスドキュメントの動作とは異なります。Amazon S3バケットをウェブサイトとして設定し、インデックスドキュメントを指定すると、ユーザーがバケット内のサブディレクトリをリクエストした場合でも、Amazon S3はインデックスドキュメントを返します。(インデックスドキュメントのコピーは、すべてのサブディレクトリに表示される必要があります。)Amazon S3バケットをウェブサイトとして設定する方法とインデックスドキュメントの詳細については、Amazon Simple Storage Service開発者ガイドの「Amazon S3でのウェブサイトのホスティング」の章を参照してください。

そのため、Cloudfrontではデフォルトのルートオブジェクトを指定できますが、これはに対してのみ機能しwww.example.com、に対しては機能しませんwww.example.com/subdir。この問題を回避するために、S3によって提供されたWebサイトのエンドポイントを指すようにオリジンドメイン名を変更できます。これはうまく機能し、ルートオブジェクトを均一に指定できます。残念ながら、これはオリジンアクセスIDと互換がないようです。具体的には、上記のリンクは次のように述べています。

編集モードに変更します。

Webディストリビューション– [Origins]タブをクリックし、編集するオリジンをクリックして、[Edit]をクリックします。オリジンタイプがS3オリジンであるオリジンに対してのみ、オリジンアクセスIDを作成できます。

基本的に、正しいデフォルトルートオブジェクトを設定するために、ウェブサイトバケット自体ではなく、S3ウェブサイトエンドポイントを使用します。これは、発信元アクセスIDの使用と互換性がありません。したがって、私の質問はどちらかに要約されます

  1. Cloudfrontで静的にホストされているウェブサイトのすべてのサブディレクトリにデフォルトのルートオブジェクトを指定することは可能ですか?

  2. オリジンがS3バケットではなくS3ウェブサイトエンドポイントであるCloudfrontから提供されるコンテンツのオリジンアクセスIDをセットアップすることは可能ですか?


1
/で終わるすべてのURLを/index.htmlにリダイレクトする関数を使用して、これをLambda @ edgeで実行できるようになったと思います。ウェブサイトで試して、結果を報告し、詳細な設定を回答として投稿します。
Cristian Măgherușan-Stanciu

回答:


1

更新:それは私が間違っていたようです!このスレッドで受け入れられるはずのJBaczukの回答を参照してください。

残念ながら、両方の質問に対する答えはノーです。

1. Cloudfrontで静的にホストされているウェブサイトのすべてのサブディレクトリにデフォルトのルートオブジェクトを指定することはできますか?

いいえ。AWSCloudFrontドキュメントに記載されているように...

...デフォルトのルートオブジェクトを定義した場合、ディストリビューションのサブディレクトリに対するエンドユーザーのリクエストは、デフォルトのルートオブジェクトを返しません。たとえば、index.htmlがデフォルトのルートオブジェクトであり、CloudFrontがCloudFrontディストリビューションの下のインストールディレクトリに対するエンドユーザーリクエストを受け取ったとします。

http://d111111abcdef8.cloudfront.net/install/

のコピーがindex.htmlインストールディレクトリに表示されても、CloudFrontはデフォルトのルートオブジェクトを返しません。

...

CloudFrontデフォルトルートオブジェクトの動作は、Amazon S3インデックスドキュメントの動作とは異なります。Amazon S3バケットをウェブサイトとして設定し、インデックスドキュメントを指定すると、ユーザーがバケット内のサブディレクトリをリクエストした場合でも、Amazon S3はインデックスドキュメントを返します。(インデックスドキュメントのコピーは、すべてのサブディレクトリに表示される必要があります。)

2.オリジンがS3バケットではなくS3ウェブサイトエンドポイントであるCloudfrontから提供されるコンテンツのオリジンアクセスIDをセットアップすることは可能ですか?

直接ではありません。CloudFrontを使用したオリジンのオプションは、S3バケットまたは独自のサーバーです。

ただし、これは2番目のオプションであり、興味深い可能性を広げます。これはおそらく、実行しようとしていることの目的に反することになりますが、CloudFrontオリジンサーバーのみを目的とする独自のサーバーをセットアップすることもできます。

http://d111111abcdef8.cloudfront.net/install/に対するリクエストが受信されると、CloudFrontはこのリクエストをオリジンサーバーに転送し、を要求します/install。オリジンサーバーはindex.html、この場合に提供することも含めて、必要に応じて構成できます。

または、この呼び出しを受け取り、S3から直接取得する小さなWebアプリを作成することもできます。

しかし、私はあなた自身のサーバーをセットアップし、それをスケーリングすることを心配すると、そもそもあなたがしようとしていることの目的を無効にするかもしれないことを理解しています。


これに関して私が抱えている1つの問題は、これを機能させると、s3上のWebサイトにアクセスできるURLが2つあることです。クラウドフロントのURLとs3のURL(bucket_name.s3-website-us-east-1.amazonaws.com)
Hayden

217

そこISこれを行う方法は。ドロップダウン(www.example.com.s3.amazonaws.com)でバケットを選択してバケットを指すのではなく、バケットの静的ドメインを指します(例:www.example.com.s3-website-us)。 -west-2.amazonaws.com):

ここに画像の説明を入力してください

このAWSフォーラムのスレッドに感謝


6
s3オリジンとWebオリジンがある場合に、これが異なる方法で請求されるかどうかは誰にも分かりますか
fideloper

3
Webサイト全体とファイルHTTPSのみを提供したい場合、これは問題ありませんか?
Manjit Kumar 2016

3
S3をWebサーバーとして有効にする必要があるということですか?
アンソニーコング

6
OPはこのアプローチは彼にはうまくいかないと明言しました:「この問題を回避するために、S3によって指定されたWebサイトのエンドポイントを指すようにオリジンドメイン名を変更できます。これはうまく機能し、ルートオブジェクトを均一に指定できます。残念ながら、 、これはオリジンアクセスIDと互換性がないようです。」AWS自身が、このためにエッジ@ラムダを推奨しているように見える- aws.amazon.com/blogs/compute/...
icyitscold

3
これは、Cloud Front-Origin Access Identityと互換性がありません。この方法でS3バケットへのアクセスを制限することはできません。
ロケットスペーサー

15

S3ホスティングを有効にするには、バケットを公開する必要があります。私の場合、バケットをプライベートに保ち、オリジンアクセスID機能を使用して、Cloudfrontへのアクセスのみを制限する必要がありました。@Juissiが提案したように、Lambda関数はリダイレクトを修正できます。

'use strict';

/**
 * Redirects URLs to default document. Examples:
 *
 * /blog            -> /blog/index.html
 * /blog/july/      -> /blog/july/index.html
 * /blog/header.png -> /blog/header.png
 *
 */

let defaultDocument = 'index.html';

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;

    if(request.uri != "/") {
        let paths = request.uri.split('/');
        let lastPath = paths[paths.length - 1];
        let isFile = lastPath.split('.').length > 1;

        if(!isFile) {
            if(lastPath != "") {
                request.uri += "/";
            }

            request.uri += defaultDocument;
        }

        console.log(request.uri);
    }

    callback(null, request);
};

関数を公開した後、AWSコンソールでクラウドフロントディストリビューションに移動します。に移動しBehaviors、次にを選択Origin RequestLambda Function Associations、最後にARNを新しい関数に貼り付けます。


5
1と同様のデプロイラムダ関数への準備があります:serverlessrepo.aws.amazon.com/applications/...
marcanuy

ここでの問題は、この関数をus-east-1にデプロイする必要があることです。GDPRの厳しい規制のもとで、ドイツ国外での1ビットのみを許可しない会社がある場合、これは適していません。
Renato Gama

5

のようなサブディレクトリで提供されるデフォルトのファイルを取得するには、他に1つの方法がありますexample.com/subdir/。キーを含むファイルを実際に(プログラムで)subdir/バケットに保存できます。このファイルはS3管理コンソールに表示されませんが、実際には存在し、CloudFrontが提供します。


S3はsubdir /をsubdirに変換します。HTMLをアップロードしようとしたとき。また、example.com / subdir /にアクセスしようとすると失敗し、example.com / subdirにアクセスしようとすると失敗します。HTMLファイルをレンダリングする代わりにダウンロードします。
jacobfogg

4

この問題の回避策は、リクエストの書き換えにlambda @ edgeを利用することです。CloudFrontディストリビューションのビューアリクエストイベントのラムダをセットアップし、「/」で終わり、デフォルトのルートドキュメント(たとえばindex.html)の「/」に等しくないものをすべて書き換えるだけです。


ここでは、このアプローチに関する詳細:aws.amazon.com/blogs/compute/...
ヘンリックAastedソーレンセン

残念ながら、Lambda @ Edgeはus-east-1リージョンでのみ機能します。ソース:github.com/awslabs/serverless-application-model/issues/635
mruanova

4

CloudFrontディストリビューションによってトリガーされるLambda @ Edge関数のセットアップを推奨する「公式」ガイドがAWSブログ公開されています。

もちろん、ユーザーが常にすべてのURLの最後にindex.htmlを入力することを期待する(またはそこにあるべきであるとさえ知っている)ことを期待するのは悪いユーザーエクスペリエンスです。これまで、CloudFrontを介してこれらのより単純なURL(Apache Webサーバー構成のDirectoryIndexディレクティブに相当)をユーザーに提供する簡単な方法はありませんでした。それでも、OAIを使用してS3オリジンへのアクセスを制限できるようにしたい場合はそうしません。ただし、Lambda @ Edgeのリリースでは、CloudFrontエッジノードで実行されているJavaScript関数を使用してこれらのパターンを検索し、S3オリジンから適切なオブジェクトキーをリクエストできます。

解決

この例では、CloudFrontエッジのコンピューティングパワーを使用して、クライアントからのリクエストを検査します。次に、CloudFrontが「/」で終わるすべてのリクエストURIに対してデフォルトのインデックスオブジェクト(この場合はindex.html)をリクエストするようにリクエストを書き直します。

Webサーバーに対してリクエストが行われると、クライアントはリクエストで取得するオブジェクトを指定します。このURIを使用して正規表現を適用すると、CloudFrontがオリジンからオブジェクトをリクエストする前に、これらのURIがデフォルトのインデックスオブジェクトに解決されます。次のコードを使用します。

'use strict';
exports.handler = (event, context, callback) => {

    // Extract the request from the CloudFront event that is sent to Lambda@Edge
    var request = event.Records[0].cf.request;

    // Extract the URI from the request
    var olduri = request.uri;

    // Match any '/' that occurs at the end of a URI. Replace it with a default index
    var newuri = olduri.replace(/\/$/, '\/index.html');

    // Log the URI as received by CloudFront and the new URI to be used to fetch from origin
    console.log("Old URI: " + olduri);
    console.log("New URI: " + newuri);

    // Replace the received URI with the URI that includes the index page
    request.uri = newuri;

    // Return to CloudFront
    return callback(null, request);

};

上記のガイドに従って、S3バケット、CloudFrontディストリビューション、Lambda @ Edge関数の作成など、これをセットアップするために必要なすべての手順を確認してください。


2

lambda @ edgeを使用する別の方法は、CloudFrontのエラーページを使用することです。すべての403を特定のファイルに送信するようにカスタムエラー応答を設定します。次に、そのファイルにjavascriptを追加して、/で終わるURLにindex.htmlを追加します。サンプルコード:

if ((window.location.href.endsWith("/") && !window.location.href.endsWith(".com/"))) {
    window.location.href = window.location.href + "index.html";
}
else {
    document.write("<Your 403 error message here>");
}

1

私はこれが古い質問であることを知っていますが、私自身、これに苦労しました。結局のところ、私の目標は、ディレクトリにデフォルトのファイルを設定することではなく、ファイル.htmlの最後になくても提供されるファイルの最終結果を得ることでした。

.htmlファイル名から削除し、プログラム/手動でMIMEタイプをに設定しましたtext/html。これは従来の方法ではありませんが、機能しているようで、cloudformationの利点を犠牲にすることなく、かなりのURLに対する私の要件を満たしています。MIMEタイプを設定するのは面倒ですが、私の見解では、メリットを支払うための小さな価格です

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.