August 23, 2020

Fixing "AccessDenied" Errors for Static Websites in Cloudfront

Painted wooden door with locks Photo by Rod Long

TLDR

To fix “AccessDenied” errors on static website pages, such as those generated by Hugo, when deployed to S3 and served with Cloudfront, change the Origin Domain Name property to the S3 bucket endpoint found in the Static Website Hosting property.

Our Problem

If we deploy our static site to Amazon’s S3 Static Website Hosting, and serve the content with AWS Cloudfront, we may find that pages other than the homepage give an “AccessDenied” error message.

Generated Path

When building our static site with a generator such as Hugo, we create content pages such as the About page. However, instead of generating example.com/about.html, the site page generated is typically something like example.com/about/index.html. But we would like to reach the About page by navigating to its directory example.com/about/ without explicitly specifying /index.html in the path.

Normally, if no file extension is specified in the URL, a web server will assume that is a directory path and look for an index.html file to serve to the user. Hosting our site directly from S3 without Cloudfront, does exactly this. Adding Cloudfront changes this functionality, and only looks for this file from the root directory example.com/

Default Root Object

In this case the index.html page is our “Default Root Object”. Note that in both S3 and Cloudfront we need to specify the name of the “Default Root Object”. Again, S3 will look for index.html file after any path if we use it without Cloudfront. However, if we serve our site with Cloudfront, it will only look for this file in the root directory.

Origin Domain Name

To resolve this, we can replace the path made available in the Origin Domain Name dropdown (example.com.s3.amazonaws.com), with the Endpoint shown in the Static website hosting in the S3 Properties (example.com.s3-website-us-east-1.amazonaws.com). This effectively bypasses Cloudfront’s behavior in favor of S3’s.

Additional Information

While this solution works, it affects the ability to restrict direct access to the S3 endpoint by a client. AWS offers another solution, which is to modify the incoming URLs with Lambda@Edge See this StackOverflow post for additional discussion of this topic.