web-dev-qa-db-fra.com

Comment définir un objet racine par défaut pour les sous-répertoires d'un site Web hébergé statiquement sur Cloudfront?

Comment définir un objet racine par défaut pour les sous-répertoires d'un site Web hébergé statiquement sur Cloudfront? Plus précisément, j'aimerais www.example.com/subdir/index.html à diffuser chaque fois que l'utilisateur demande www.example.com/subdir. Remarque: il s'agit de fournir un site Web statique contenu dans un compartiment S3. De plus, je souhaite utiliser une identité d'accès Origin pour limiter l'accès au compartiment S3 à Cloudfront uniquement.

Maintenant, je suis conscient que Cloudfront fonctionne différemment des états S3 et Amazon spécifiquement :

Le comportement des objets racine par défaut CloudFront est différent du comportement des documents d'index Amazon S3. Lorsque vous configurez un compartiment Amazon S3 en tant que site Web et spécifiez le document d'index, Amazon S3 renvoie le document d'index même si un utilisateur demande un sous-répertoire dans le compartiment. (Une copie du document d'index doit apparaître dans chaque sous-répertoire.) Pour plus d'informations sur la configuration des compartiments Amazon S3 en tant que sites Web et sur les documents d'index, consultez le chapitre Hébergement de sites Web sur Amazon S3 dans le Guide du développeur Amazon Simple Storage Service.

En tant que tel, même si Cloudfront nous permet de spécifier un objet racine par défaut, cela ne fonctionne que pour www.example.com et pas pour www.example.com/subdir. Afin de contourner cette difficulté, nous pouvons changer le nom de domaine d'origine pour pointer vers le point de terminaison du site Web donné par S3. Cela fonctionne très bien et permet aux objets racine d'être spécifiés uniformément. Malheureusement, cela ne semble pas être compatible avec Identités d'accès d'origine . Plus précisément, les liens ci-dessus indiquent:

Passer en mode édition:

Distributions Web - Cliquez sur l'onglet Origines, cliquez sur l'origine que vous souhaitez modifier, puis cliquez sur Modifier. Vous ne pouvez créer une identité d'accès à l'origine que pour les origines dont le type d'origine est l'origine S3.

Fondamentalement, afin de définir l'objet racine par défaut correct, nous utilisons le point de terminaison du site Web S3 et non le compartiment de site Web lui-même. Ceci n'est pas compatible avec l'utilisation de l'identité d'accès Origin. En tant que tel, mes questions se résument soit à

  1. Est-il possible de spécifier un objet racine par défaut pour tous les sous-répertoires d'un site Web hébergé statiquement sur Cloudfront?

  2. Est-il possible de configurer une identité d'accès Origin pour le contenu servi à partir de Cloudfront où Origin est un point de terminaison de site Web S3 et non un compartiment S3?

72
wyer33

MISE À JOUR: On dirait que j'étais incorrect! Voir la réponse de JBaczuk, qui devrait être la réponse acceptée sur ce fil.

Malheureusement, la réponse à vos deux questions est non.

1. Est-il possible de spécifier un objet racine par défaut pour tous les sous-répertoires d'un site Web hébergé statiquement sur Cloudfront?

Non. Comme indiqué dans les documents AWS CloudFront ...

... Si vous définissez un objet racine par défaut, une demande de l'utilisateur final pour un sous-répertoire de votre distribution ne renvoie pas l'objet racine par défaut. Par exemple, supposons que index.html est votre objet racine par défaut et que CloudFront reçoit une demande de l'utilisateur final pour le répertoire d'installation sous votre distribution CloudFront:

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

CloudFront ne renverra pas l'objet racine par défaut même si une copie de index.html apparaît dans le répertoire d'installation.

...

Le comportement des objets racine par défaut CloudFront est différent du comportement des documents d'index Amazon S3. Lorsque vous configurez un compartiment Amazon S3 en tant que site Web et spécifiez le document d'index, Amazon S3 renvoie le document d'index même si un utilisateur demande un sous-répertoire dans le compartiment. (Une copie du document d'index doit apparaître dans chaque sous-répertoire.)

2. Est-il possible de configurer une identité d'accès Origin pour le contenu servi à partir de Cloudfront où Origin est un point de terminaison de site Web S3 et non un compartiment S3?

Pas directement. Vos options pour les origines avec CloudFront sont des compartiments S3 ou votre propre serveur.

C'est cette deuxième option qui ouvre cependant des possibilités intéressantes. Cela va probablement à l'encontre de l'objectif de ce que vous essayez de faire, mais vous pouvez configurer votre propre serveur dont le seul travail consiste à être un serveur CloudFront Origin.

Lorsqu'une demande arrive http://d111111abcdef8.cloudfront.net/install/ , CloudFront transmet cette demande à votre serveur Origin, en demandant /install. Vous pouvez configurer votre serveur Origin comme vous le souhaitez, notamment pour servir index.html dans ce cas.

Ou vous pouvez écrire une petite application Web qui prend simplement cet appel et l'obtient directement de S3 de toute façon.

Mais je me rends compte que la configuration de votre propre serveur et le fait de s'inquiéter de sa mise à l'échelle peuvent aller à l'encontre de l'objectif de ce que vous essayez de faire en premier lieu.

2
Josh Padnick

Il y a [~ # ~] est [~ # ~] un moyen de le faire. Au lieu de le pointer vers votre compartiment en le sélectionnant dans la liste déroulante (www.example.com.s3.amazonaws.com), pointez-le vers le domaine statique de votre compartiment (par exemple, www.example.com.s3-website-us -west-2.amazonaws.com):

enter image description here

Merci à Ce fil du forum AWS

196
JBaczuk

L'activation de l'hébergement S3 signifie que vous devez ouvrir le compartiment au monde. Dans mon cas, je devais garder le compartiment privé et utiliser la fonctionnalité d'identité d'accès Origin pour restreindre l'accès à Cloudfront uniquement. Comme l'a suggéré @Juissi, une fonction Lambda peut corriger les redirections:

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

Après avoir publié votre fonction, accédez à votre distribution cloudfront dans la console AWS. Accédez à Behaviors, puis choisissezOrigin Request en dessous de Lambda Function Associations, et enfin collez l'ARN dans votre nouvelle fonction.

9
kenske

Il existe une autre façon d'obtenir un fichier par défaut servi dans un sous-répertoire, comme example.com/subdir/. Vous pouvez réellement (par programme) stocker un fichier avec la clé subdir/ dans le seau. Ce fichier pas apparaîtra dans la console de gestion S3, mais il existe réellement, et CloudFront le servira.

4
Johan Gorter

La solution de contournement consiste à utiliser lambda @ Edge pour réécrire les demandes. Il suffit de configurer le lambda pour l'événement de demande de visionneuse de la distribution CloudFront et de réécrire tout ce qui se termine par '/' ET n'est pas égal à '/' avec le document racine par défaut, par exemple index.html.

3
Juissi

Une autre alternative à l'utilisation de lambda @ Edge consiste à utiliser les pages d'erreur de CloudFront. Configurez un réponse d'erreur personnalisée pour envoyer tous les 403 vers un fichier spécifique. Ajoutez ensuite javascript à ce fichier pour ajouter index.html aux URL qui se terminent par un /. Exemple de code:

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
user1333371

Je sais que c'est une vieille question, mais je me suis juste débattu avec ça. En fin de compte, mon objectif était moins de définir un fichier par défaut dans un répertoire, et plus d'avoir le résultat final d'un fichier servi sans .html à la fin

J'ai fini par supprimer .html à partir du nom de fichier et définissez par programme/manuellement le type MIME sur text/html. Ce n'est pas la manière traditionnelle, mais cela semble fonctionner et répond à mes exigences pour les jolies URL sans sacrifier les avantages de la cloudformation. Définir le type mime est ennuyeux, mais un petit prix à payer pour les avantages à mon avis

1
whtevn

Il existe un guide "officiel" publié sur le blog AWS qui recommande de configurer une fonction Lambda @ Edge déclenchée par votre distribution CloudFront:

Bien sûr, c'est une mauvaise expérience utilisateur de s'attendre à ce que les utilisateurs tapent toujours index.html à la fin de chaque URL (ou même sachent que cela devrait être là). Jusqu'à présent, il n'y avait pas de moyen facile de fournir ces URL plus simples (équivalentes à la directive DirectoryIndex dans une configuration de serveur Web Apache) aux utilisateurs via CloudFront. Pas si vous voulez toujours pouvoir restreindre l'accès à l'origine S3 à l'aide d'un OAI. Cependant, avec la version de Lambda @ Edge, vous pouvez utiliser une fonction JavaScript exécutée sur les nœuds CloudFront Edge pour rechercher ces modèles et demander la clé d'objet appropriée à l'origine S3.

Solution

Dans cet exemple, vous utilisez la puissance de calcul sur CloudFront Edge pour inspecter la demande lorsqu'elle provient du client. Réécrivez ensuite la demande afin que CloudFront demande un objet d'index par défaut (index.html dans ce cas) pour tout URI de requête se terminant par ‘/’.

Lorsqu'une demande est faite sur un serveur Web, le client spécifie l'objet à obtenir dans la demande. Vous pouvez utiliser cet URI et lui appliquer une expression régulière afin que ces URI soient résolus en un objet d'index par défaut avant que CloudFront ne demande l'objet à l'Origin. Utilisez le code suivant:

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

};

Suivez le guide lié ci-dessus pour voir toutes les étapes nécessaires à la configuration, y compris le compartiment S3, la distribution CloudFront et la création de la fonction Lambda @ Edge .

1
Max Desiatov