Come si imposta un oggetto radice predefinito per le sottodirectory di un sito Web ospitato staticamente su Cloudfront?


96

Come si imposta un oggetto radice predefinito per le sottodirectory su un sito Web ospitato staticamente su Cloudfront? In particolare, vorrei www.example.com/subdir/index.htmlessere servito ogni volta che l'utente lo richiede www.example.com/subdir. Nota, questo serve per fornire un sito web statico contenuto in un bucket S3. Inoltre, vorrei utilizzare un'identità di accesso origine per limitare l'accesso al bucket S3 solo a Cloudfront.

Ora, sono consapevole che Cloudfront funziona in modo diverso da S3 e Amazon afferma specificamente :

Il comportamento degli oggetti root predefiniti di CloudFront è diverso dal comportamento dei documenti di indice di Amazon S3. Quando configuri un bucket Amazon S3 come sito Web e specifichi il documento di indice, Amazon S3 restituisce il documento di indice anche se un utente richiede una sottodirectory nel bucket. (Una copia del documento di indice deve apparire in ogni sottodirectory.) Per ulteriori informazioni sulla configurazione dei bucket Amazon S3 come siti Web e sui documenti di indice, consulta il capitolo Hosting di siti Web su Amazon S3 nella Guida per lo sviluppatore di Amazon Simple Storage Service.

Pertanto, anche se Cloudfront ci consente di specificare un oggetto root predefinito, questo funziona solo per www.example.come non per www.example.com/subdir. Per aggirare questa difficoltà, possiamo cambiare il nome del dominio di origine in modo che punti all'endpoint del sito web fornito da S3. Funziona alla grande e consente di specificare in modo uniforme gli oggetti root. Sfortunatamente, questo non sembra essere compatibile con le identità di accesso all'origine . In particolare, i link sopra affermano:

Passa alla modalità di modifica:

Distribuzioni Web: fare clic sulla scheda Origini, fare clic sull'origine che si desidera modificare e fare clic su Modifica. È possibile creare un'identità di accesso all'origine solo per origini per cui il tipo di origine è S3 Origin.

Fondamentalmente, per impostare l'oggetto root predefinito corretto, utilizziamo l'endpoint del sito Web S3 e non il bucket del sito stesso. Ciò non è compatibile con l'utilizzo dell'identità di accesso dell'origine. In quanto tale, le mie domande si riducono a entrambe

  1. È possibile specificare un oggetto radice predefinito per tutte le sottodirectory per un sito Web ospitato staticamente su Cloudfront?

  2. È possibile impostare un'identità di accesso all'origine per i contenuti serviti da Cloudfront dove l'origine è un endpoint del sito Web S3 e non un bucket S3?


1
Penso che ora sia fattibile con Lambda @ edge, utilizzando una funzione che reindirizza tutti gli URL che terminano in / a /index.html Lo proverò sul mio sito Web e riporterò i risultati e pubblicherò la configurazione dettagliata come risposta.
Cristian Măgherușan-Stanciu

Risposte:


1

AGGIORNAMENTO: Sembra che mi sia sbagliato! Vedi la risposta di JBaczuk, che dovrebbe essere la risposta accettata in questo thread.

Sfortunatamente, la risposta a entrambe le tue domande è no.

1. È possibile specificare un oggetto root predefinito per tutte le sottodirectory di un sito Web ospitato staticamente su Cloudfront?

No. Come indicato nella documentazione di AWS CloudFront ...

... Se si definisce un oggetto root predefinito, una richiesta dell'utente finale per una sottodirectory della propria distribuzione non restituisce l'oggetto root predefinito. Ad esempio, supponiamo che index.htmlsia il tuo oggetto root predefinito e che CloudFront riceva una richiesta dell'utente finale per la directory di installazione nella tua distribuzione CloudFront:

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

CloudFront non restituirà l'oggetto root predefinito anche se una copia di index.htmlviene visualizzata nella directory di installazione.

...

Il comportamento degli oggetti root predefiniti di CloudFront è diverso dal comportamento dei documenti di indice di Amazon S3. Quando configuri un bucket Amazon S3 come sito Web e specifichi il documento di indice, Amazon S3 restituisce il documento di indice anche se un utente richiede una sottodirectory nel bucket. (Una copia del documento indice deve apparire in ogni sottodirectory.)

2. È possibile impostare un'identità di accesso origine per i contenuti serviti da Cloudfront in cui l'origine è un endpoint del sito Web S3 e non un bucket S3?

Non direttamente. Le tue opzioni per le origini con CloudFront sono i bucket S3 o il tuo server.

Tuttavia, è quella seconda opzione che apre alcune possibilità interessanti. Questo probabilmente vanifica lo scopo di ciò che stai cercando di fare, ma potresti configurare il tuo server il cui unico compito è essere un server di origine CloudFront.

Quando arriva una richiesta per http://d111111abcdef8.cloudfront.net/install/ , CloudFront inoltrerà questa richiesta al tuo server di origine, chiedendo /install. Puoi configurare il tuo server di origine come preferisci, anche per servire index.htmlin questo caso.

Oppure potresti scrivere una piccola app web che accetta questa chiamata e la ottiene comunque direttamente da S3.

Ma mi rendo conto che configurare il tuo server e preoccuparti di ridimensionarlo potrebbe vanificare lo scopo di ciò che stai cercando di fare in primo luogo.


L'unico problema che ho con questo è che farlo funzionare significa che avresti due (2) URL in grado di accedere al tuo sito web su s3. Il tuo URL cloud front e il tuo URL s3 (bucket_name.s3-website-us-east-1.amazonaws.com)
Hayden

218

Ci È un modo per fare questo. Invece di puntarlo al tuo bucket selezionandolo nel menu a discesa (www.example.com.s3.amazonaws.com), indirizzalo al dominio statico del tuo bucket (ad es. Www.example.com.s3-website-us -west-2.amazonaws.com):

inserisci qui la descrizione dell'immagine

Grazie a questo thread del forum AWS


6
Qualcuno sa se questo addebita in modo diverso quando si ha un'origine s3 rispetto a un'origine web?
fideloper

3
Funziona bene se desidero servire solo l'intero sito Web e i file HTTPS?
Manjit Kumar,

3
Significa che l'S3 deve essere abilitato come server web?
Anthony Kong

6
OP ha dichiarato esplicitamente che questo approccio non funzionerà per lui: "Per aggirare questa difficoltà, possiamo cambiare il nome del dominio di origine in modo che punti all'endpoint del sito web fornito da S3. Funziona alla grande e consente di specificare in modo uniforme gli oggetti root. Sfortunatamente , questo non sembra essere compatibile con le identità di accesso dell'origine ". AWS stesso sembra consigliare lamda @ edge per questo - aws.amazon.com/blogs/compute/…
icyitscold

3
Questo non è compatibile con Cloud Front - Origin Access Identity. Non sarai in grado di limitare l'accesso al tuo bucket S3 in questo modo.
rocketspacer

15

Attivare l'hosting S3 significa che devi aprire il secchio al mondo. Nel mio caso, dovevo mantenere privato il bucket e utilizzare la funzionalità dell'identità di accesso dell'origine per limitare l'accesso solo a Cloudfront. Come suggerito da @Juissi, una funzione Lambda può correggere i reindirizzamenti:

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

Dopo aver pubblicato la funzione, vai alla distribuzione cloudfront nella console AWS. Vai a Behaviors, quindi scegli Origin Requestsotto Lambda Function Associationse infine incolla l'ARN nella tua nuova funzione.


5
Esiste una funzione lambda pronta per il deployment simile a quella: serverlessrepo.aws.amazon.com/applications/…
marcanuy

Il problema qui è che questa funzione deve essere distribuita a us-east-1, quindi se hai un'azienda soggetta a una rigida regolamentazione GDPR che non consente un singolo bit al di fuori della Germania, questo non fa per te.
Renato Gama

5

C'è un altro modo per ottenere un file predefinito servito in una sottodirectory, come example.com/subdir/. Puoi effettivamente (programmaticamente) memorizzare un file con la chiave subdir/nel bucket. Questo file non verrà visualizzato nella console di gestione S3, ma in realtà esiste e CloudFront lo servirà.


S3 converst sottodirectory / a sottodirectory; quando provi a caricare l'HTML. Inoltre, quando si tenta di accedere a example.com/subdir/ non riesce e se si tenta di accedere a example.com/subdir; scarica il file HTML invece di renderlo.
jacobfogg

4

La soluzione alternativa per il problema è utilizzare lambda @ edge per riscrivere le richieste. È sufficiente impostare lambda per l'evento di richiesta del visualizzatore della distribuzione CloudFront e riscrivere tutto ciò che termina con "/" E non è uguale a "/" con il documento radice predefinito, ad esempio index.html.


Maggiori dettagli su questo approccio qui: aws.amazon.com/blogs/compute/…
Henrik Aasted Sørensen

purtroppo Lambda @ Edge funziona solo nella regione us-east-1, fonte: github.com/awslabs/serverless-application-model/issues/635
mruanova

4

Esiste una guida "ufficiale" pubblicata sul blog AWS che consiglia di configurare una funzione Lambda @ Edge attivata dalla distribuzione CloudFront:

Ovviamente, è una cattiva esperienza utente aspettarsi che gli utenti digitino sempre index.html alla fine di ogni URL (o addirittura sappiano che dovrebbe essere lì). Fino ad ora, non esisteva un modo semplice per fornire questi URL più semplici (equivalenti alla direttiva DirectoryIndex in una configurazione di server Web Apache) agli utenti tramite CloudFront. No, se vuoi comunque limitare l'accesso all'origine S3 utilizzando un OAI. Tuttavia, con il rilascio di Lambda @ Edge, puoi utilizzare una funzione JavaScript in esecuzione sui nodi edge di CloudFront per cercare questi pattern e richiedere la chiave dell'oggetto appropriata dall'origine S3.

Soluzione

In questo esempio, utilizzi la potenza di calcolo all'edge di CloudFront per ispezionare la richiesta mentre arriva dal client. Quindi riscrivi la richiesta in modo che CloudFront richieda un oggetto indice predefinito (index.html in questo caso) per qualsiasi URI di richiesta che termini con "/".

Quando viene effettuata una richiesta su un server Web, il client specifica l'oggetto da ottenere nella richiesta. Puoi utilizzare questo URI e applicarvi un'espressione regolare in modo che questi URI vengano risolti in un oggetto indice predefinito prima che CloudFront richieda l'oggetto dall'origine. Usa il codice seguente:

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

};

Segui la guida collegata sopra per vedere tutti i passaggi necessari per configurarlo, inclusi il bucket S3, la distribuzione CloudFront e la creazione della funzione Lambda @ Edge .


2

Un'altra alternativa all'utilizzo di lambda @ edge è utilizzare le pagine di errore di CloudFront. Crea un file risposta di errore personalizzata per inviare tutti i 403 a un file specifico. Quindi aggiungi javascript a quel file per aggiungere index.html agli URL che terminano con /. Codice di esempio:

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

So che questa è una vecchia domanda, ma l'ho affrontata da solo. In definitiva, il mio obiettivo era meno quello di impostare un file predefinito in una directory e di più avere il risultato finale di un file che veniva servito senza.html alla fine di esso

Ho finito per rimuovere .htmldal nome del file e impostare programmaticamente / manualmente il tipo MIME su text/html. Non è il modo tradizionale, ma sembra funzionare e soddisfa i miei requisiti per i graziosi URL senza sacrificare i vantaggi della cloudformation. Impostare il tipo mimo è fastidioso, ma secondo me un piccolo prezzo da pagare per i benefici

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.