2

I'm hosting a static website on AWS S3, served through AWS Cloudfront. Site is build with Hugo in multilingual mode. So it redirects from index page "/" to default lang index page url /en . On this page I get error access denied. When I manually type URL /en/index.html page loaded normally.

How should I setup AWS bucket or Hugo to show page properly?

qwelp
  • 111
  • 7

3 Answers3

0

Find answer in this post CloudFront + S3 Website: "The specified key does not exist" when an implicit index document should be displayed I need to use the bucket's web site hosting endpoint as the origin domain name in Cloudfront setup

qwelp
  • 111
  • 7
0

One way of doing it is to follow the link shared by @qwelp,whereby the solution states that if you are using S3 REST API endpoint as opposed to the static website hosting, you would need to change the origin of your CloudFront from "S3" to "custom" origin.

The other way to solve this is implement a lambda edge function that redirects all user requests that requests files in hugo sub-directories. As quoted inAWS Knowledge Center here ;

use Lambda@Edge to be able to use CloudFront with an S3 origin access identity and serve a default root object on subdirectory URLs.

From AWS Knowledge Center

Why isn't CloudFront returning my default root object from a subdirectory? Issue Why isn't Amazon CloudFront returning my default root object from a subfolder or subdirectory? Resolution The default root object feature for CloudFront supports only the root of the origin that your distribution points to. CloudFront doesn't return default root objects in subdirectories. For more information, see Specifying a Default Root Object.

If your CloudFront distribution must return the default root object from a subfolder or subdirectory, you can integrate Lambda@Edge with your distribution. For an example configuration, see Implementing Default Directory Indexes in Amazon S3-backed Amazon CloudFront Origins Using Lambda@Edge.

Important: You'll be charged an additional fee when you use Lambda@Edge. For more information, see Lambda@Edge Pricing Details.

As stated in AWS Knowledge Center here "In this example, you use the compute power at the CloudFront edge to inspect the request as it’s coming in from the client. Then re-write the request so that CloudFront requests a default index object (index.html in this case) for any request URI that ends in ‘/’."

The Lambda Edge Function in JS:

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

};

Ensure that you gave the Lambda@Edge function IAM permissions

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:*:*:*"
            ]
        }
    ]
}
crakama
  • 759
  • 11
  • 25
0

I suffered the same problem and I ended up setting up my S3 bucket as public, I didn't want to pay an extra Lambda for handling this.

Here is a post explaining the situation.

Albert
  • 146
  • 2
  • 12