S3 Static Hosting Lessons

Some tricks I learned setting this whole thing up.

There are a lot of parts getting this whole thing set up.

S3 and CloudFront can’t find default root objects

Hugo uses a directory url by default (i.e. website.com/post/post_title/). When a directory url is passed to the server, it looks for the default root object in that directory. S3 is not a file system, it is an object storage system. Asking for a key (s3://website-bucket/post/post_title/) fails to find the index.html file inside that folder.

You’ll get an error like this:

This XML file does not appear to have any style information associated with it. The document tree is shown below.
<Error>
  <Code>NoSuchKey</Code>
  <Message>The specified key does not exist.</Message>
  <Key>index.html</Key>
  <RequestId>C8E2EDE206C2B1B5</RequestId>
  <HostId>
    0J8imf9YuVNW1sRbQQOtzFSRXFzpl25t2p1B9l9p6MYc+fs7+GhFZdJQ/qYhA68gxodjAYzlzx4=
  </HostId>
</Error>

When setting up CloudFront, it’s tempting to use the standard reference to S3 for your origin. In fact, the console very much encourages you to set it up this way: AWS Console CloudFront Create Origin

When hosting from S3, there are two URLs provided. You can see them in the CloudFormation S3::Bucket return values. One is the DomainName, which is the standard way to reference S3. This works for websites where they’re not referencing directories for their pages. This doesn’t work for Hugo sites. The second is WebsiteURL, which is the one we want to use. By using the WebsiteURL as a custom origin domain, it supports referencing directories. I wracked my brain for a long time over this one.

Use http-only protocol for S3 origin

After deploying this infrastructure, I was getting really long load times and some were timing out. I thought I was having problems with cached responses, so I left it overnight to clear. In the morning, it wasn’t resolved. After digging into it more, I found that I had set OriginProtocolPolicy: match-viewer. Documented here, it clearly says that S3 endpoints must be http-only. Once I flipped that switch, the load time for my site plunged into sub-seconds. There’s some more optimization that could happen here, but I’ll handle that after I build my own Hugo theme.