Serverless - Host a website using S3, CloudFront and CloudFlare
This is a tutorial on how to host a static website on AWS while paying less than 5 USD per month for resources.
To prove that this is working as intended, we're going to use as reference this exact website.
What is Serverless?
Serverless computing is a cloud computing execution model in which the cloud provider has the role of dynamically allocating machine resources to fulfill the client's needs.
Although it is true, yes, that they DO utilize compute power, the capacity planning decisions and resource utilization are completely hidden from the developer.
So, in this case, pricing is actually based on the actual amount of resources used only by the application itself, instead of locking your budget on a full fleet of servers. This is also known as a form of utility computing.
Who else is doing this?
The best example of resource utilization and low-budget cost is provided by ACloud Guru, which is a social learning platform based on micro-services and serverless architecture, able to deliver thousands of online trainings per month whilst staying under a 20 USD/month budget for their entire infrastructure.
We're also using the same methodologies for our website, but since we don't deliver video content to our users, our configuration is a bit more easier to replicate.
Thus, this tutorial is specifically dedicated to all companies out there who are using a static HTML website to present their brand to prospect customers. If you follow this tutorial closely, you will be delivering your website with under 5 USD/month, while also benefiting from:
- Free SSL termination
- Free HSTS set-up
- Automatic HTTPS Rewrites
- Firewall and Access Rules
- DNS Obfuscation
- Auto-Minify JS,CSS and HTML
- Auto-Enable AMP links
- 3-Layer caching level - 1 provided by CloudFlare, the other 2 provided by AWS
- On the fly Browser Cache Expiration
- HTTP URL Rewrite
- HTTP/2 Acceleration
- World-Wide Edge caching - through AWS CloudFront
- CI/CD deployment pipeline - using Jenkins and AWS S3
About the stack
In order to store the HTML code for our website and the adjacent resources (JS,CSS,images), we'll be using an S3 bucket. Although it's primary utilization is to store a huge amount of data through an Object-Based storage mechanism, it is also a powerful utility that can help you host a static website on it.
Hosting the website won't be enough though. We need to also make sure that all users, irelevant of their location around the globe, will be able to access it in less than 3 seconds, as per Google's requirements.
In order to that, we're going to make use of the Global Edge Caching service offered by AWS, specifically Amazon CloudFront. 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. If the content is already in the edge location with the lowest latency, CloudFront delivers it immediately. If the content is not in that edge location, CloudFront retrieves it from an Amazon S3 bucket or an HTTP server (for example, a web server) that you have identified as the source for the definitive version of your content.
SSL termination and other goodies
This is where CloudFlare comes in. Cloudflare speeds up and protects millions of websites, APIs, SaaS services, and other properties connected to the Internet. Their Anycast technology enables them to scale with every server they add to their growing footprint of data centers. Best of all, for what we're going to deploy, it's absolutely free.
STEP 1 : Setting up the S3 bucket
Assuming that you already have an AWS account setup, then all you have to do is:
- Access the AWS console and browse to the S3 service
- Click on "Create bucket"
- Give it a name, select a region and click on Next
- Hit "Next" on the "Set Properties" screen
- Hit "Next" on the "Set Permissions" screen
- Click on "Create bucket"
- Click on the bucket that you just created and go to the "Properties" tab
- Click on the "Static Website Hosting" card and select "Use this bucket to host a website"
- Input "index.html" and "error.html" in the respective "Index document" and "Error document" fields
- Hit "save"
- Go to the "Permissions" tab, select the "Bucket Policy" sub-tab, and paste this policy after updating the S3 bucket name:
That's it. To make sure that you've set this up just right, upload a sample file (with the name "index.html" to the bucket and access the endpoint.
You'll find the endpoint URL generated in the "Static Website Hosting" card, but if you're to lazy to go there again, you can "guess" it by following this algorithm:
In our case, it's http://netbears-serverless-website.s3-website-us-east-1.amazonaws.com.
STEP 2 : Setting up the AWS CloudFront cache
Assuming that your S3 bucket is up and accessible through the HTTP endpoint, then let's move to setting up the CDN:
- Access the AWS console and browse to the CloudFront service
- Click on the "Get Started" button under the "Web" tooltip
- In the "Origin Domain Name" field, input your bucket endpoint (without "http://"). In our case, it's -> netbears-serverless-website.s3-website-us-east-1.amazonaws.com
- In the "Origin ID" field, leave the generated ID by AWS or create a new one, per your own choosing
- In the "Alternate Domain Names (CNAMEs)" field, input your domain name -> It would be better to input both expected web URLs (www and non-www)
- Leave everything else with default options and click on "Create Distribution"
The process of creating an AWS CloudFront distribution usually takes around 30 minutes, but when it finishes, you'll be able to access your distribution using the URL generated under the "Domain Name" column field.
STEP 3 : Setting up CloudFlare
Now that you have your CloudFront distribution up and running, all we need to do now is just register it with CloudFlare.
After you initially sign up on their website, you will be given a tutorial on how to change your DNS NameServer records.
Don't worry, this doesn't mean that you change your registrar, it just means that, from this point on, CloudFlare will be the sole-responsible of handling all DNS requests made against your domain. And they have an army of servers to do that while also making sure that you never get DDoS'ed -> https://www.cloudflare.com/ddos/
For those of you who don't know or don't remember, here's a nice an explanation and what is one while also talking about the biggest DDoS attack in the history of GitHub.
After you made sure that your nameservers point to CloudFlare, it's time to set it up. Each of the following subtitles refers to the top-level tab in the CloudFlare dashboard.
First you need to add your CloudFront endpoint in the DNS records list. For that, create a CNAME record for both "@" and "www" Name and click on "Add Record" (while making sure that the orange cloud is visible).
This will ensure that all requests go through the CloudFlare network so that they are sanitized and that you benefit from all other improvements that we're going to add.
Now, let's also secure your DNS zone against DNS poisoning. To do that, simply scroll down and click on "Enable DNSSEC" and follow the instructions.
Make sure that the SSL is set up to "Full (strict)". This ensures that all communication between user <> CloudFlare <> AWS is highly secured using latest certs.
Let's not leave the choice of using SSL/non-SSL to our users and scroll down to "Always use HTTPS" and make sure it's on. This ensure that all HTTP requests are automatically redirected to HTTPS. While we're here, it would be best if we also enable "Automatic HTTPS Rewrites", just to be sure.
To gain some latency, we're going to also switch on HSTS. Be careful though! This will not only ensure that all users will automatically use HTTPS when connecting to your website, but ALL EXISTING AND FUTURE websites and applications hosted under this domain, will automatically use HTTPS. So, think if through please. If you're not 100% sure that you'll be able to support this, then don't activate it. There is a deactivation process in place of course, but it takes around 3-6 months to accomplish it!
Now, for my favorite feature -> CloudFlare's speed adjustments.
CloudFlare also let's you enable AMP pages. The AMP project has been developed by Google and offers you the possibility to deliver high-speed content to your users by making use of their own CDN and delivery systems, thus, no traffic will be sent to your website, but your users will still be able to view your content. This works perfectly if you have a blog running on your company website, like us -> netbears.com/blog.
This page offers us some cool features, which not only increases website delivery for your visitors, but will also help you a bit with your Google's ranking mechanism.
First, let's make sure that we also use CloudFlare's caching mechanism by setting the "Caching Level" as "Ignore Query String".
Next, by setting up the "Browser Cache Expiration" to "8 days", we'll make sure that content is also served from the visitor's browser cache, instead of doing a round-trip to our systems.
Lastly, if setting up all those settings in the "Crypto" tab wasn't enough, we're going to create 3 more page rules, to not only show you how they work, but also to ensure that your visitors will always use HTTPS. This is our current config which ensures just that:
If you followed our tutorial closely, then you'll not only notice a huge increase of speed, but also a better performance on Google's PageSpeed Insights:
I mean, I don't know about you guys, but an 89 score without changing literally anything in the code, is awesome isn't it?
Awesome, but does it scale?!
Of course it does!
In this stress test, we've sent 5000 users over a period of 1 minute to our DevOps page, and all requests were handled in less than 1 second, with an average response time of 48 ms!
About that budget again...
Yes, I'm sure you don't believe us that it's that cheap...
So why don't we show you the invoice instead then ?
Need help implementing this?
Feel free to contact us using this form.