AWS CloudFront is a popular solution for deploying websites and single page applications (SPAs). This post explains how to deploy multiple sites on different subdomains using a single S3 bucket and CloudFront distribution. This is not a step-by-step tutorial, but it does contain relevant sample code.
CloudFront Overview for SPAs
Hosting a website in CloudFront is relatively straightforward. Create an S3 bucket and create a CloudFront distribution pulling from the S3 bucket. Set the default index document to
index.html (or whatever), and this setup will work fine for most static sites. However, if CloudFront is being used to host a single page application, the error document will also need to be set to
This is due to the way CloudFront serves files. When a path, such as
/user/account is requested, CloudFront will look for an object matching that path in the S3 origin bucket. Since such a path does not exist, CloudFront will return a key error, when the desired behaviour is to let the SPA handle this path. Setting the error document to the index document, will give the desired behaviour.
This is a well-documented method for hosting SPAs on CloudFront.
Here’s the gotcha: CloudFront will not return index or error documents in ‘subdirectories’.
Routing and S3 bucket structure
Since the goal is to use different subdomains as the differentiator between sites, the S3 bucket will contain a separate folder for each site.
e.g. The following domains should point to the following ‘directories’.
site1.example.com => s3://
Furthermore, a wildcard DNS record will need to be created direct all traffic from *.example.com to the CloudFront distribution.
Modifying the request with CloudFront and Lambda
CloudFront provides four different types of hooks to modify requests and responses via Lambda@Edge functions, but we only need to focus on two, the
Viewer Request and the
Origin Request. In AWS CloudFront console, under
Behaviours, Lambda function ARNs can be specified for each type of hook.
This is triggered as soon as the request from a client comes to CloudFront. In this request, we need to take the leftmost part of the domain and add it as a prefix to the URI.
This is triggered after the request has entered CloudFront, but before the request hits the S3 origin bucket. In this request, we need to take the return a file for any file that is specified, otherwise, return the index document in the subdomain folder.