IT TIP

Cloudfront에서 정적으로 호스팅되는 웹 사이트의 하위 디렉터리에 대한 기본 루트 개체를 어떻게 설정합니까?

itqueen 2020. 10. 22. 23:48
반응형

Cloudfront에서 정적으로 호스팅되는 웹 사이트의 하위 디렉터리에 대한 기본 루트 개체를 어떻게 설정합니까?


Cloudfront에서 정적으로 호스팅되는 웹 사이트의 하위 디렉터리에 대한 기본 루트 개체를 어떻게 설정합니까? 특히 www.example.com/subdir/index.html사용자가 요청할 때마다 서비스를 받고 싶습니다 www.example.com/subdir. 이는 S3 버킷에 보관 된 정적 웹 사이트를 제공하기위한 것입니다. 또한 원본 액세스 ID를 사용하여 S3 버킷에 대한 액세스를 Cloudfront로만 제한하고 싶습니다.

지금, 나는 CloudFront를가 S3보다 및 상태 아마존 다르게 작동하는지 알고 구체적으로 :

CloudFront 기본 루트 객체의 동작은 Amazon S3 인덱스 문서의 동작과 다릅니다. Amazon S3 버킷을 웹 사이트로 구성하고 인덱스 문서를 지정하면 Amazon S3는 사용자가 버킷의 하위 디렉터리를 요청하더라도 인덱스 문서를 반환합니다. (인덱스 문서의 사본은 모든 하위 디렉터리에 있어야합니다.) Amazon S3 버킷을 웹 사이트로 구성하는 방법과 인덱스 문서에 대한 자세한 내용은 Amazon Simple Storage Service 개발자 가이드의 Amazon S3에서 웹 사이트 호스팅 장을 참조하십시오.

따라서 Cloudfront에서 기본 루트 개체를 지정할 수 있지만 www.example.com이는 www.example.com/subdir. 이 문제를 해결하기 위해 S3에서 제공 한 웹 사이트 엔드 포인트를 가리 키도록 원본 도메인 이름을 변경할 수 있습니다. 이것은 훌륭하게 작동하며 루트 객체를 균일하게 지정할 수 있습니다. 불행히도 이것은 원본 액세스 ID 와 호환되지 않는 것으로 보입니다 . 특히, 위의 링크는 다음과 같습니다.

편집 모드로 변경 :

웹 배포 – 원본 탭을 클릭하고 편집 할 원본을 클릭 한 다음 편집을 클릭합니다. 오리진 유형이 S3 오리진 인 오리진에 대해서만 오리진 액세스 ID를 생성 할 수 있습니다.

기본적으로 올바른 기본 루트 객체를 설정하기 위해 웹 사이트 버킷 자체가 아닌 S3 웹 사이트 엔드 포인트를 사용합니다. 이것은 원본 액세스 ID 사용과 호환되지 않습니다. 따라서 내 질문은 다음 중 하나로 요약됩니다.

  1. Cloudfront에서 정적으로 호스팅되는 웹 사이트의 모든 하위 디렉터리에 대한 기본 루트 개체를 지정할 수 있습니까?

  2. 오리진이 S3 버킷이 아닌 S3 웹 사이트 엔드 포인트 인 Cloudfront에서 제공되는 콘텐츠에 대한 오리진 액세스 ID를 설정할 수 있습니까?


업데이트 : 내가 잘못된 것 같습니다! 이 스레드에서 수락 된 답변이어야하는 JBaczuk의 답변을 참조하십시오.

안타깝게도 두 질문에 대한 답은 '아니요'입니다.

1. Cloudfront에서 정적으로 호스팅되는 웹 사이트의 모든 하위 디렉터리에 대한 기본 루트 개체를 지정할 수 있습니까?

아니요. AWS CloudFront 문서에 명시된대로 ...

... 기본 루트 개체를 정의하면 배포의 하위 디렉터리에 대한 최종 사용자 요청이 기본 루트 개체를 반환하지 않습니다. 예를 들어 index.html는 기본 루트 객체이고 CloudFront가 CloudFront 배포 아래의 설치 디렉터리에 대한 최종 사용자 요청을 수신 한다고 가정 합니다.

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

CloudFront는 복사본이 index.html설치 디렉터리 나타나 더라도 기본 루트 객체를 반환하지 않습니다 .

...

CloudFront 기본 루트 객체의 동작은 Amazon S3 인덱스 문서의 동작과 다릅니다. Amazon S3 버킷을 웹 사이트로 구성하고 인덱스 문서를 지정하면 Amazon S3는 사용자가 버킷의 하위 디렉터리를 요청하더라도 인덱스 문서를 반환합니다. (인덱스 문서의 사본은 모든 하위 디렉토리에 있어야합니다.)

2. 오리진이 S3 버킷이 아닌 S3 웹 사이트 엔드 포인트 인 Cloudfront에서 제공되는 콘텐츠에 대해 오리진 액세스 ID를 설정할 수 있습니까?

직접적으로는 아닙니다. CloudFront의 오리진 옵션은 S3 버킷 또는 자체 서버입니다.

하지만 흥미로운 가능성을 열어주는 것은 두 번째 옵션입니다. 이것은 아마도 당신이하려는 일의 목적을 훼손 할 수 있지만, 유일한 작업이 CloudFront 오리진 서버 인 자체 서버를 설정할 수 있습니다.

http://d111111abcdef8.cloudfront.net/install/ 에 대한 요청이 들어 오면 CloudFront는이 요청을 오리진 서버로 전달하여 /install. index.html이 경우 서비스 포함하여 원하는대로 원본 서버를 구성 할 수 있습니다 .

또는이 호출을 받아 S3에서 직접 가져 오는 작은 웹 앱을 작성할 수 있습니다.

하지만 자신의 서버를 설정하고 확장에 대해 걱정하면 처음에하려는 작업의 목적이 무너질 수 있음을 알고 있습니다.


IS 할 수있는 방법은. 드롭 다운 (www.example.com.s3.amazonaws.com)에서 버킷을 선택하여 버킷을 가리키는 대신 버킷의 정적 도메인 (예 : www.example.com.s3-website-us)을 가리 킵니다. -west-2.amazonaws.com) :

여기에 이미지 설명 입력

이 AWS 포럼 스레드 덕분에


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);
};

After you publish your function, go to your cloudfront distribution in the AWS console. Go to Behaviors, then chooseOrigin Request under Lambda Function Associations, and finally paste the ARN to your new function.


There is one other way to get a default file served in a subdirectory, like example.com/subdir/. You can actually (programatically) store a file with the key subdir/ in the bucket. This file will not show up in the S3 management console, but it actually exists, and CloudFront will serve it.


Workaround for the issue is to utilize lambda@edge for rewriting the requests. One just needs to setup the lambda for the CloudFront distribution's viewer request event and to rewrite everything that ends with '/' AND is not equal to '/' with default root document e.g. index.html.


There is an "official" guide published on AWS blog that recommends setting up a Lambda@Edge function triggered by your CloudFront distribution:

Of course, it is a bad user experience to expect users to always type index.html at the end of every URL (or even know that it should be there). Until now, there has not been an easy way to provide these simpler URLs (equivalent to the DirectoryIndex Directive in an Apache Web Server configuration) to users through CloudFront. Not if you still want to be able to restrict access to the S3 origin using an OAI. However, with the release of Lambda@Edge, you can use a JavaScript function running on the CloudFront edge nodes to look for these patterns and request the appropriate object key from the S3 origin.

Solution

In this example, you use the compute power at the CloudFront edge to inspect the request as it’s coming in from the client. Then re-write the request so that CloudFront requests a default index object (index.html in this case) for any request URI that ends in ‘/’.

When a request is made against a web server, the client specifies the object to obtain in the request. You can use this URI and apply a regular expression to it so that these URIs get resolved to a default index object before CloudFront requests the object from the origin. Use the following code:

'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);

};

Follow the guide linked above to see all steps required to set this up, including S3 bucket, CloudFront distribution and Lambda@Edge function creation.


I know this is an old question, but I just struggled through this myself. Ultimately my goal was less to set a default file in a directory, and more to have the the end result of a file that was served without .html at the end of it

I ended up removing .html from the filename and programatically/manually set the mime type to text/html. It is not the traditional way, but it does seem to work, and satisfies my requirements for the pretty urls without sacrificing the benefits of cloudformation. Setting the mime type is annoying, but a small price to pay for the benefits in my opinion


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>");
}

참고 URL : https://stackoverflow.com/questions/31017105/how-do-you-set-a-default-root-object-for-subdirectories-for-a-statically-hosted

반응형