Hosting your entire web application using S3 and CloudFront

語言: CN / TW / HK

There are several ways to host an application on the internet, but the one that I am most familiar with is to use a web server such as Apache or NGINX where you can host all the static components of your application and also use it as a reverse proxy server to direct API calls.

But recently I came across another way to host a web application which is more elegant, cost effective and has no need for maintenance. This method makes use of AWS S3 and AWS Cloudfront and it’s turned out to be significantly easier to set up, scales infinitely and is cheaper than the alternative.

Why did we need S3 to host a web application?

The product that I have built is currently architected in this way - we use an open source version of Nginx that is hosted on an AWS VPS instance which takes care of hosting our static files for our web app and also works as a reverse proxy server to send API calls to our backend applications.

This setup worked great so far because we have a limited number of users that need access to the application dashboard and there is no need for a CDN either because the users, especially the ones on a paid plan do not have any problem waiting a couple of seconds more for the website to load.

This requirement changed when there was a new feature requirement within our product. Our users are e-commerce merchants and most of them accept “Cash on delivery” as an option while accepting orders and this leaves a lot of room for fraud to occur where somebody places an order and selects the payment method as “Cash on delivery” without the intention to actually buy the product.

In order to fix this we introduced a feature where the customer who places a COD order gets an automated message on WhatsApp to confirm their order via a link.

Automated WhatsApp message to confirm a COD order

Clicking on this link would open this web page

Reactjs web app used to confirm a COD order

Now this web page would be accessed by the customers that buy from the merchants that use our application, so the traffic to this page could be very erratic, not to mention the fact that it would come from various parts of the world where the users internet connection would also be erratic and vary according to the region.

Therefore it did not make sense to host this web page the way the rest of our application is hosted. This web app had the following requirements

  • High availability from any part of the world
  • Fast load time
  • Ability to handle any amount of traffic
  • Not having the need to manage or monitor

It turns out that all of these things can be achieved if you host the app using a combination of S3 and CloudFront which is the CDN offered by AWS.

How to host an application on s3

There is a comprehensive guide in the AWS documentation on how to do this - link to documentation

The TL:DR for this is to Create an s3 bucket with the same name as the domain/subdomain where you want to host your web app.

For instance, our web page had to be hosted on cod.superlemon.xyz , so this is what the s3 bucket would be called. After this there are a bunch of properties and settings that you would have to change on the bucket which are mentioned in the doc. 

Once this is done, you can test whether it worked or not by using either of the below links based on the region where you are hosted

End points for verifying if the s3 hosting worked or not

Though the steps in the AWS doc are quite comprehensive, there is one gotcha here that you must keep in mind. If your web app runs on a framework like react which is what we are using, you must make sure that under the “static website hosting” settings of the AWS bucket, you set the index document as well as error document as index.html.

S3 static web hosting settings

This is to ensure that if you have any URL routes set up in your react application, those routes are honoured.

How to put the s3 application behind a CDN

The above step only completes one step of the process where your application is now residing in s3. But the process is only complete if the application is accessible as a CDN. For this you would have to use CloudFront and configure it to use your s3 bucket as the source. A comprehensive documentation for this process is given here

There are a few gotchas here as well. The first one being that you will require an SSL certificate to host your application as https:// . You can get an SSL certificate easily using AWS Certificate manager . This process becomes even more easy if you are using Route53 to manage your domains and subdomains. Even if you use another provider like Godaddy or Bigrock for your domains, I would highly recommend following these steps to plug in your domains to Route53. 

The other gotcha here is once again something to do with reactjs URL routing. If you are using this in your application, there is another step that you have to follow. Under your CloudFront distribution, you must navigate to error pages and create a new custom error response as follows

CloudFront distribution error pages settings
CloudFront distribution handling 403 error

This will ensure that if the CDN is not able to find the URL path you specify, it will default to index.html which will handle the routing in case of a reactjs application.

After finishing all these steps you will receive a url for your CloudFront distribution that looks something like this - dohgltcrfo5nj.cloudfront.net . You just need to use this URL as an alias and map it to your domain/subdomain which in our case is cod.superlemon.xyz

Route53 subdomain targeting

And that’s it, it's done! You now have a highly available application which does not need to be monitored or managed. Once you launch your application this way, it is now on a CDN and if you have to update the application in the future, the CDN cache must be invalidated for the changes to take effect. This can be done under the “invalidations” tab.

CloudFront cache invalidation

Then supply all the paths that have been updated and you would like the CDN cache to invalidate. If you would like to invalidate the entire app, just enter "*".

CloudFront cache invalidation for specific paths

Closing notes

This approach works great for a use case where the web application is mostly static and can be completely decoupled from the backend applications.

In terms of cost, with this approach you will only incur the CDN cost since the s3 storage cost for any web application would be quite low and the CDN cost will depend on how much traffic you have so it would scale well with usage.

For reference, we had around 100k hits on our web page in the month of June and our cost was roughly 0.79$

Our cost for this setup in the month of June