Как установить корневой объект по умолчанию для подкаталогов для статически размещенного веб-сайта в Cloudfront?

103

Как установить корневой объект по умолчанию для подкаталогов на статически размещенном веб-сайте в Cloudfront? В частности, я хотел бы, www.example.com/subdir/index.htmlчтобы меня обслуживали всякий раз, когда об этом просит пользователь www.example.com/subdir. Обратите внимание, это для доставки статического веб-сайта, хранящегося в корзине S3. Кроме того, я хотел бы использовать удостоверение доступа к источнику, чтобы ограничить доступ к корзине S3 только Cloudfront.

Теперь, я знаю , что CloudFront работает иначе , чем S3 и амазонка состояний конкретно :

Поведение корневых объектов CloudFront по умолчанию отличается от поведения индексных документов Amazon S3. Когда вы настраиваете корзину Amazon S3 в качестве веб-сайта и указываете индексный документ, Amazon S3 возвращает индексный документ, даже если пользователь запрашивает подкаталог в корзине. (Копия индексного документа должна находиться в каждом подкаталоге.) Для получения дополнительных сведений о настройке корзин Amazon S3 в качестве веб-сайтов и об индексных документах см. Главу «Хостинг веб-сайтов на Amazon S3» в Руководстве разработчика Amazon Simple Storage Service.

Таким образом, хотя Cloudfront позволяет нам указывать корневой объект по умолчанию, это работает только для, www.example.comа не для www.example.com/subdir. Чтобы обойти эту трудность, мы можем изменить имя исходного домена, чтобы оно указывало на конечную точку веб-сайта, заданную S3. Это отлично работает и позволяет единообразно указывать корневые объекты. К сожалению, это несовместимо с идентификаторами доступа к источнику . В частности, в приведенных выше ссылках говорится:

Перейти в режим редактирования:

Распространение через Интернет - перейдите на вкладку «Происхождение», щелкните источник, который нужно изменить, и нажмите «Изменить». Вы можете создать удостоверение доступа к источнику только для источников, для которых Тип происхождения - S3 Origin.

По сути, чтобы установить правильный корневой объект по умолчанию, мы используем конечную точку веб-сайта S3, а не сам сегмент веб-сайта. Это несовместимо с использованием идентификатора доступа к источнику. Таким образом, мои вопросы сводятся к либо

  1. Можно ли указать корневой объект по умолчанию для всех подкаталогов для статически размещенного веб-сайта в Cloudfront?

  2. Можно ли настроить идентификатор доступа к источнику для контента, обслуживаемого из Cloudfront, где источником является конечная точка веб-сайта S3, а не корзина S3?

wyer33
источник
1
Я думаю, что теперь это можно сделать с помощью Lambda @ edge, используя функцию, которая перенаправляет все URL-адреса, заканчивающиеся на /, на /index.html. Я попробую это на своем веб-сайте, сообщу о результатах и ​​опубликую подробную конфигурацию в качестве ответа.
Cristian Măgheruan-Stanciu

Ответы:

2

ОБНОВЛЕНИЕ: похоже, я был неправ! См. Ответ 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. Можно ли настроить идентификатор доступа источника для контента, обслуживаемого из Cloudfront, если источником является конечная точка веб-сайта S3, а не корзина S3?

Не прямо. Возможными вариантами происхождения с CloudFront являются корзины S3 или собственный сервер.

Однако именно этот второй вариант открывает некоторые интересные возможности. Это, вероятно, противоречит цели того, что вы пытаетесь сделать, но вы можете настроить свой собственный сервер, единственная задача которого - быть исходным сервером CloudFront.

Когда поступает запрос для http://d111111abcdef8.cloudfront.net/install/ , CloudFront пересылает этот запрос на ваш исходный сервер, запрашивая /install. Вы можете настроить исходный сервер, как хотите, в том числе и index.htmlв этом случае.

Или вы можете написать небольшое веб-приложение, которое просто принимает этот вызов и в любом случае получает его напрямую от S3.

Но я понимаю, что настройка собственного сервера и беспокойство о его масштабировании могут в первую очередь свести на нет цель того, что вы пытаетесь сделать.

Джош Падник
источник
Единственная проблема, с которой я столкнулся, заключается в том, что заставить это работать означает, что у вас будет два (2) URL-адреса, способных получить доступ к вашему веб-сайту на s3. URL-адрес вашего облачного сервера и URL-адрес s3 (bucket_name.s3-website-us-east-1.amazonaws.com)
Хайден,
226

Там IS способ сделать это. Вместо того, чтобы указывать его на свой сегмент, выбирая его в раскрывающемся списке (www.example.com.s3.amazonaws.com), укажите его на статический домен вашего сегмента (например, www.example.com.s3-website-us -west-2.amazonaws.com):

введите описание изображения здесь

Благодаря этой ветке форума AWS

JBaczuk
источник
6
Кто-нибудь знает, по-разному ли это взимается при наличии s3-источника по сравнению с веб-источником?
fideloper 05
3
Это нормально, если я хочу обслуживать весь свой веб-сайт и HTTPSтолько файлы ?
Манджит Кумар
3
Означает ли это, что S3 должен быть включен как веб-сервер?
Энтони Конг
6
OP явно заявил, что этот подход для него не сработает: «Чтобы обойти эту трудность, мы можем изменить имя исходного домена, чтобы оно указывало на конечную точку веб-сайта, заданную S3. Это отлично работает и позволяет единообразно указывать корневые объекты. К сожалению, , похоже, это несовместимо с идентификаторами доступа к источнику ". AWS, кажется, рекомендуют для этого lamda @ edge - aws.amazon.com/blogs/compute/…
icyitscold
3
Это несовместимо с Cloud Front - Origin Access Identity. Таким образом вы не сможете ограничить доступ к своей корзине S3.
rocketspacer
15

Активация хостинга S3 означает, что вы должны открыть ведро всему миру. В моем случае мне нужно было сохранить сегмент приватным и использовать функцию идентификации доступа к источнику, чтобы ограничить доступ только к 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 Requestпод Lambda Function Associationsи, наконец, вставьте ARN в новую функцию.

Кенске
источник
5
Существует готовый развернуть лямбда - функцию , аналогичную той одной: serverlessrepo.aws.amazon.com/applications/...
marcanuy
Проблема здесь в том, что эту функцию необходимо развернуть в us-east-1, поэтому, если у вас есть компания, в которой действуют строгие правила GDPR, которые не допускают ни одного бита за пределами Германии, тогда это не для вас.
Ренато Гама
5

Есть еще один способ получить файл по умолчанию, обслуживаемый в подкаталоге, например example.com/subdir/. Фактически вы можете (программно) сохранить файл с ключом subdir/в корзине. Этот файл не будет отображаться в консоли управления S3, но он действительно существует, и CloudFront будет его обслуживать.

Йохан Гортер
источник
S3 преобразовать subdir / в subdir; когда вы пытаетесь загрузить HTML. Кроме того, когда вы пытаетесь получить доступ к example.com/subdir/, он терпит неудачу, а если вы пытаетесь получить доступ к example.com/subdir; он загружает HTML-файл вместо его рендеринга.
jacobfogg 03
4

Чтобы решить эту проблему, используйте лямбда @ edge для перезаписи запросов. Просто нужно настроить лямбда для события запроса средства просмотра распространения CloudFront и переписать все, что заканчивается на '/' И не равно '/' с корневым документом по умолчанию, например index.html.

Джуисси
источник
Более подробная информация об этом подходе здесь: aws.amazon.com/blogs/compute/…
Хенрик Эастед Соренсен
к сожалению, Lambda @ Edge работает только в регионе us-east-1, источник: github.com/awslabs/serverless-application-model/issues/635
mruanova
4

В блоге AWS опубликовано «официальное» руководство, в котором рекомендуется настроить функцию Lambda @ Edge, запускаемую вашим дистрибутивом CloudFront:

Конечно, ожидать, что пользователи всегда будут вводить index.html в конце каждого URL-адреса (или даже знать, что он должен быть там), - плохой пользовательский опыт. До сих пор не существовало простого способа предоставить эти более простые URL-адреса (эквивалент директиве DirectoryIndex в конфигурации веб-сервера Apache) пользователям через CloudFront. Нет, если вы все еще хотите иметь возможность ограничивать доступ к источнику S3 с помощью OAI. Однако с выпуском Lambda @ Edge вы можете использовать функцию JavaScript, работающую на пограничных узлах CloudFront, чтобы искать эти шаблоны и запрашивать соответствующий ключ объекта из источника S3.

Решение

В этом примере вы используете вычислительную мощность на границе CloudFront для проверки запроса, поступающего от клиента. Затем перепишите запрос так, чтобы CloudFront запрашивал объект индекса по умолчанию (в данном случае index.html) для любого URI запроса, который заканчивается на '/'.

Когда делается запрос к веб-серверу, клиент указывает объект, который нужно получить, в запросе. Вы можете использовать этот URI и применить к нему регулярное выражение, чтобы эти URI были преобразованы в объект индекса по умолчанию до того, как CloudFront запросит объект из источника. Используйте следующий код:

'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 в этот файл, чтобы добавить index.html к URL-адресам, заканчивающимся на /. Образец кода:

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>");
}
user1333371
источник
1

Я знаю, что это старый вопрос, но я просто боролся с этим сам. В конечном итоге моя цель заключалась не столько в том, чтобы установить файл по умолчанию в каталоге, сколько в том, чтобы получить конечный результат файла, который обслуживается без .htmlв конце

Я закончил удаление .htmlиз имени файла и программно / вручную установил тип mime на text/html. Это не традиционный способ, но, похоже, он работает и удовлетворяет моим требованиям к красивым URL-адресам без ущерба для преимуществ облачной информации. Установка типа пантомимы раздражает, но, на мой взгляд, это небольшая цена за преимущества.

Whtevn
источник