web-dev-qa-db-ja.com

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

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

現在、Cloudfrontの動作はS3と異なり、Amazonの状態 具体的に

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

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

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

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

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

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

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

72
wyer33

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

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

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

いいえ。 AWS CloudFront docs ...に記載されているとおり.

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

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

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

...

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

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

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

ただし、いくつかの興味深い可能性を開くのは2番目のオプションです。これはおそらくあなたがやろうとしていることの目的を無効にしますが、CloudFront Originサーバーを唯一の仕事とする独自のサーバーをセットアップできます。

http://d111111abcdef8.cloudfront.net/install/ のリクエストが来ると、CloudFrontはこのリクエストをOriginサーバーに転送し、/installを要求します。この場合index.htmlを提供するなど、必要に応じてOriginサーバーを設定できます。

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

しかし、私は自分のサーバーをセットアップし、それをスケーリングすることを心配すると、そもそもやろうとしていることの目的を損なうかもしれないことを理解しています。

2
Josh Padnick

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

enter image description here

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

196
JBaczuk

S3ホスティングを有効にすると、バケットを世界中に公開する必要があります。私の場合、バケットをプライベートに保ち、Originアクセス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コンソールでCloudfrontディストリビューションに移動します。 Behaviorsに移動し、次に選択しますOrigin RequestLambda Function Associations、最後にARNを新しい関数に貼り付けます。

9
kenske

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

4
Johan Gorter

この問題の回避策は、リクエストの書き換えにlambda @ Edgeを利用することです。 CloudFrontディストリビューションのビューアーリクエストイベントのラムダを設定し、「/」で終わるすべてを書き換え、デフォルトルートドキュメントで「/」と等しくないようにする必要があります。 index.html。

3
Juissi

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
user1333371

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

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

1
whtevn

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

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

解決

この例では、CloudFront Edgeの計算能力を使用して、クライアントからのリクエストを検査します。次に、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 関数の作成など、これを設定するために必要なすべての手順を確認してください。

1
Max Desiatov