Self-hosting Secured Static Web Site using S3, Route 53, ACM, CloudFront
Tags: staticwebsite, s3, aws, cloudfront
Published: 2020-07-25 10:43:14

Long time wish of building a personal website & self hosting with custom domain, all happened over two weekends. 
Here you go with steps followed in the making of [https://bhuvana.pro](https://bhuvana.pro) after developing the static website. 
The entire blog is detailed out with three stages. You can stop at any stage but still have working website with custom domain.
1. Stage 1 - Static Website hosted on routed with Route 53
2. Stage 2 - Static Website hosted on S3 routed with Route 53 & CloudFront with ACM for SSL
3. Stage 3 - Stage 2 + CI CD for deploying static website

### Table of Contents
* [AWS Services Used](#awsservices)
* [Best Practise](#bestpractise)
* [Highlevel Steps Involved](#highlevel)
  * [Stage 1](#stage1)
  * [Stage 2](#stage2)
  * [Stage 3](#stage3)
* [Pricing](#pricing)
* [Reference Links](reflinks)

### AWS Services Used <a name="awsservices"></a>
* S3
* Route 53 
* Amazon Certificate Manager
* CloudFront
* AWS CodeCommit
* AWS CodeDeploy
* AWS CodePipeline

### Best Practise <a name="bestpractise"></a>
* Ensure to tag all the resources that you create.
  * S3 root domain & logging bucket
  * CloudFront Distribution
  * Route 53 - Hosted Zone
  * ACM - public certificate 
* I have created two tags (Name: Bhuvana.pro and Usage: website), which will help for resource grouping and cost analysis.
* To standardize example.com and www.example.com is used as root and subdomain throughout this article

### Highlevel Steps Involved <a name="highlevel"></a>
![In the making of https://bhuvana.pro](https://dev-to-uploads.s3.amazonaws.com/i/hpe0nv9htocl9igbgdlj.png)

### Detailed Implementation Instructions
#### Stage 1 <a name="stage1"></a>
We will be implementing Static Website on S3 routing to Custom domain (example.com) using Route 53 where Custom domain is registered with GoDaddy.com. This will be implemented from Steps 1 to 9. 
![Static Website hosted on S3 with Route 53
](https://dev-to-uploads.s3.amazonaws.com/i/oakg9qynks5d6c6ovjqi.png)

##### Step 1:
Amazon Route 53 is a highly available and scalable Domain Name System (DNS) web service. You can use Route 53 to perform three main functions in any combination: domain registration, DNS routing, and health checking. In our tutorial, we will be using Route 53 for DNS routing with an external site for domain registration. Read [here](https://docs.aws.amazon.com/route53/index.html) for more details on Route 53

Register your favorite domain based on availability.  I registered with GoDaddy just to integrate the external domain with Route 53; otherwise registering a domain with Route 53 will automatically create a hosted zone for you.

##### Step 2:
Amazon Simple Storage Service (Amazon S3) is storage for the internet and static website hosting functionality helps you to host a static website on S3 bucket without the need to provision and manage servers to meet the scale. Read [here](https://docs.aws.amazon.com/s3/index.html) for more details on how to use S3.

Create an S3 bucket for the root domain (say example.com) and upload the content for your static website
![Setup Static Website on S3](https://dev-to-uploads.s3.amazonaws.com/i/50sdoth7o8h03yjocm78.png)

##### Step 3:
Create an S3 bucket for the subdomain and configure that to redirect to the domain bucket
![Website Redirection](https://dev-to-uploads.s3.amazonaws.com/i/9bhveaf9k24fhrw37crt.png)

##### Step 4:
Create a hosted zone in Route 53 for the registered domain name and copy the NS Record server details to update in GoDaddy.com
If you have registered the domain with Route 53, this is handled automatically by AWS.
![Hosted Zone setup](https://dev-to-uploads.s3.amazonaws.com/i/fakqjfbscbrhoxsax07z.png)

##### Step 5:
Add the NameServers in GoDaddy.com.
Remember to exclude the trailing dot while copying the server names.
![Update NameServers](https://dev-to-uploads.s3.amazonaws.com/i/pbe4byt9fzux9ss3b4v6.png)

##### Step 6:

Now that you have created two S3 buckets for hosting and redirecting, let's check if it's working by copying the endpoints of S3 buckets to the browser. Yes, the Website is up with S3!
![Testing](https://dev-to-uploads.s3.amazonaws.com/i/cij13mrckjsovd0js36r.png)

##### Step 7:
It's time to route the domain/subdomain to access the website hosted in S3. You will have to create two recordsets under the hosted zone pointing to the S3 buckets example.com and www.example.com
![Routing](https://dev-to-uploads.s3.amazonaws.com/i/4xmzhlrw9inxxmgmm2ac.png)

##### Step 8:
To watch the website traffic, you can enable logging on the root domain s3 bucket and store that logs in logs.example.com under prefix **logs/**
![Enable Logging](https://dev-to-uploads.s3.amazonaws.com/i/9v1i6beh43lhexftcfqu.png)

##### Step 9:
Test the websites with root domain and subdomain as follows
![Testing](https://dev-to-uploads.s3.amazonaws.com/i/rec8h6i7jv3jabxmbo28.png)

#### Stage 2: <a name="stage2"></a>
We have the website up & running, but how secured it is? Good to have SSL integration. But S3 does not support SSL Integration, hence let's use Amazon CloudFront to deliver the static website from S3 secured with a public certificate created from Amazon Certificate Manager (ACM).
![Static Website hosted on S3 with Route 53 with CDN
](https://dev-to-uploads.s3.amazonaws.com/i/y6u10c00a6fduj4y6aha.png)

##### Step 10:
Amazon Certificate Manager helps you to easily provision, manage & deploy public and private SSL certificates. Read [here](https://aws.amazon.com/certificate-manager/) for more details.

**Important note:** You should create the SSL only in N.Virginia region for usage with ACM. 
![Your certificate](https://dev-to-uploads.s3.amazonaws.com/i/v449nyayy6id4v2nqebc.png)

##### Step 11:
Amazon CloudFront is a web service that speeds up the distribution of your static and dynamic web content, such as .html, .css, .js, and image files, to your users. CloudFront delivers your content through a worldwide network of data centers called edge locations. When a user requests content that you're serving with CloudFront, the user is routed to the edge location that provides the lowest latency (time delay), so that content is delivered with the best possible performance. Read [here](https://docs.aws.amazon.com/cloudfront/index.html) for more details on CloudFront.

Let's create a Web distribution in Amazon CloudFront to act as a CDN for our static website hosting
![CloudFront WebDistribution](https://dev-to-uploads.s3.amazonaws.com/i/nee0nkbcrzz3q2cr8k2t.png)

##### Step 12:
In Step 7, we routed the domain / sub domain to access the website hosted in S3. delete those record sets and create two new record sets to point to the CloudFront domain.
If ipv6 is turned on for the CloudFront web distribution, create two more recordsets.
![Routing to CloudFront](https://dev-to-uploads.s3.amazonaws.com/i/bx9bsrq8l09jui7gsq63.png)

##### Step 13:
Your website is up & running with SSL Integration
![Website is up](https://dev-to-uploads.s3.amazonaws.com/i/z93jxfqoy04e2p4pw4lu.png)

##### Step 14:
Well, now your website can be browsed via S3 endpoint without SSL & via root domain & subdomains with SSL.

That isn't enough. Further, why should users access S3 content directly when we have SSL integration for your domain in place?

Let's go in for Origin Access Identity to restrict access to content that you serve from Amazon S3 buckets and here are the steps:
Create a special CloudFront user called an origin access identity (OAI) within the CloudFront console and associate it with your distribution.

Configure your S3 bucket permissions so that CloudFront can use the OAI to access the files in your bucket and serve them to your users. Make sure that users can’t use a direct URL to the S3 bucket to access a file there.

After you take these steps, users can only access your files through CloudFront, not directly from the S3 bucket.

Click [here](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html) to read more about OAI and follow the below instructions to setup

![OAI Integration](https://dev-to-uploads.s3.amazonaws.com/i/lpkgymkaisf26ayrc61n.png)

##### Step 15:
Try accessing the content via S3 endpoint.. Hope you are getting **403 Forbidden** ?
First time you can be happy about getting Access Denied Error. Hurray!!

Now your website should be only accessible via your root domain and subdomain delivered through CloudFront distribution.

Hearty Congratulations for successfully setting up your secured static website along with me.

#### Stage 3: <a name="stage3"></a>
As a DevOps person, implementation is incomplete without a source control repository for versioning to the website changes and seamlessly integrating the changes to the S3 bucket through a DevOps pipeline, and here is the architecture. 

![Static Website hosted on S3 with Route 53 with CDN + DevOps Pipeline](https://dev-to-uploads.s3.amazonaws.com/i/ea4lowy9nbt35wiunjc8.png)


### Pricing
If you wanted to explore how much is your expenditure on the monthly basis, go to My Billing Dashboard to Activate Cost Allocation Tags for Name & Usage that we have created for all resources. Activating tags for cost allocation tells AWS that the associated cost data for these tags should be made available throughout the billing data pipeline. Once activated, cost allocation tags can be used as a filtering and grouping dimension in AWS Cost Explorer, as a filtering dimension in AWS Budgets, and as a dedicated column in the AWS Cost & Usage Report.


### Reference Links
[Static Website hosting with Custom Domain](https://docs.aws.amazon.com/AmazonS3/latest/dev/website-hosting-custom-domain-walkthrough.html)
[Configuring SSL Certificate to CloudFront Distribution](https://aws.amazon.com/premiumsupport/knowledge-center/install-ssl-cloudfront/)
[Routing to CloudFrond Distribution](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-to-cloudfront-distribution.html)
[Restricting Access to S3 Content via Origin Access Identity](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html)