La implementación de un sitio en Angular hosteado sobre Amazon S3 y CloudFront presenta algunos desafíos de configuración para poder ajustar el routing de manera correcta.

El problema es que cuando uno accede a una URL generada por el router de Angular, el path en realidad no existe, y al recargar la página, Amazon, según la configuración que tengamos, nos devolverá un 403 o un 404.

Cuando realizamos la configuración de S3 y CloudFront para servir el contenido, podemos elegir entre dos configuraciones de seguridad para el acceso al contenido:

  • Permitiendo el acceso sólo mediante CloudFront. (Restingiendo mediante Origin Access Identity en la policy del bucket)
  • Permitiendo el acceso mediante CloudFront y también directo mediante S3.

La segunda opción nos quita un poco de control, por qué en CloudFront entre otras cosas podemos configurar por ejemplo auditoría, https y muchas opciones que en S3 no podemos (además de obviamente la cdn propiamente dicha), y si los usuarios lo bypasean se las estarían salteando.

Hay diferentes maneras de solucionar esto:

RoutingRules en S3

La primera opción es editar las reglas de ruteo directamente en S3. Lo que le decimos a la config es que cuando devuelva un 404, lo redireccione a la raiz.

<RoutingRules>
	<RoutingRule>
		<Condition>
			<HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
		</Condition>
		<Redirect>
			<HostName>3ops.com</HostName>
			<ReplaceKeyPrefixWith>#!/</ReplaceKeyPrefixWith>
		</Redirect>
	</RoutingRule>
</RoutingRules>

El problema de este método, es que cuando pasamos por Cloudfront y el S3 está restringido a únicamente CloudFront, no funciona. Devuelve un 403 (forbiden).

Custom Error Pages en CloudFront

La segunda opción es generar un Custom Error Page en CloudFront, y redireccionar el response 403 a /index.html o a la raiz.

A saber, Amazon S3 devuleve un 403 en vez de un 404 cuando no existe el archivo que se busca y no se tiene permiso de ListBucket.

Saludos!