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


96

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를 설정할 수 있습니까?


1
이제 Lambda @ edge로 /로 끝나는 모든 URL을 /index.html로 리디렉션하는 기능을 사용하여이 작업을 수행 할 수 있다고 생각합니다. 내 웹 사이트에서 시도해보고 결과를보고하고 자세한 구성을 답변으로 게시 할 것입니다.
Cristian Măgherușan-Stanciu

답변:


1

업데이트 : 내가 잘못된 것 같습니다! 이 스레드에서 수락 된 답변이어야하는 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에서 직접 가져 오는 작은 웹 앱을 작성할 수 있습니다.

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


내가 가진 한 가지 문제는 이것이 작동한다는 것은 s3에서 웹 사이트에 액세스 할 수있는 두 개의 URL이 있다는 것을 의미합니다. 클라우드 프런트 URL 및 s3 URL (bucket_name.s3-website-us-east-1.amazonaws.com)
Hayden

218

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

여기에 이미지 설명 입력

이 AWS 포럼 스레드 덕분에


6
s3 오리진과 웹 오리진을 사용할 때 이것이 다르게 청구되는지 아는 사람이 있습니까?
fideloper

3
전체 웹 사이트와 파일을 제공하려는 경우 HTTPS에만 작동합니까?
Manjit Kumar 2016

3
S3를 웹 서버로 활성화해야한다는 의미입니까?
Anthony Kong

6
OP는이 접근 방식이 그를 위해 작동하지 않을 것이라고 명시 적으로 언급했습니다. "이 문제를 해결하기 위해 S3에서 제공 한 웹 사이트 엔드 포인트를 가리 키도록 오리진 도메인 이름을 변경할 수 있습니다. 이것은 훌륭하게 작동하며 루트 객체를 균일하게 지정할 수 있도록합니다. , 이것은 원본 액세스 ID와 호환되지 않는 것 같습니다. " AWS 자신이를 위해 가장자리 @ 람다를 추천 할 것 - aws.amazon.com/blogs/compute/...
icyitscold

3
이것은 Cloud Front-Origin Access Identity와 호환되지 않습니다. 이러한 방식으로 S3 버킷에 대한 액세스를 제한 할 수 없습니다.
rocketspacer 19

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 콘솔에서 cloudfront 배포로 이동합니다. 로 이동 Behaviors한 다음 Origin Request아래 Lambda Function Associations에서 선택 하고 마지막으로 ARN을 새 함수에 붙여 넣습니다.


5
이와 유사한 람다 함수를 배포 할 준비가되었습니다. serverlessrepo.aws.amazon.com/applications/…
marcanuy

여기서 문제는이 기능을 us-east-1에 배포해야한다는 것입니다. 따라서 엄격한 GDPR 규정에 따라 독일 외부에서 단일 비트를 허용하지 않는 회사가 있다면 이는 귀하에게 적합하지 않습니다.
Renato Gama

5

와 같은 하위 디렉토리에서 기본 파일을 제공하는 다른 방법이 하나 있습니다 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 Sørensen은

안타깝게도 Lambda @ Edge는 us-east-1 리전에서만 작동합니다. 출처 : github.com/awslabs/serverless-application-model/issues/635
mruanova

4

CloudFront 배포에 의해 트리거되는 Lambda @ Edge 함수 설정을 권장 하는 "공식"안내서가 AWS 블로그에 게시 되어 있습니다.

물론 사용자가 항상 모든 URL의 끝에 index.html을 입력 할 것으로 기대하는 것은 나쁜 사용자 환경입니다 (또는 URL이 있어야한다는 것을 알고 있음). 지금까지 CloudFront를 통해 사용자에게 이러한 간단한 URL (Apache Web Server 구성의 DirectoryIndex 지시문에 해당)을 제공하는 쉬운 방법이 없었습니다. OAI를 사용하여 S3 오리진에 대한 액세스를 계속 제한하려는 경우에는 해당되지 않습니다. 그러나 Lambda @ Edge 릴리스에서는 CloudFront 엣지 노드에서 실행되는 JavaScript 함수를 사용하여 이러한 패턴을 찾고 S3 오리진에서 적절한 객체 키를 요청할 수 있습니다.

해결책

이 예제에서는 CloudFront 엣지의 컴퓨팅 성능을 사용하여 클라이언트에서 들어오는 요청을 검사합니다. 그런 다음 CloudFront가 '/'로 끝나는 모든 요청 URI에 대해 기본 인덱스 객체 (이 경우 index.html)를 요청하도록 요청을 다시 작성합니다.

웹 서버에 대한 요청이있을 때 클라이언트는 요청에서 가져올 개체를 지정합니다. 이 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에 대한 요구 사항을 충족합니다. 마임 유형을 설정하는 것은 귀찮지 만 제 생각에는 혜택을 지불하는 데 약간의 비용이 듭니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.