¿Cómo se configura un objeto raíz predeterminado para los subdirectorios de un sitio web alojado estáticamente en Cloudfront?

100

¿Cómo se configura un objeto raíz predeterminado para subdirectorios en un sitio web alojado estáticamente en Cloudfront? Específicamente, me gustaría que me www.example.com/subdir/index.htmlsirvieran cuando el usuario lo solicite www.example.com/subdir. Tenga en cuenta que esto es para entregar un sitio web estático en un bucket de S3. Además, me gustaría usar una identidad de acceso de origen para restringir el acceso al bucket de S3 solo a Cloudfront.

Ahora, soy consciente de que Cloudfront funciona de manera diferente a S3 y Amazon afirma específicamente :

El comportamiento de los objetos raíz predeterminados de CloudFront es diferente del comportamiento de los documentos de índice de Amazon S3. Cuando configura un bucket de Amazon S3 como sitio web y especifica el documento de índice, Amazon S3 devuelve el documento de índice incluso si un usuario solicita un subdirectorio en el bucket. (Debe aparecer una copia del documento de índice en cada subdirectorio). Para obtener más información sobre la configuración de buckets de Amazon S3 como sitios web y sobre documentos de índice, consulte el capítulo Alojamiento de sitios web en Amazon S3 en la Guía para desarrolladores de Amazon Simple Storage Service.

Como tal, aunque Cloudfront nos permite especificar un objeto raíz predeterminado, esto solo funciona para www.example.comy no para www.example.com/subdir. Para sortear esta dificultad, podemos cambiar el nombre de dominio de origen para que apunte al punto final del sitio web proporcionado por S3. Esto funciona muy bien y permite que los objetos raíz se especifiquen de manera uniforme. Desafortunadamente, esto no parece ser compatible con las identidades de acceso de origen . Específicamente, los enlaces anteriores indican:

Cambiar al modo de edición:

Distribuciones web: haz clic en la pestaña Orígenes, haz clic en el origen que deseas editar y haz clic en Editar. Solo puede crear una identidad de acceso de origen para los orígenes para los que el Tipo de origen es Origen S3.

Básicamente, para establecer el objeto raíz predeterminado correcto, usamos el punto final del sitio web de S3 y no el depósito del sitio web en sí. Esto no es compatible con el uso de la identidad de acceso de origen. Como tal, mis preguntas se reducen a

  1. ¿Es posible especificar un objeto raíz predeterminado para todos los subdirectorios de un sitio web alojado estáticamente en Cloudfront?

  2. ¿Es posible configurar una identidad de acceso de origen para el contenido servido desde Cloudfront donde el origen es un punto final del sitio web de S3 y no un depósito de S3?

wyer33
fuente
1
Creo que esto ahora es posible con Lambda @ edge, usando una función que redirige todas las URL que terminan en / a /index.html. Lo probaré en mi sitio web, informaré los resultados y publicaré la configuración detallada como respuesta.
Cristian Măgherușan-Stanciu

Respuestas:

2

ACTUALIZACIÓN: ¡Parece que estaba equivocado! Vea la respuesta de JBaczuk, que debería ser la respuesta aceptada en este hilo.

Desafortunadamente, la respuesta a ambas preguntas es no.

1. ¿Es posible especificar un objeto raíz predeterminado para todos los subdirectorios de un sitio web alojado estáticamente en Cloudfront?

No. Como se indica en los documentos de AWS CloudFront ...

... Si define un objeto raíz predeterminado, una solicitud del usuario final para un subdirectorio de su distribución no devuelve el objeto raíz predeterminado. Por ejemplo, supongamos que index.htmles su objeto raíz predeterminado y que CloudFront recibe una solicitud del usuario final para el directorio de instalación en su distribución de CloudFront:

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

CloudFront no devolverá el objeto raíz predeterminado incluso si index.htmlaparece una copia de en el directorio de instalación.

...

El comportamiento de los objetos raíz predeterminados de CloudFront es diferente del comportamiento de los documentos de índice de Amazon S3. Cuando configura un bucket de Amazon S3 como sitio web y especifica el documento de índice, Amazon S3 devuelve el documento de índice incluso si un usuario solicita un subdirectorio en el bucket. (Debe aparecer una copia del documento índice en cada subdirectorio).

2. ¿Es posible configurar una identidad de acceso de origen para el contenido servido desde Cloudfront donde el origen es un punto final del sitio web de S3 y no un depósito de S3?

No directamente. Sus opciones para orígenes con CloudFront son buckets S3 o su propio servidor.

Sin embargo, es esa segunda opción la que abre algunas posibilidades interesantes. Esto probablemente anula el propósito de lo que está tratando de hacer, pero podría configurar su propio servidor cuyo único trabajo es ser un servidor de origen de CloudFront.

Cuando llega una solicitud para http://d111111abcdef8.cloudfront.net/install/ , CloudFront reenviará esta solicitud a su servidor de origen, solicitando /install. Puedes configurar tu servidor de origen como quieras, incluso para servir index.htmlen este caso.

O puede escribir una pequeña aplicación web que simplemente tome esta llamada y la obtenga directamente de S3 de todos modos.

Pero me doy cuenta de que configurar su propio servidor y preocuparse por escalarlo puede frustrar el propósito de lo que está tratando de hacer en primer lugar.

Josh Padnick
fuente
El único problema que tengo con esto es que hacer que esto funcione significa que tendría dos (2) URL capaces de acceder a su sitio web en s3. Tu URL frontal en la nube y tu URL s3 (bucket_name.s3-website-us-east-1.amazonaws.com)
Hayden
223

Hay ES una manera de hacer esto. En lugar de apuntarlo a su depósito seleccionándolo en el menú desplegable (www.example.com.s3.amazonaws.com), apúntelo al dominio estático de su depósito (por ejemplo, www.example.com.s3-website-us -west-2.amazonaws.com):

ingrese la descripción de la imagen aquí

Gracias a este hilo del foro de AWS

JBaczuk
fuente
6
¿Alguien sabe si esto se cobra de manera diferente al tener un origen s3 frente a un origen web?
fideloper
3
¿Funciona bien si quiero publicar todo mi sitio web y archivos HTTPSúnicamente?
Manjit Kumar
3
¿Significa que el S3 tiene que estar habilitado como servidor web?
Anthony Kong
6
OP declaró explícitamente que este enfoque no funcionará para él: "Para superar esta dificultad, podemos cambiar el nombre de dominio de origen para que apunte al punto final del sitio web proporcionado por S3. Esto funciona muy bien y permite que los objetos raíz se especifiquen de manera uniforme. Desafortunadamente , esto no parece ser compatible con las identidades de acceso de origen ". AWS parece estar recomendando lamda @ edge para esto - aws.amazon.com/blogs/compute/…
icyitscold
3
Esto no es compatible con Cloud Front - Origin Access Identity. No podrá restringir el acceso a su bucket de S3 de esta manera.
rocketspacer
15

Activar el alojamiento S3 significa que tienes que abrir el depósito al mundo. En mi caso, necesitaba mantener el depósito en privado y usar la funcionalidad de identidad de acceso de origen para restringir el acceso solo a Cloudfront. Como sugirió @Juissi, una función Lambda puede corregir los redireccionamientos:

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

Después de publicar su función, vaya a su distribución en la nube en la consola de AWS. Vaya a Behaviors, luego elija Origin Requestdebajo Lambda Function Associationsy finalmente pegue el ARN en su nueva función.

kenske
fuente
5
Hay una lista para desplegarse lambda función similar a uno: serverlessrepo.aws.amazon.com/applications/...
marcanuy
El problema aquí es que esta función debe implementarse en us-east-1, por lo que si tiene una empresa bajo una estricta regulación GDPR que no permite ni un solo bit fuera de Alemania, entonces esto no es para usted.
Renato Gama
5

Hay otra forma de obtener un archivo predeterminado servido en un subdirectorio, como example.com/subdir/. De hecho, puede almacenar (programáticamente) un archivo con la clave subdir/en el depósito. Este archivo no aparecerá en la consola de administración de S3, pero en realidad existe y CloudFront lo servirá.

Johan Gorter
fuente
S3 converst subdir / to subdir; cuando intenta cargar el HTML. Además, cuando intenta acceder a example.com/subdir/ falla, y si intenta acceder a example.com/subdir; descarga el archivo HTML en lugar de renderizarlo.
jacobfogg
4

La solución al problema es utilizar lambda @ edge para reescribir las solicitudes. Solo se necesita configurar la lambda para el evento de solicitud del visor de la distribución de CloudFront y reescribir todo lo que termina con '/' Y no es igual a '/' con el documento raíz predeterminado, por ejemplo, index.html.

Juissi
fuente
Más detalles sobre este enfoque aquí: aws.amazon.com/blogs/compute/…
Henrik Aasted Sørensen
lamentablemente, Lambda @ Edge solo funciona en la región us-east-1, fuente: github.com/awslabs/serverless-application-model/issues/635
mruanova
4

Existe una guía "oficial" publicada en el blog de AWS que recomienda configurar una función Lambda @ Edge activada por su distribución de CloudFront:

Por supuesto, es una mala experiencia de usuario esperar que los usuarios escriban siempre index.html al final de cada URL (o incluso que sepan que debería estar allí). Hasta ahora, no había una manera fácil de proporcionar estas URL más simples (equivalentes a la Directiva DirectoryIndex en una configuración de servidor web Apache) a los usuarios a través de CloudFront. No, si aún desea poder restringir el acceso al origen de S3 mediante un OAI. Sin embargo, con el lanzamiento de Lambda @ Edge, puede usar una función de JavaScript que se ejecuta en los nodos de borde de CloudFront para buscar estos patrones y solicitar la clave de objeto adecuada del origen de S3.

Solución

En este ejemplo, utiliza la potencia informática en el borde de CloudFront para inspeccionar la solicitud a medida que proviene del cliente. Luego, vuelva a escribir la solicitud para que CloudFront solicite un objeto de índice predeterminado (index.html en este caso) para cualquier URI de solicitud que termine en '/'.

Cuando se realiza una solicitud contra un servidor web, el cliente especifica el objeto a obtener en la solicitud. Puede usar este URI y aplicarle una expresión regular para que estos URI se resuelvan en un objeto de índice predeterminado antes de que CloudFront solicite el objeto desde el origen. Utilice el siguiente código:

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

};

Siga la guía vinculada anteriormente para ver todos los pasos necesarios para configurar esto, incluido el depósito S3, la distribución de CloudFront y la creación de la función Lambda @ Edge .

Max Desiatov
fuente
2

Otra alternativa al uso de lambda @ edge es usar las páginas de error de CloudFront. Configure una Respuesta de error personalizada para enviar todos los 403 a un archivo específico. Luego agregue javascript a ese archivo para agregar index.html a las URL que terminan en /. Código de muestra:

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>");
}
usuario1333371
fuente
1

Sé que esta es una vieja pregunta, pero yo mismo luché con esto. En última instancia, mi objetivo era menos establecer un archivo predeterminado en un directorio y más tener el resultado final de un archivo que se sirvió sin .htmlal final

Terminé eliminando .htmldel nombre de archivo y configuré programada / manualmente el tipo de mime en text/html. No es la forma tradicional, pero parece funcionar y satisface mis requisitos de URL bonitas sin sacrificar los beneficios de la formación en la nube. Establecer el tipo de mímica es molesto, pero en mi opinión es un pequeño precio a pagar por los beneficios.

whtevn
fuente