Static website hosting on AWS with S3, CloudFront & Lambda@Edge

In an earlier blog entry of this series about static website hosting on Amazon Web Services I wrote on the few mistakes Taxi 020–or rather Cabonline Technologies–made in handling their website’s infrastructure on AWS and how these mistakes could have been mitigated by leveraging Amazon Simple Storage Service (S3) together with CloudFront.

I also wrote that I would come back to the infrastructure as code for static website hosting topic and elaborate on how it can be achieved with CloudFormation templates and CloudFormation stacks in AWS. Here are ready-to-use templates for three alternatives; from the simpler S3 only solution to the more advanced S3 with CloudFront and Lambda@Edge architecture.

Note. I deliberately left out the DNS part since not everyone manages their DNS records in Route53.

S3

CloudFormation template on Github

The simplest solution, which is well described in the Setting up a Static Website Using a Custom Domain walkthrough, leverages on S3 only. AWS does not however provide with a CloudFormation template to create the S3 bucket so follow the link to Github and have a look at the one I uploaded there.

Parameters

  1. your domain name

Resources created

  1. an S3 bucket with that name will be created if available. If not, static website hosting with S3 only will not be possible for that particular domain and the solution is to use S3 with CloudFront.

S3 with CloudFront

CloudFormation template on Github

If the previous solution cannot be implemented or if you want to leverage CloudFront and its 110+ points of presence around the globe this second template–also on Github–is for you.

Parameters

  1. your domain name
  2. the Amazon Resource Name (ARN) of the SSL certificate required to deliver content over HTTPS using your own domain name (instead of the CloudFront distribution domain name)

You can request a free certificate or import an existing certificate via AWS Certificate Manager.

Resources created

  1. an S3 bucket with a semi-random name
  2. a CloudFront distribution
  3. an Origin Access Identity
  4. an S3 bucket policy granting the CloudFront distribution read access to all objects in the S3 bucket

But as I wrote in my previous blog post there are limitations to that solution:

Limiting access to the S3 bucket from the CloudFront distribution only with Origin Access Identity comes with a price though as CloudFront must use the S3 REST endpoint–instead of the HTTP endpoint–which does not support redirection to default index pages.

S3, CloudFront & Lambda@Edge

CloudFormation template on Github

S3, CloudFront & Lambda@Edge

Last but not least, the S3 + CloudFront solution is sometimes not enough if you configured, for example, your favorite static site generator to produce clean URLs. While clean URLs are not an issue when served directly out of an S3 bucket, they do not work seamlessly with CloudFront as Ronnie Eichler very well explained on the AWS Compute blog back in October 2017.

For example, I generate–using Hugo–this blog with clean URLs and need to rewrite the path to all RESTful like resources in order for CloudFront to fetch a default index object from S3–done by appending index.html or /index.html to all requests that are not for objects with extension like images and scripts.

Again, have a look at the template I pushed to Github; it is the one I use to provision the AWS resources needed to serve this blog.

Before you go ahead and create a CloudFormation stack using my template make sure you select the us-east-1 region since “Lambda@Edge functions can now be authored in US East (N. Virginia), and will be replicated globally for invocation in response to CloudFront events.” - see Lambda@Edge now Generally Available.

Parameters

  1. your domain name
  2. the Amazon Resource Name (ARN) of the SSL certificate required to deliver content over HTTPS using your own domain name (instead of the CloudFront distribution domain name)
  3. a list of file extensions that you expect in a URL and for which URL rewriting to a default index object should not be performed: css, jpg, js, png, txt for example

Resources created

  1. an S3 bucket with a semi-random name
  2. a CloudFront distribution
  3. an Origin Access Identity
  4. an S3 bucket policy that grants the CloudFront distribution read access objects in the S3 bucket
  5. a Lambda function to perform URI rewriting
  6. an IAM execution role for the Lambda function
  7. a parameter in AWS Systems Manager > Parameter store holding the list of file extensions (simplifies additions to and removals from the initial list)

The template also glues together the Lambda function with the CloudFront distribution in order to intercept–the CloudFront distribution triggers the Lambda function–requests made to the origin (origin request event) and rewrite the requested object path.

Don’t fool yourself

Whether you go for solution 1, 2 or 3, keep in mind that a quick and secured architecture is just something you must have. Technicalities always should remain invisible to the users. Only content is king and always will be.

Part 1: Taking over taxi020.se, yet another S3 rookie mistake

Comments