Cloudfront Static Site
S3 is a really basic service that allows us to store files in the cloud. Cloudfront is a more advanced service that allows us to take those files stored in an S3 bucket and distribute them globally.
If our static files exist in a bunch of locations around the world, this will significantly reduce latency when people request our files. On top of that we get a lot more power over cloudfront than we do s3 and we can add custom domain names and ssl certificates. We can also run lightweight serverless functions in cloudfront, but that's a topic for another day.
We are going to host a static website using S3 and Cloudfront.
Here's what we'll do:
- Create another S3 Bucket to store the files
- Create a Cloudfront Distribution to serve the files from the bucket
- Enable website hosting in cloudfront
- Add a dns record to point to the cloudfront distribution
- Setup a certificate to use https
Static Site Requirements
You can use any static site you want for this, it just has to be valid HTML and optionally css, javascript, images, and other assets.
If you wan't, you can use this qr code generator as your static site. Just download the dist.zip folder and unzip it. It contains the index.html
file and other assets. Feel free to clone the react code and play around with the app if you like.
- How to host a website using cloudfront
- Set up a custom domain name with an SSL certificate so that you can access your site over https
This is different than the steps we went through to host a static website in an S3 bucket. It's just a simple S3 bucket with the files stored it it.
- It doesn't matter what you name the bucket, as long as it's unique
- You don't need to configure any special permissions on the bucket
- You don't need to enable web hosting on the bucket
You can do this through the AWS console, or you can use the AWS CLI. If you run the following script, make sure you change the four variables at the top.
#!/bin/bash
bucket_name='a-bucket-name'
# website_directory must be the path to the folder that contains your index.html file
website_directory='/path/to/website/'
region='us-west-2'
profile='playground-profile'
# 1. Create a new bucket with a unique name
aws s3 mb --profile $profile --region $region "s3://$bucket_name"
# 2. Upload you website
aws s3 sync --profile $profile --region $region $website_directory "s3://$bucket_name/"
#!/bin/bash
bucket_name='a-bucket-name'
# website_directory must be the path to the folder that contains your index.html file
website_directory='/path/to/website/'
region='us-west-2'
profile='playground-profile'
# 1. Create a new bucket with a unique name
aws s3 mb --profile $profile --region $region "s3://$bucket_name"
# 2. Upload you website
aws s3 sync --profile $profile --region $region $website_directory "s3://$bucket_name/"
#!/bin/bash
bucket_name='a-bucket-name'
# website_directory must be the path to the folder that contains your index.html file
website_directory='/path/to/website/'
region='us-west-2'
profile='playground-profile'
# 1. Create a new bucket with a unique name
aws s3 mb --profile $profile --region $region "s3://$bucket_name"
# 2. Upload you website
aws s3 sync --profile $profile --region $region $website_directory "s3://$bucket_name/"
#!/bin/bash
bucket_name='a-bucket-name'
# website_directory must be the path to the folder that contains your index.html file
website_directory='/path/to/website/'
region='us-west-2'
profile='playground-profile'
# 1. Create a new bucket with a unique name
aws s3 mb --profile $profile --region $region "s3://$bucket_name"
# 2. Upload you website
aws s3 sync --profile $profile --region $region $website_directory "s3://$bucket_name/"
Remember that CloudFront doesn't actually host files, it just catches them. So it will cache the files from our S3 bucket all around the globe. But the files only really live in the S3 bucket.
Nothing is able to directly access the files in the S3 bucket, and this will allow us to keep the S3 bucket private. It will generate a policy that we can add to the S3 bucket to only allow this CloudFront distribution to access the files in the bucket.
We will need to manually add the policy to S3 after we've setup this CloudFront distribution.
Everything in AWS already comes with a free service called AWS Shield. This protects our infrastructure from basic attacks. But for an extra fee, we can add extra security to our CloudFront distribution.
This is a nice feature, but costs $8 a month minimum, more if you have a lot of network traffic.
This only tells CloudFront that we will want to access it using that domain. We are still responsible for setting up a record in Route53 and creating a certificate so that it can accept traffic over HTTPS.
Requesting a Certificate
It's now pending validation. We need to setup a record in Route53 to allow certificate manager to perform the DNS validation.
Luckily, certificate manager can create the certificate for us in Route53 and validation should happen within a couple of minutes. If it doesn't, double check your domain name is a valid subdomain of your hosted zone.
The distribution will take a moment to completely setup everywhere in the world. But that gives us time to do all of the other setup steps
S3 Policy
Route 53
Now we need to setup the record in Route 53 to direct people to the CloudFront distribution when they visit the custom subdomain.
We need to setup an A
record to map to IPv4 and a AAAA
record for IPv6.
Error Page
We're almost done, just one more thing to take care of. If someone tries to visit our CloudFront site using an invalid path like example.com/invalid-path
then they will get the default cloudfront 403 error page. This is fine if we're just using CloudFront for normal file caching, but not great when it's hosting a website.
One fix to this is to direct them to a custom error page. Or when we're hosing an SPA, we'll just always serve up index.html
and let the client side JavaScript give a nicer error message to the user.
Now the site should be ready to use. Try visiting your custom domain and playing around with the site.
At this point, you're done, you've completed everything to deploy a static site globally. You can continue reading if you want to know how to update a site once it's deployed.
Update Website
If you make a change to your website, how do you deploy those updates?
Remember that the files live in S3 and CloudFront is caching them. So if you need to update any of the assets on the site, you'll need to:
-
Update the files in the S3 bucket
-
Invalidate the CloudFront cache to use the new files
You can update the files in S3 using the cli, or by dragging and dropping in the web console. Only after you've done that, should you invalidate the CloudFront cache.
Now CloudFront will serve the updated files. If you wanted to do this last part using the AWS CLI, it would look something like this:
# Sync @3 bucket contents
aws s3 sync directory-path "s3://your-bucket-name/"
# Invalidate the CloudFront distribution
aws cloudfront create-invalidation --distribution-id your-distribution-id --paths '/*'
# Sync @3 bucket contents
aws s3 sync directory-path "s3://your-bucket-name/"
# Invalidate the CloudFront distribution
aws cloudfront create-invalidation --distribution-id your-distribution-id --paths '/*'
# Sync @3 bucket contents
aws s3 sync directory-path "s3://your-bucket-name/"
# Invalidate the CloudFront distribution
aws cloudfront create-invalidation --distribution-id your-distribution-id --paths '/*'
# Sync @3 bucket contents
aws s3 sync directory-path "s3://your-bucket-name/"
# Invalidate the CloudFront distribution
aws cloudfront create-invalidation --distribution-id your-distribution-id --paths '/*'