SummaryUsing a combination of S3 and CloudFront, hosting a static website in AWS is simple and very affordable. In this post, I discuss the architecture of such a solution and the reference implementation I have created to get you started.
The most economical way to host a “web scale” site is to generate static files and to host and serve them with a Content Delivery Network (CDN). CDN’s push your files to geographically distributed servers that will offer user’s the lowest latency when requesting files. In AWS, the CDN solution is CloudFront. With CloudFront, we can configure one or more origins for a given distribution. CloudFront will route requests to the appropriate origin and cache the results. In this solution, we will put CloudFront in front of an S3 bucket. S3 is a highly scalable object storage service provided by Amazon. It enables you to store massive amounts of files for many different use cases.
Most organizations have a policy against creating public buckets. For this solution, I have placed a private S3 bucket behind a CloudFront distribution. The ramifications of this is that we need to create an origin access identity for CloudFront to access the S3 bucket. In addition, it requires a lambda to run at the edge location. This lambda is responsible for turning
/ requests to
/index.html. Unfortunately, this lambda runs for every request. This could potentially get expensive. For this reason, I have turned up the default cache TTL to a year. This means a resource will be served from the distribution before hitting the origin.
If you wish to update your site, you will need a mechanism for invalidating the cache. This can be a lambda triggered by S3 bucket events or an action in a pipeline. For my use, I have added an action to my CodePipeline. During the deployment staging, after the files have been pushed to S3, the distribution is invalidated.
One note, this template creates a certificate in ACM and uses it for the CloudFront distribution. This will require DNS validation that you own the domain. The ACM creation will suspend and output the required entries into your DNS Zone. You can do it this way or pass the ACM Certificate ARN in as a parameter.
Should you need to use dynamically generated content, you will need to add an additional origin to the CloudFront distribution. This will be in the origins configuration of the CloudFormation template. If you wish to do this, consider adding WAF rules to protect the application against user malfeasance.
I have added the templates to my AWS Reference Implementations repository. This repository includes two CloudFormation templates from this post:
- cloudfront-s3-bucket - CloudFront distribution in front of a private S3 bucket
- codepipeline-hugo-site - Template that creates a CodePipeline for a Hugo generated static site and pushes to S3
I am open to feedback and improvements to the templates via standard GitHub issues or pull requests.