Як встановити кореневий об’єкт за замовчуванням для підкаталогів для статично розміщеного веб-сайту на Cloudfront?


100

Як встановити кореневий об’єкт за замовчуванням для підкаталогів на статично розміщеному веб-сайті 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?


1
Я думаю, що це тепер можна зробити з Lambda @ edge, використовуючи функцію, яка перенаправляє всі URL-адреси, що закінчуються на /, на /index.html. Я спробую це на своєму веб-сайті, повідомим результати та опублікую детальну конфігурацію як відповідь.
Крістіан Магеруган-Станчіу

Відповіді:


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)
Хайден,

223

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

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

Завдяки цій темі форуму AWS


6
Хто-небудь знає, чи не стягується це по-різному при наявності джерела s3 проти веб-джерела?
fideloper

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, функція Лямбда може виправити переспрямування:

'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 конвертувати субдиректор / в субдиректор; при спробі завантажити HTML. Крім того, при спробі отримати доступ до example.com/subdir/ це не вдається, і якщо ви намагаєтесь отримати доступ до example.com/subdir; він завантажує файл HTML, а не відображає його.
jacobfogg

4

Вирішення проблеми - використання lambda @ 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>");
}

1

Я знаю, що це давнє запитання, але я просто пробився через це сам. Врешті-решт, моєю метою було менше встановити файл за замовчуванням у каталозі, а більше - отримати кінцевий результат файлу, який обслуговувався без .htmlкінця

Я закінчив видаляти .htmlз імені файлу і програмно / вручну встановив тип mime на text/html. Це не традиційний спосіб, але, здається, він працює, і задовольняє мої вимоги до гарних URL-адрес, не жертвуючи перевагами хмарних процесів. Встановлення типу mime дратує, але невелика ціна, яку потрібно заплатити за переваги, на мій погляд

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.