Jak ustawić domyślny obiekt główny dla podkatalogów dla witryny hostowanej statycznie w Cloudfront?

103

Jak ustawić domyślny obiekt główny dla podkatalogów w witrynie hostowanej statycznie w Cloudfront? W szczególności chciałbym www.example.com/subdir/index.htmlbyć obsługiwany za każdym razem, gdy poprosi o to użytkownik www.example.com/subdir. Uwaga: służy to dostarczaniu statycznej witryny internetowej przechowywanej w zasobniku S3. Ponadto chciałbym użyć tożsamości dostępu pochodzenia, aby ograniczyć dostęp do zasobnika S3 tylko do Cloudfront.

Teraz zdaję sobie sprawę, że Cloudfront działa inaczej niż S3 i stany amazon w szczególności :

Zachowanie domyślnych obiektów głównych CloudFront różni się od zachowania dokumentów indeksowych Amazon S3. Po skonfigurowaniu zasobnika Amazon S3 jako witryny internetowej i określeniu dokumentu indeksu Amazon S3 zwraca dokument indeksu, nawet jeśli użytkownik zażąda podkatalogu w zasobniku. (Kopia dokumentu indeksu musi znajdować się w każdym podkatalogu). Aby uzyskać więcej informacji na temat konfigurowania zasobników Amazon S3 jako witryn internetowych i dokumentów indeksowych, zobacz rozdział Hostowanie witryn internetowych na Amazon S3 w podręczniku programisty Amazon Simple Storage Service.

W związku z tym, mimo że Cloudfront pozwala nam określić domyślny obiekt główny, działa to tylko dla, www.example.coma nie dla www.example.com/subdir. Aby obejść tę trudność, możemy zmienić nazwę domeny pochodzenia tak, aby wskazywała punkt końcowy witryny internetowej podany przez S3. Działa to świetnie i umożliwia jednolite określanie obiektów głównych. Niestety wydaje się, że nie jest to zgodne z tożsamościami dostępu pochodzenia . W szczególności powyższe linki stanowią:

Zmień na tryb edycji:

Dystrybucje internetowe - kliknij kartę Początki, kliknij źródło, które chcesz edytować, i kliknij Edytuj. Możesz utworzyć tożsamość dostępu do źródła tylko dla źródeł, dla których Typ pochodzenia to S3 Origin.

Zasadniczo, aby ustawić prawidłowy domyślny obiekt główny, używamy punktu końcowego witryny S3, a nie samego zasobnika witryny. Nie jest to zgodne z używaniem tożsamości dostępu pochodzenia. Jako takie, moje pytania sprowadzają się do jednego z nich

  1. Czy można określić domyślny obiekt główny dla wszystkich podkatalogów dla witryny hostowanej statycznie w Cloudfront?

  2. Czy można skonfigurować tożsamość dostępu pochodzenia dla treści udostępnianej z Cloudfront, gdzie źródłem jest punkt końcowy witryny S3, a nie zasobnik S3?

wyer33
źródło
1
Myślę, że jest to teraz wykonalne z Lambda @ edge, używając funkcji, która przekierowuje wszystkie adresy URL kończące się na / do /index.html. Wypróbuję to na mojej stronie internetowej i przedstawię wyniki i opublikuję szczegółową konfigurację jako odpowiedź.
Cristian Măgherușan-Stanciu

Odpowiedzi:

2

AKTUALIZACJA: Wygląda na to, że się pomyliłem! Zobacz odpowiedź JBaczuka, która powinna być akceptowaną odpowiedzią w tym wątku.

Niestety, odpowiedź na oba pytania brzmi: nie.

1. Czy można określić domyślny obiekt główny dla wszystkich podkatalogów w witrynie hostowanej statycznie w Cloudfront?

Nie. Jak stwierdzono w dokumentacji AWS CloudFront ...

... Jeśli zdefiniujesz domyślny obiekt główny, żądanie użytkownika końcowego dotyczące podkatalogu Twojej dystrybucji nie zwróci domyślnego obiektu głównego. Na przykład załóżmy, że index.htmljest to domyślny obiekt główny i CloudFront odbiera żądanie użytkownika końcowego dotyczące katalogu instalacyjnego w Twojej dystrybucji CloudFront:

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

CloudFront nie zwróci domyślnego obiektu głównego, nawet jeśli kopia programu index.htmlpojawi się w katalogu instalacyjnym.

...

Zachowanie domyślnych obiektów głównych CloudFront różni się od zachowania dokumentów indeksowych Amazon S3. Po skonfigurowaniu zasobnika Amazon S3 jako witryny internetowej i określeniu dokumentu indeksu Amazon S3 zwraca dokument indeksu, nawet jeśli użytkownik zażąda podkatalogu w zasobniku. (Kopia dokumentu indeksu musi znajdować się w każdym podkatalogu).

2. Czy można skonfigurować tożsamość dostępu pochodzenia dla treści udostępnianej z Cloudfront, gdzie źródłem jest punkt końcowy witryny S3, a nie zasobnik S3?

Nie bezpośrednio. Twoje opcje początkowe w CloudFront to zasobniki S3 lub własny serwer.

Jednak to ta druga opcja otwiera kilka interesujących możliwości. To prawdopodobnie podważa cel tego, co próbujesz zrobić, ale możesz skonfigurować własny serwer, którego jedynym zadaniem jest być serwerem pochodzenia CloudFront.

Gdy nadejdzie żądanie dotyczące http://d111111abcdef8.cloudfront.net/install/ , CloudFront przekaże to żądanie do Twojego serwera pochodzenia, prosząc o /install. Możesz dowolnie konfigurować serwer pochodzenia, w tym do obsługi index.htmlw tym przypadku.

Możesz też napisać małą aplikację internetową, która po prostu odbiera to połączenie i i tak pobiera je bezpośrednio z S3.

Ale zdaję sobie sprawę, że skonfigurowanie własnego serwera i martwienie się o jego skalowanie może zniweczyć cel tego, co próbujesz zrobić.

Josh Padnick
źródło
Jedyny problem, jaki mam z tym, polega na tym, że uruchomienie tego oznacza, że ​​będziesz mieć dwa (2) adresy URL umożliwiające dostęp do Twojej witryny internetowej na s3. Twój przedni adres URL w chmurze i adres URL s3 (nazwa_wiadra.s3-website-us-east-1.amazonaws.com)
Hayden,
225

Istnieje JEST sposób to zrobić. Zamiast kierować go do swojego zasobnika, wybierając go z listy rozwijanej (www.example.com.s3.amazonaws.com), wskaż statyczną domenę swojego zasobnika (np. Www.example.com.s3-website-us -west-2.amazonaws.com):

wprowadź opis obrazu tutaj

Dzięki wątku z tego forum AWS

JBaczuk
źródło
6
Czy ktoś wie, czy to ładuje się inaczej, gdy ma pochodzenie s3 niż pochodzenie internetowe?
fideloper
3
Czy to działa dobrze, jeśli chcę obsługiwać tylko całą moją witrynę internetową i pliki HTTPS?
Manjit Kumar
3
Czy to oznacza, że ​​S3 musi być włączony jako serwer WWW?
Anthony Kong
6
OP wyraźnie stwierdził, że to podejście nie zadziała w jego przypadku: „Aby obejść tę trudność, możemy zmienić nazwę domeny źródłowej, tak aby wskazywała punkt końcowy witryny internetowej podany przez S3. , wydaje się, że nie jest to zgodne z tożsamościami dostępu pochodzenia ”. Wydaje się, że same AWS polecają lamda @ edge do tego - aws.amazon.com/blogs/compute/ ...
icyitscold
3
To nie jest zgodne z Cloud Front - tożsamość Origin Access. W ten sposób nie będziesz w stanie ograniczyć dostępu do swojego zasobnika S3.
rocketspacer
15

Aktywacja hostingu S3 oznacza, że ​​musisz otworzyć wiadro na świat. W moim przypadku musiałem zachować prywatność zasobnika i użyć funkcji tożsamości pochodzenia, aby ograniczyć dostęp tylko do Cloudfront. Jak zasugerował @Juissi, funkcja Lambda może naprawić przekierowania:

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

Po opublikowaniu funkcji przejdź do dystrybucji w chmurze w konsoli AWS. Idź do Behaviors, następnie wybierz Origin Requestponiżej Lambda Function Associationsi na koniec wklej ARN do nowej funkcji.

kenske
źródło
5
Jest gotowa do wdrożenia funkcja lambda podobna do tej: serverlessrepo.aws.amazon.com/applications/ ...
marcanuy
Problem polega na tym, że ta funkcja musi zostać wdrożona w us-east-1, więc jeśli masz firmę podlegającą ścisłym przepisom RODO, które nie zezwalają na ani trochę poza Niemcy, to nie jest dla ciebie.
Renato Gama
5

Jest jeszcze jeden sposób na pobranie domyślnego pliku udostępnianego w podkatalogu, na przykład example.com/subdir/. Możesz faktycznie (programowo) przechowywać plik z kluczem subdir/w wiadrze. Ten plik nie pojawi się w konsoli zarządzania S3, ale faktycznie istnieje i CloudFront go obsłuży.

Johan Gorter
źródło
S3 converst subdir / to subdir; kiedy próbujesz załadować HTML. Ponadto, próba uzyskania dostępu do example.com/subdir/ kończy się niepowodzeniem, a jeśli próbujesz uzyskać dostęp do example.com/subdir; pobiera plik HTML zamiast go renderować.
jacobfogg
4

Obejściem tego problemu jest użycie lambda @ edge do ponownego zapisywania żądań. Wystarczy ustawić lambdę dla zdarzenia żądania przeglądarki w dystrybucji CloudFront i przepisać wszystko, co kończy się na „/” i nie jest równe „/” z domyślnym dokumentem głównym, np. Index.html.

Juissi
źródło
Więcej szczegółów dotyczących tego podejścia tutaj: aws.amazon.com/blogs/compute/…
Henrik Aasted Sørensen
niestety Lambda @ Edge działa tylko w regionie us-east-1, źródło: github.com/awslabs/serverless-application-model/issues/635
mruanova
4

Istnieje "oficjalny" przewodnik opublikowany na blogu AWS, który zaleca skonfigurowanie funkcji Lambda @ Edge uruchamianej przez Twoją dystrybucję CloudFront:

Oczywiście oczekiwanie, że użytkownicy zawsze wpisują index.html na końcu każdego adresu URL (lub nawet wiedzą, że powinien tam być), jest złym doświadczeniem użytkownika. Do tej pory nie było łatwego sposobu na udostępnienie użytkownikom tych prostszych adresów URL (odpowiednik dyrektywy DirectoryIndex w konfiguracji serwera internetowego Apache) za pośrednictwem CloudFront. Nie, jeśli nadal chcesz mieć możliwość ograniczenia dostępu do źródła S3 za pomocą OAI. Jednak wraz z wydaniem Lambda @ Edge można użyć funkcji JavaScript działającej na węzłach krawędziowych CloudFront, aby wyszukać te wzorce i zażądać odpowiedniego klucza obiektu ze źródła S3.

Rozwiązanie

W tym przykładzie używasz mocy obliczeniowej na krawędzi CloudFront do sprawdzania żądania przychodzącego od klienta. Następnie ponownie napisz żądanie, aby CloudFront zażądał domyślnego obiektu indeksu (w tym przypadku index.html) dla dowolnego identyfikatora URI żądania, który kończy się na „/”.

Gdy żądanie skierowane jest do serwera WWW, klient określa obiekt do uzyskania w żądaniu. Możesz użyć tego identyfikatora URI i zastosować do niego wyrażenie regularne, aby te identyfikatory URI zostały przetłumaczone na domyślny obiekt indeksu, zanim CloudFront zażąda obiektu od źródła. Użyj poniższego kodu:

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

};

Postępuj zgodnie z powyższym przewodnikiem, aby zobaczyć wszystkie kroki wymagane do skonfigurowania tego, w tym wiadro S3, dystrybucję CloudFront i tworzenie funkcji Lambda @ Edge .

Max Desiatov
źródło
2

Inną alternatywą dla używania lambda @ edge jest użycie stron błędów CloudFront. Skonfiguruj niestandardową odpowiedź na błąd, aby wysłać wszystkie 403 do określonego pliku. Następnie dodaj javascript do tego pliku, aby dołączyć index.html do adresów URL kończących się na /. Przykładowy kod:

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
źródło
1

Wiem, że to stare pytanie, ale sam się z tym zmagałem. Ostatecznie moim celem było mniej ustawienie domyślnego pliku w katalogu, a bardziej uzyskanie końcowego wyniku pliku, który był obsługiwany bez .htmlna końcu

Skończyło się na usunięciu .htmlz nazwy pliku i programowo / ręcznie ustawiłem typ MIME na text/html. Nie jest to tradycyjny sposób, ale wydaje się działać i spełnia moje wymagania dotyczące ładnych adresów URL, nie rezygnując z zalet cloudformation. Ustawienie typu mime jest denerwujące, ale moim zdaniem niewielka cena za korzyści

whtevn
źródło