[amazon-web-services] 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);
};

함수를 게시 한 후 AWS 콘솔에서 cloudfront 배포로 이동합니다. 로 이동 Behaviors한 다음 Origin Request아래 Lambda Function Associations에서 선택 하고 마지막으로 ARN을 새 함수에 붙여 넣습니다.


답변

와 같은 하위 디렉토리에서 기본 파일을 제공하는 다른 방법이 하나 있습니다 example.com/subdir/. 실제로 (프로그래밍 방식으로) subdir/버킷에 키 가 있는 파일을 저장할 수 있습니다 . 이 파일은 S3 관리 콘솔에 표시 되지 않지만 실제로 존재하며 CloudFront에서 제공합니다.


답변

이 문제에 대한 해결 방법은 요청을 다시 작성하기 위해 lambda @ edge를 활용하는 것입니다. CloudFront 배포의 뷰어 요청 이벤트에 대해 람다를 설정하고 ‘/’로 끝나고 index.html과 같은 기본 루트 문서로 ‘/’가 아닌 모든 항목을 다시 작성하면됩니다.


답변

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 함수 생성을 포함하여이를 설정하는 데 필요한 모든 단계를 보려면 위에 링크 된 가이드를 따르십시오 .


답변

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