[Part 2] Hosting a Hugo Static Site on AWS

[Part 2] Hosting a Hugo Static Site on AWS

This is part two of a two part series about hosting Hugo on AWS.

Intro

In Part 1 I deployed the Hugo website to S3, and put cloudfront in-front of it. Today i’ll:

  • Add Origin Access Control to force traffic via the CloudFront & Private the S3 bucket.
  • Add Cloudfront Functions for custom URI redirecting

Table of contents

Requirements

Origin Access Control

OAC provides a secure way to access S3 origins to CloudFront. It’s the successor to OAI (Origin Access Identity) as it provides a number of improvements over OAI including comprehensive HTTP method support, S3 KMS encryption support and more.

We need to secure our S3 bucket and restrict access to the website strictly via S3.

Should be simple. Let’s create the OAC via AWS CLI.

aws cloudfront create-origin-access-control --origin-access-control-config Name="demo-site",Description="demo hugo website",SigningProtocol="sigv4",SigningBehavior="always",OriginAccessControlOriginType="s3"

And now we plug it into CloudFront.

Adding OAC

Adding OAC

Adding OAC

Let’s follow that link and overwrite the bucket policy.

Overwriting bucket policy

Overwriting bucket policy

Overwriting bucket policy

Great! So let’s test.

Attempting to access the S3 static site directly

http://jeremyritchie-demo-hugo.s3-website-ap-southeast-2.amazonaws.com/

S3 Error

S3 Error

S3 Error

However if we access cloudfront via demo.jeremyritchie.com

OAC Works!

OAC Works!

OAC Works!

Cloudfront Functions

What are CloudFront Fuctions and Why do i need them?

CloudFront Functions are a compute platform where you can manipulate the request/response data for your website. Examples such as shortening URL’s, redirects, adding cookies or headers, etc.

CloudFront Functions

CloudFront Functions

CloudFront Functions

Cloudfront Functions are very very similar to Lambda@Edge, but provide faster latency and lower cost, and the cost of flexibility and execution time. Check out this post here.

So why do I need them?

Well let’s add a post to our demo website

hugo new posts/my-first-post.md
echo "my first post" >> content/posts/my-first-post.md
hugo --buildDrafts
hugo deploy --force

Error!

Error!

Error!

The post is not working?!

Let’s try a slightly different URL: https://demo.jeremyritchie.com/posts/my-first-post/index.html

Working again??

Working again??

Working again??

What’s going on here is what you expect from SSG (Static Site Generators) - It’s taking complex input from themes and markdown and more, and using it to generate a static file structure of html files.

The consequence is that for any publicly visible URL, there must be a filesystem entity (either a file, or a directory containing an index.html file). This means loading demo.jeremyritchie.com needs to implicitly load demo.jeremyritchie.com/index.html

That’s easy, because on S3 you set a index document, and on Cloudfront, we configured a Default Root Object.

When it comes to a post, we’re no longer being helped by built-in redirection provided by S3 or CloudFront. We need to build it our self.

We know Hugo likes to add a trailing / to each page. But we need it to end in /index.html instead.

That’s where CloudFront Functions come in. Let’s check it out!

CloudFormation Function Create

CloudFormation Function Create

CloudFormation Function Create

function handler(event) {
    var request = event.request;
    var uri = request.uri;
    
    // Logging
    console.log(request)
    

    // Check whether the URI is index.html
    if (uri.endsWith('/')) {
        request.uri += 'index.html';
    }
    
    // other custom redirects
    else if (uri.endsWith('blog') || uri.endsWith('jeremy-ritchie')) {
        request.uri += '/index.html';
    }

    return request;
}

Add this code to the function and then publish it.

Function Publish & Associate

Function Publish & Associate

Function Publish & Associate

After publishing, you are able to associate it to a distribution:

  • Distribution - Your hugo website!
  • Event type - Viewer Request
  • Cache behavior - Default (*)

Function Publish & Associate

Function Publish & Associate

Function Publish & Associate

Alright! We’re associated that Function.

Let’s retest https://demo.jeremyritchie.com/posts/my-first-post/

Working Blog Post URL!

Working Blog Post URL!

Working Blog Post URL!

Conclusion

Holy macaroni! We’ve done it.

We’ve both locked down the website to CloudFront only, and added some wicked cool Functions that run at the edge!

For more reading about Hugo + CloudFront OAC + index.html issue. Check out this link: https://aws.amazon.com/blogs/compute/implementing-default-directory-indexes-in-amazon-s3-backed-amazon-cloudfront-origins-using-lambdaedge/

comments powered by Disqus