Static Website Hosting on Amazon S3 with CloudFront and Route 53
I’m going to build a static website for an upcoming personal project I have in mind. S3 is perfectly suited for hosting highly available static websites at low cost. The drawback for using S3 as a hosting platform is that the S3 bucket website URLs do not look very professional for your website visitors and only support un-secure http connections. I have already purchased a domain name in from Route 53 to associate with my S3 hosted static website and have decided to use AWS CloudFront to support secure https connections to the S3 website endpoint.
The scope of this exercise is therefore to create an S3 bucket for the static website content, configure the bucket as a static website, create a CloudFront distribution that serves the website content and associate the distribution with my purchased domain name in Route 53. After completion, when end users enter my-domain.com in their browser, the index.html page that is hosted in S3 is served from CloudFront’s distribution network in the browser window.
That all sounded straightforward enough and as somebody who has recently passed the AWS Solutions Architect Associate exam I thought I should be able to execute this quite simply. However, I kept getting tripped up in places and wasn’t able to complete it all on my first few attempts. I usually find the AWS documentation very good and thorough but in this instance I couldn’t quite connect all the dots for this particular work flow. You only really learn by doing so after quite a bit of perseverance and trial and error I successfully completed all of the tasks. To make sure I’d really learned how to do this, I tore it all down and rebuilt the solution again, this time documenting all of the steps required.
Here is the process I followed to build this solution. Hopefully you are able to follow along if you have the same requirements for hosting a static website. I’ve highlighted the banana skins that slipped me up when first building this solution so you can avoid these pitfalls. Thanks to @Jack Lavelle for encouraging me to write.
Stage 1 - Create, Host and Test Your Static Website on S3
Create an S3 bucket and upload the index.html document and other associated files.
Select the bucket and edit Permissions to uncheck “Block all public access”
Save changes. If you try to edit the bucket policy before saving changes at this stage you will receive an API error stating that you do not have permissions to change the bucket policy.
Go back to the Permissions tab and edit the bucket policy to make the bucket contents publicly accessible. I generally use the policy editor for this.
Select the Properties tab for your bucket and enable Static Website Hosting for your bucket and minimally specify the index document for your static website i.e. index.html
From the Properties tab copy your bucket website endpoint from the bottom of the page and paste the address into a new browser window to check your index.html file is now accessible from the web e.g.
http://YOURBUCKETNAME.s3-website.eu-west-2.amazonaws.com
You should now have a working static website hosted on S3.
As mentioned earlier, websites hosted on S3 do not support secure HTTPS connections, only HTTP. This can reduce user confidence that your S3 website is a genuine site. So, let’s create a CloudFront distribution for your static website which does support HTTPS connections. As CloudFront is AWS’s Content Delivery Network, user latency should be reduced and your site should load faster to end users all over the world.
Stage 2 - Create a CloudFront Distribution To Serve Your Static Website Content
Navigate to CloudFront and select “Create Distribution” in the AWS console.
Select your S3 bucket from the drop down list in the Origin Domain Field.
Note – If you paste your bucket website endpoint into this field e.g. http://YOURBUCKETNAME.s3-website.eu-west-2.amazonaws.com instead of selecting from the drop down list your distribution will still work but you will not get the option of using an OAI (Origin Access Identity) which we will use later. The Origin names in the drop down list refer to the REST API endpoint for your bucket and are required to control bucket access with an OAI.
Scroll down to “Default cache behaviour” section choose “Redirect HTTP to HTTPS” under “Viewer protocol policy”
Scroll down to “Settings”
Change Price Class to “Use only North America and Europe”. This is to reduce costs as this blog is for testing and demonstration purposes. You may wish to choose “Use all edge locations (best performance)” for your production workloads.
Enter index.html in the “Default root object” field. If you miss this step your CloudFront distribution will return an AccessDenied error when called by your browser.
Click “Create Distribution”. It will take around 10 minutes for the distribution in this price class to fully deploy.
Once created and deployed, select your distribution from the console, copy the “Distribution domain name” (DNS) and paste it into another browser window. If you have completed all the steps above you should see your index.html website page displayed just as when you entered the bucket website endpoint URL, but now you will notice your browser has established a secure https connection.
Stage 3 - Create an OAI and Disable Direct Bucket Access
At this point our end user browsers are able to access our static website either with the DNS name of our CloudFront distribution or via the S3 bucket website endpoint. It is generally best practice if using CloudFront to secure your bucket so that your static website can only be accessed by end users via CloudFront. This is achieved by using an OAI (Origin Access Identity) which is a specially created CloudFront user and then editing the website bucket policy so that only the OAI (and therefore CloudFront) can access our website bucket.
At this point it is advisable to go back to you S3 bucket, edit the bucket policy and delete the entire policy. Remember to click “Save changes” after deleting the bucket policy. Experience has demonstrated that this is the simplest way for the OAI wizard to create all the necessary settings for your new bucket policy in the next step. At this point you will lose access to your static website via the bucket website endpoint but this is what we want to achieve anyway. If you try and use your bucket website URL in your browser after deleting your bucket policy e.g. http://YOURBUCKETNAME.s3-website.eu-west-2.amazonaws.com a Forbidden 403 error will be returned.
Select your CloudFront distribution from the console, choose the Origins tab, select the checkbox next to your Origin name and select Edit. This will open the “Edit origin” window.
Under “S3 bucket access” select “Yes, use OAI”. Select “Create new OAI” and assign the OAI a name e.g. “mywebsitebucketoai” and select “Yes, update the bucket policy” This will update your S3 bucket policy so that the OAI associated with this distribution can access your website. Select “Save changes”
Recommended by LinkedIn
If you return to your S3 bucket and examine the bucket policy now, you will find that CloudFront has modified the bucket policy to look similar to this :
The bucket policy has changed from allowing everyone (*) to only the OAI identity to access files in your website bucket.
Once the revised distribution has completed deployment the only way to access your static website is via your CloudFront distribution DNS name e.g. https://d3m5ztnkwwg8pz.cloudfront.net/
Would you agree that this URL is even less user friendly than our S3 website endpoint? Let’s fix this.
So far we have hosted our static website in S3 and ensured the only way to connect to it is via our CloudFront distribution. The DNS names created by CloudFront are not particularly memorable or user friendly. Ideally, we should associate this distribution with a Route 53 hosted custom domain name that we own.
Stage 4 - Accessing Your Website With a Friendly Domain Name
The domain aws-demo.co.uk was purchased by me from Route 53 for use with projects and demonstrations like this.
In order to use your CloudFront distribution with your Route 53 hosted domain name you will need a certificate for your domain issued by AWS Certificate Manager. This certificate needs to be created in us-east-1 (N. Virginia) or you will not be able to complete this section.
Go to Certificate Manager in the AWS console and change to us-east-1 region.
Select “Request a certificate” and choose “Request a public certificate” from the options.
In the next screen, add the domain names your users are likely to use to navigate to your static website e.g. yourdomain.com, www.yourdomain.com. Click “Next”
Select DNS validation from the next screen as it saves navigating away from the AWS console. Click “Next”
Add a Name tag to your certificate and click “Review” and then click “Confirm and request”
Click the triangle next to each domain name where the status is listed as Pending Validation and select “Create record in Route 53” and then select “Continue”.
If you check the records in the hosted zone for this domain in Route 53 you will see that CNAME records have been created for you to validate your certificate. The status of your certificate will change to “Issued” within a minute.
Navigate back to CloudFront and select your distribution. In the General tab click the Edit button for Settings.
Click the Add Item button and enter the domain names that you associated with your certificate in the previous step.
Select your newly issued certificate from the drop down list in the Custom SSL Certificate field. If you did not create your certificate in the us-east-1 region you will not be able to Save Changes for this step.
Click the “Save Changes” button.
Once this revised distribution is deployed the final step is to create alias records for your domain hosted in Route 53 to point to this CloudFront distribution.
Navigate to Route 53 and select the hosted zone for the domain that you wish to associate with the distribution.
Select “Create record” and create an A type Alias record for each domain record for your website e.g. yourdomain.com and www.yourdomain.com. If you did not complete all of the previous steps then your distribution will not be available for selection in the drop down box under “Alias to CloudFront distribution”
Click “Create records”
Within minutes you will now be able to access your static website via the custom domain name you configured in Route 53 e.g. aws-demo.co.uk as well as the CloudFront distribution domain name you created earlier.
I hope you were successful. As a challenge see if you can create the distribution successfully with the OAI and alternate domain names in one go. Tip – Create your certificate for your Route 53 domain first before creating your CloudFront Distribution.
Great work
nice one David...keep it up
Amazing
This is really a good article David.
Awesome job David, congrats on your first article.