The easiest way to host a static website on AWS is Amazon S3. In combination with Amazon CloudFront a really fast and cost-effective solution.
But if you run a multilingual static site, you run into the following problem: Amazon CloudFront allows you to specify a default root object, such as index.html
, but this will not work in subdirectories.
Take a deeper look into the project structure of the different applications to make them easier to understand.
Single Page Application
my-s3-bucket
├── app.css
├── app.js
└── index.html
Multi Page Application
my-s3-bucket
├── app.css
├── app.js
├── index.html
├── de
│ └── index.html
└── fr
└── index.html
When you access your CloudFront root URL /
in the browser, the requested index.html
page is delivered. Everything is fine. But if you call /de
instead of /de/index.html
in the browser, you will get an error page with the HTTP response status code 403.
A possible solution is to change your links and add /index.html
to each link, but I would not recommend this. All right, but which solution is the better one? Use a Lambda function!
Use Lambda@Edge
Lambda@Edge is a feature of Amazon CloudFront that allows your code to run globally at AWS locations close to your users. 🚀
The Lambda function is very simple. Let's have a look at the code:
exports.handler = (event, context, callback) => {
const request = event.Records[0].cf.request
const uri = request.uri
if (uri.endsWith('/')) {
request.uri += 'index.html'
} else if (!uri.includes('.')) {
request.uri += '/index.html'
}
callback(null, request)
}
This function inspects the incoming request from the client. Then rewrites the request so that CloudFront requests a default index object (index.html
in this case) for each request URI that ends with /
or does not contain a dot (.
).
❗️ The AWS Lambda function must be deployed in the region us-east-1
!
IAM
You also need to create an IAM role that can be assumed by the service principals lambda.amazonaws.com
and edgelambda.amazonaws.com
. Assign this role to your Lambda function.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com",
"edgelambda.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
Update CloudFront settings
Last but not least, it is necessary to set the default root object in the Amazon CloudFront settings to empty, as your Lambda function will handle it.
If you now call /de
in the browser, you should see the correct page instead of the error page.
Note: Serverless Framework
As you probably noticed from my previous posts, I use the Serverless Framework in some projects.
If your application is not deployed in the AWS region us-east-1
you will have the following problem: The Serverless Framework does not allow you to deploy individual services in different regions. Therefore it is necessary to use two different serverless.yml
manifests.
If you have any kind of feedback, suggestions or ideas - feel free to comment this post!
Top comments (0)