Cloud Course

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
step 1:

Create a new S3 bucket in your playground account and upload your website files to it.

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/"
step 2:

Make sure you're logged into your Playground account

Make sure you're logged into your Playground account
step 3:

Navigate to the CloudFront dashboard

Navigate to the **CloudFront** dashboard
step 4:

Click on Create a CloudFront distribution

Click on **Create a CloudFront distribution**
step 5:

Select the name of the S3 bucket you setup in a previous step

Select the name of the S3 bucket you setup in a previous step

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.

step 6:

Select Origin access control settings (recommended)

Select **Origin access control settings (recommended)**
step 7:

Click on Select an origin access control

Click on Select an origin access control
step 8:

Select Origin access control settings (recommended)

Then click on Create new OAC

Select **Origin access control settings (recommended)**   Then click on **Create new OAC**

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.

step 9:

Click on Create

Click on **Create**

We will need to manually add the policy to S3 after we've setup this CloudFront distribution.

step 10:

Select Redirect HTTP to HTTPS

Select Redirect **HTTP to HTTPS**

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.

step 11:

If you want to keep this free, select Do not enable security protections

If you want to keep this free, select **Do not enable security protections**
step 12:

Under Alternate domain name Click on Add item

Under **Alternate domain name** Click on Add item
step 13:

Add a custom sub domain

Make sure this is a valid subdomain of your playground hosted zone (subdomain.play.yourdomain.com)

Add a custom sub domain   Make sure this is a valid subdomain of your **playground** hosted zone ...

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

step 14:

Click on Request certificate which will open a new certificate manager window

Click on **Request certificate** which will open a new certificate manager window
step 15:

Click on Next to start

Click on **Next** to start
step 16:

Type in the same sub domain you added to CloudFront

Type in the same sub domain you added to CloudFront
step 17:

Leave all the other settings alone and click on Request

Leave all the other settings alone and click on **Request**

It's now pending validation. We need to setup a record in Route53 to allow certificate manager to perform the DNS validation.

step 18:

Click on Create records in Route 53

Click on **Create records in Route 53**
step 19:

Click on Create records

Click on **Create records**

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.

step 20:

Go back to CloudFront and refresh the certificates

Go back to CloudFront and refresh the certificates
step 21:

Select the certificate that you just made

Select the certificate that you just made
step 22:

Under default root object, type "/index.html"

This is the default file that will be served when anyone visits our site

Under default root object, type "/index.html"   This is the default file that will be s...
step 23:

Click on Create distribution

Click on **Create distribution**

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

step 24:

Click on Copy policy to copy the S3 policy

Click on **Copy policy** to copy the S3 policy
step 25:

Navigate to the S3 dashboard

Navigate to the S3 dashboard
step 26:

Select the bucket that's connected to the CloudFront distribution

Select the bucket that's connected to the CloudFront distribution
step 27:

Click on Permissions

Click on Permissions
step 28:

Click on Edit next to Bucket policy

Click on **Edit** next to **Bucket policy**
step 29:

Paste in the policy, and click Save changes

Paste in the policy, and click **Save changes**

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.

step 30:

Navigate to the Route 53 dashboard and select your play hosted zone

Navigate to the Route 53 dashboard and select your play hosted zone
step 31:

Click on Create record

Click on **Create record**
step 32:

Select Simple routing and click Next

Select **Simple routing** and click **Next**
step 33:

Click on Define simple record to create the A record

Click on **Define simple record** to create the `A` record
step 34:

Input the subdomain you used with your cloudfront distribution

Input the subdomain you used with your cloudfront distribution
step 35:

Select Alias to CloudFront distribution

Select **Alias to CloudFront distribution**
step 36:

Select the CloudFront distribution you just setup

Select the CloudFront distribution you just setup
step 37:

Click on Define simple record

Click on **Define simple record**
step 38:

Click on Define simple record to define the AAAA record

Click on **Define simple record** to define the `AAAA` record
step 39:

Use all of the same settings from before, but select AAAA as the record type

Use all of the same settings from before, but select `AAAA` as the record type
step 40:

Click on Define simple record

Click on **Define simple record**
step 41:

Click on Create records to create the two records

Click on **Create records** to create the two records

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.

step 42:

Navigate back over to CloudFront and select your CloudFront distribution

Navigate back over to CloudFront and select your CloudFront distribution
step 43:

Click on Error pages

Click on Error pages
step 44:

Click on Create custom error response

Click on **Create custom error response**
step 45:

Select 403: Forbidden

That's the error we're going to customize

Select **403: Forbidden**   That's the error we're going to customize
step 46:

Select Yes, enter /index.html as the page path, and 200 as the status code

Then select Create custom error response

Select **Yes**, enter `/index.html` as the page path, and 200 as the status code   Then select **...

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:

  1. Update the files in the S3 bucket

  2. 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.

step 47:

In CloudFront, click on Invalidations

In CloudFront, click on **Invalidations**
step 48:

Click on Create invalidation

Click on **Create invalidation**
step 49:

Specify any files you've updated, or input /* for all files

Specify any files you've updated, or input `/*` for all files
step 50:

Click on Create invalidation

Click on **Create invalidation**

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 '/*'