In this article, I would like to share my experience in setting up AWS services to serve static assets for your application. Before moving on, I recommend that you should have some experience with building web application on AWS and have basic understanding of CloudFront, S3 and Lambda.
There are 2 main ways you can serve static assets to your end users:
- Put static assets in a server instance (EC2 instance) and serve them via a web server like Nginx and Apache
- Put static assets in a CDN service
The first one is what you may use when developing and deploying your web application for the first time. Around that time, the usage may be low and number of requests to the app is not significant and globally.
When your app grows, imagine that more and more users use your app and they are in a location where it’s far from the AWS region where you setup your EC2 instances, the latency will be high if assets aren’t cached in client side. As a result, your user will not be happy as he/she has to wait for a while for assets to load and the latency can get higher depending on the size. This is when second way comes to the rescue.
In order to serve static assets via CDN on AWS, you will need 3 services: CloudFront, Lambda@Edge and S3?
- CloudFront: CDN that supports static asset caching with regional edge caches.
- S3: Origin of assets, this is where static assets will be stored.
- Lambda@Edge: Lambda function that can be executed at edge locations.
I will now go into detail into each of them and the sequence of events
This is where client request will hit to request assets. CF does the following steps:
- Checked if requested asset is cached at nearest edge location
- If NOT, the request will be forwarded to Lambda@Edge
- If YES, return the cached asset on CF to the client.
You can think of LE as a middleware between CF and S3. Since Lambda allows you to write code, you can use it to customize request from or response to CF.
Imagine your asset has a pre-compressed version such as
.br . gz stands for Gzip and br stands for Brotli, in case you don’t know those are 2 most popular compression algorithms to compress assets when sending over the network.
We will be 2 Lambda functions, one will act as middleware for request from CF to S3 and one will act as middleware for response from S3 to CF.
To add the Lambda functions above as the middlewares, refer to this guide to help you. This will be quick to add but you will have to wait around 10 minutes for it to take effect on all edge locations.
As I mentioned above, it’s simply a place where all of your assets are stored.
After implement serving static assets with CDN, you will have a system architecture like this
Some useful tips
- To reduce requests to CF, Lambda and S3 (more request means more money), you should set metadata to your assets with
Cache-Control: public, max-age=31536000. This will tell CF and browser to cache assets at edge locations of a year.
- To set
Cache-Control, I suggest using AWS CLI S3 sync command with cache-control property. You can refer here for detail.
- For this to work properly even when the assets are updated on S3 side but the client still caches old version, you need to implement cache busting for your assets from your application’s side. The file will look like
- You can force invalidate cache on all edge locations, but you should try to avoid it as much as possible because invalidation will cost you more money. Implementing cache busting as I mentioned above will help you avoid this issue but remember to clean up old asset version unless you want to pay for unnecessary storage consumption ;) .