Deploying a Secure Static Site to AWS with S3, Route 53 and CloudFront
Tags: aws, webdev, beginners, tutorial
Published: 2022-02-12 22:26:00

There probably hasn't been a better time to host static websites than today. As a developer, you can use some excellent free services such as [Netlify](https://www.netlify.com/), [Github](https://github.com/), and [Firebase](https://firebase.google.com/). 

Hosting a static site in the cloud with companies such as [AWS](https://aws.amazon.com/), [Heroku](https://www.heroku.com/), and [DigitalOcean](https://www.digitalocean.com/) can be done at a low cost as well.

Being most familiar with AWS, this is the route I have chosen for a client. These instructions will likely be outdated within a year but should offer some guidance for anyone trying to create a static site that takes advantage of the features and services provided by AWS.

## AWS

There are several economic reasons for using AWS to host a static site. AWS provides developers with a free tier for many of their services. Bandwidth and storage costs are low because of the large scale of AWS. AWS can help us manage our custom domain with certificate management, hosted zones, and a content delivery network.

My intention is to provide guidance through this process of setting up and hosting an HTTPS-enabled static website using AWS services with a custom domain. I use [Namecheap](https://www.namecheap.com/) for domain name registrations, but these instructions can be applied with other registrar services.

There are a few assumptions that will be made for this guide. 

1. You have an AWS account or can create an account before starting the guide.
2. You have a custom domain registered and access to modify nameserver.
3. You have about thirty minutes to complete this guide.

Here are the four services we will be using with our static website project.

1. [AWS Certificate Manager](https://console.aws.amazon.com/acm/) or ACM. We can generate an SSL certificate for our custom domain name with this service and set up HTTPS for our site.
2. [Simple Storage Service](https://s3.console.aws.amazon.com/s3/) or S3. As the name suggests, we can upload our static content to a **bucket**, and serve the files to website visitors.
3. [CloudFront](https://console.aws.amazon.com/cloudfront/v3/). This is the AWS content delivery network. The service distributes static content to nodes around the globe. This service improves the user experience for worldwide traffic. CloudFront will add a small cost to our hosting fees but provide free SSL termination for HTTPS.
4. [Route 53](https://console.aws.amazon.com/route53/v2/) is the service to manage our DNS records. This service integrates our custom domain from NameCheap to our CloudFront distribution.

## Route Traffic From Our Custom Domain to Route53 

1. Log into your AWS account and open the Route 53 dashboard. In the left navigation, select the **Hosted Zone** link. Once the **Hosted Zone** page loads, find and click the **Create hosted zone** button.
2. Add your Domain name and a description of the hosted zone record. Leave the default type **Public hosted zone** selected. Add any tags you would like and click the **Create hosted zone** button.
![Create hosted zone](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fgyc6hq5derv3kjrtap6.png)
3. Once your hosted zone is created, select the hosted zone and click the **View details** button.
4. Expand the **Hosted zone details** and take note of the name server records. We will need to use these for our custom domain.
![View hosted zone](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mmduii00vlvhv0431slm.png)
5. Open a new browser tab and use that to log into your custom domain registrar. Navigate to manage the domain nameservers. For Namecheap navigate to a list of our domains and then click the **Manage** button. Scroll down to the name server section and change the selected name server from _Namecheap BasicDNS_ to _Custom DNS_. Under the selection, you can now enter the name server records from step 4. Depending on the registrar, the propagation time of these changes can vary. In my experience, the propagation only takes a few minutes, but it can be several hours for some.
![Custom domain name server](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kyy72qy4ecnglghrjwk1.png)

## Generating an SSL certificate

1. Open a new browser tab and navigate to the ACM service. Click on the **Request a certificate** button. If viewing the certificate list, click on the **Request** button.
2. Under _Certificate Type_, verify the default **Request a public certificate** is selected and click the **Next** button.
![Request certificate](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wfhpd7uk1xiwdubi48og.png)
3. Add all fully qualified names you plan to use in the Domain section. Keep the default selected DNS validation under the Select validation method. Add any tags (optional) and then click the **Request** button. 
![Request public certificate](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gl9nhdxmmmawmgicwbeh.png)

Generation of the certificates will take some time. Once the certificate generates, click on the Certificate ID link to view the certificate. Scroll to the Domains section and take note of the CNAME records. These records will need to be added to the Route 53 hosted zone. 
![Certificate domain record](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wq587cf3uloi7ytks7m1.png)

## Connect Certificates to Hosted Zone

1. Open the Route 53 hosted zone tab and click on the domain name link to access the records. Scroll down to the **Records** section and click on the **Create record** button.
2. If there is a subdomain record, add that prefix to the _Record name_. If this is the root domain, leave the field empty. Change _Record Type_ to CNAME. Paste the _CNAME value_ from the certificate record into the Value field. 
![Create zone record](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3lz4dshixomvwidmb1jr.png)
3. If you have more than one record, click the **Add another record** button and repeat the step 2 instructions for each record. Once completed, click the **Create records** button.

_Note: We will need to confirm that the certificate has been associated with the hosted records later._

## Create an S3 bucket for Static Hosting

1. Navigate to AWS S3 and click on the **Create bucket** button.
2. S3 buckets are global, so you will need to use a unique bucket name. Use your domain name as your _Bucket Name_. Scroll down and uncheck the **Block _all_ public access** box under the **Block Public Access settings for this bucket** section. Scroll to the bottom and select the **Create bucket** button.
![S3 bucket create](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yfi8c8009ywah8r3uqcc.jpg)
3. After the bucket has been created, navigate to the **Permissions** tab of the bucket and scroll down to the **Bucket policy** section. Click the Edit button and create a bucket policy to allow public read access to the bucket.
```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "MySiteGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::example.com/*"
        }
    ]
}
```
4. Within the bucket select the **Properties** tab. Scroll down to the **Static web hosting** section (at the bottom of the page) and click the **Edit** button.
5. Select _Enable_ under **Static website hosting** and _Host a static website_ under **Hosting type**. Add the static sites Index document (index.html for most) and then click the **Save changes** button. 
![S3 edit static website](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jctqdtp4wc523ni5tyog.png)
6. After saving, we should have a URL for the static website provided by S3 (example: http://example.com.s3-website-us-east-1.amazonaws.com). Take note or copy this URL as we will need this to create our CloudFront distribution. 
7. Upload all of your static website files to the S3 bucket. You should be able to verify your site using the link provided in step 5.

## Create CloudFront Distribution

Before we start this process, we will want to make sure our SSL certificate has been successfully connected to the hosted zone. Navigate back to the ACM and wait/refresh until the Status shows success. 
![Issued status](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eqr50ut4vk23lcpngyyz.png)

1. Go to the CloudFront dashboard and click the **Create Distribution** button.
2. In the Origin domain field paste in the S3 static website URL from step 5 of creating an S3 bucket. The Name section should populate with the bucket name (example: example.s3-website-us-east-1.amazonaws.com).
3. Scroll down to **Default cache behavior** section and select _Redirect HTTP to HTTPS_ under **Viewer protocol policy**.
4. Scroll to Settings and be sure to select the price class that is best for your website. If your static hosted site is intended for use in the US only, select _Use only North America and Europe_ for example.
5. Click the **Add item** button under the _Alternate domain name (CNAME)_ heading and add each one of your domains. 
![CloudFront settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i3ky1doq5mmj2r5xzp32.png)
6. Within the selector for **Custom SSL certificate**, choose the SSL certificate for our custom domain.
7. Scroll to the bottom and click the **Create distribution** button.

The CloudFront distribution will take several minutes to generate. Once the distribution is completed, you should be able to access your website using the secure custom domain.

After making updates to your site and uploading the changes to your S3 bucket, you will want to look at creating an invalidation with the CloudFront distribution.

## Some Pro Tips for AWS

Within your AWS account, make sure you view your billing dashboard. Within the billing dashboard, you can create a budget. Be sure to use this and create a budget that is acceptable for your use. This can save you from spending more money than you expect in a monthly billing period.

Within CloudWatch, set up a billing alarm for your AWS spending. This can alert you of any unexpected services that you may have left running.

Take advantage of AWS SDK written in your preferred development language for automating deployments and creating invalidations for your CloudFront distributions.

## Conclusion

While the tutorial was not as detailed as I initially intended, it is my hope that the tutorial is enough to make your static website public to users. Please take some time to implement the pro tips above and spend some time learning more about the four AWS services we have discussed.

If you have found this tutorial useful and would like to connect, follow me on [twitter](https://twitter.com/albawebstudio). 

Best of luck and cheers!

Cover image by [Caspar Camille Rubin](https://unsplash.com/@casparrubin?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)