Configure Amazon CloudFront Error Pages
In the previous lesson we created a CloudFront distribution for S3 Bucket.
In this article, we will configure to handle website-related errors that occur on CloudFront, specifically errors 403, 404,... If error pages are not configured, users may see confusing and unfriendly error messages that look like this:
Note: Handling HTTP errors (403, 404,...) can be done on the S3 Bucket if it has the "Static Website hosting" feature enabled. Anyway, the way CloudFront and S3 Bucket handle HTTP errors is completely different, and which solution to choose is up to you.
- Amazon S3 Static Website Redirection Rules
- Amazon S3 Rest API Endpoint vs S3 Web Endpoint
1. Why does a 403 error appear for non-existing URLs?
After creating the CloudFront distribution. Try accessing a URL that doesn't exist, and you may receive an "Access Denied" error message. This is a 403 error code, when it should be 404 (NoSuchKey / Page Not Found).
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>AccessDenied</Code>
<Message>Access Denied</Message>
<RequestId>W1GYWM3Z8WRHPYC3</RequestId>
<HostId>GNRyvO3x/JrA2aTLjO5TWQMYJlqNZWkigBZ0A8heMzAXkjumCICIAjtLqtAxapp0I122P0oef8U=</HostId>
</Error>
The above error appears when the user sends a request to retrieve a non-existent object, while not having permission to list objects on the S3 Bucket. To handle this issue you need to configure a policy on the S3 Bucket that allows the s3:ListBucket permission.
After configuring the policy on S3 Bucket allows users to list objects. You re-access a URL that does not exist, now you will receive a 404 error message (NoSuchKey / Page Not Found), exactly as you expected.
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>NoSuchKey</Code>
<Message>The specified key does not exist.</Message>
<Key>123</Key>
<RequestId>YEAC2NV5KJ89BVKG</RequestId>
<HostId>FRligzQKzyXT486lUikuJjJ1hLDZpAtF7/MgD14oCX3oqkIgnq7ho8P9HIxDSYupRC31NictozA=</HostId>
</Error>
2. Where to configure error pages?
- [Selected Distribution] > Error pages > Create custom error response
3. Simple example handling 404 errors
In this section we will configure the response content to return to users when they access a URL that does not exist.
On S3 Bucket create a "response-404-simple.html" object with the following content:
response-404-simple.html
<!DOCTYPE html>
<html>
<head>
<title>404 - Page Not Found</title>
</head>
<body>
<h1>Sorry, 404 - Page Not Found!</h1>
Click <a href="/">here</a> to home page.
</body>
</html>
On CloudFront create an "Error response":
Http error code | 404: Not Found |
Customize error response | Yes |
Response page path | /response-404-simple.html |
HTTP Response code | 404: Not Found |
Finally, access a certain URL that doesn't exist and see the results. The content of "response-404-simple.html" was returned to the user.
Note: Every time you change configuration on CloudFront or data on S3 Bucket, you need to invalidate CloudFront's cache.
4. Advanced 404 error handling example (1)
Suppose your website has the following articles:
- 11111/css-tutorial.html
- 22222/java-tutorial.html
Sometimes users accidentally access URL(s) that don't exist, possibly due to typos, for example:
- 11111/csstutorial.html
- 11111/css
And you want to redirect user requests to the correct URL.
In this section, we will look at a solution illustrated below:
Configure "Error pages" for 404 errors:
Http error code | 404: Not Found |
Customize error response | Yes |
Response page path | /response-404-advanced-1.html |
HTTP Response code | 404: Not Found |
response-404-advanced-1.html
<!DOCTYPE html>
<html>
<head>
<title>404 - Page Not Found</title>
<meta name='referrer' content='no-referrer' />
<script src="/handle-404-advanced-1.js"></script>
</head>
<body>
<h1>Sorry, 404 - Page Not Found!</h1>
Click <a href="/">here</a> to home page.
</body>
</html>
Javascript will redirect user requests to the correct URL(s).
handle-404-advanced-1.js
// Create Page ID Map
const pageIdMap = new Map([
["11111", "css-tutorial.html"], // 11111/css-tutorial.html
["22222", "java-tutorial.html"] // 22222/java-tutorial.html
]);
// Check Page URL and redirect to correct URL If need.
function redirectIfNeed() {
const currentUrl = window.location.href;
const currentPathname = window.location.pathname;
console.log('currentPathname: ' + currentPathname);
if (currentPathname == '/response-404-advanced-1.html') {
console.log('Ignore for /response-404-advanced-1.html page');
return;
}
// currentPathname --> /11111/suffix-text
let j = currentPathname.indexOf('/', 1);
let pageId = '';
let suffixText = '';
if (j == -1) {
pageId = currentPathname.substring(1);
suffixText = '';
} else {
pageId = currentPathname.substring(1, j);
suffixText = currentPathname.substring(j + 1);
}
console.log('pageId= ' + pageId);
console.log('suffixText= ' + suffixText);
let correctSuffixText = pageIdMap.get(pageId);
console.log('correctSuffixText= ' + correctSuffixText);
if (!correctSuffixText) {
console.log('correctSuffixText is undefined -> The Correct Page Not Found!');
return;
}
if (correctSuffixText == suffixText) {
console.log('correctSuffixText == suffixText -> The Correct Page Not Found!');
return;
}
console.log('Wait 3 seconds before redirect to the correct URL...');
// Wait 3 seconds before redirect to the correct URL
// --> So you can see the logs in the console
setTimeout(()=> {
// Redirect
window.location.href = '/' + pageId + '/' + correctSuffixText;
} ,3000);
}
redirectIfNeed();
5. Advanced 404 error handling example (2)
Continuing with the scenario outlined above, in this section we present another solution to redirect user requests to the correct URL.
When a user sends a request to a page that doesn't exist, like this:
- /{pageId}/suffix-text
Javascript will redirect the user request to the page:
- /{pageId}/index.html
The "{pageId}/index.html" object is set with x-amz-website-redirect-location metadata, the value of which is a correct URL address.
- {pageId}/index.html metadata:
Note: x-amz-website-redirect-location only works in case your CloudFront is connected to S3 Bucket via Website Endpoint.
- Redirect in S3 Website with x-amz-website-redirect-location
- Amazon S3 Rest API Endpoint vs S3 Web Endpoint
response-404-advanced-2.html
<!DOCTYPE html>
<html>
<head>
<title>404 - Page Not Found</title>
<meta name='referrer' content='no-referrer' />
<script src="/handle-404-advanced-2.js"></script>
</head>
<body>
<h1>Sorry, 404 - Page Not Found!</h1>
Click <a href="/">here</a> to home page.
</body>
</html>
handle-404-advanced-2.java
// Check Page URL and redirect to correct URL If need.
function redirectIfNeed() {
const currentUrl = window.location.href;
const currentPathname = window.location.pathname;
console.log('currentPathname: ' + currentPathname);
if (currentPathname == '/response-404-advanced-2.html') {
console.log('Ignore for /response-404-advanced-2.html page');
return;
}
// currentPathname --> /11111/suffix-text
let j = currentPathname.indexOf('/', 1);
let pageId = '';
let suffixText = '';
if (j == -1) {
pageId = currentPathname.substring(1);
suffixText = '';
} else {
pageId = currentPathname.substring(1, j);
suffixText = currentPathname.substring(j + 1);
}
console.log('pageId= ' + pageId);
console.log('suffixText= ' + suffixText);
let idxPagePath = '/' + pageId + '/index.html';
if (currentPathname == idxPagePath) {
console.log('Not Found: ' + idxPagePath);
return;
}
console.log('Wait 3 seconds before redirect to the correct URL...');
// Wait 3 seconds before redirect to the correct URL
// --> So you can see the logs in the console
setTimeout(()=> {
// Redirect
window.location.href = idxPagePath;
} ,3000);
}
redirectIfNeed();
Let's try to see the results:
Amazon Web Services Tutorials
- Introduction to Amazon Web Services (AWS)
- Introduction to Amazon S3
- Introduction to Amazon Cloudfront and its architecture
- How to reduce Amazon Cloudfront Costs?
- Amazon CloudFront Invalidation
- Introduction to DigitalOcean Spaces
- Create DigitalOcean Spaces Bucket
- Introduction to Amazon ACM
- Java Awssdk S3 S3Client Upload object
- Create AWS accessKeyId/secretAccessKey
- Java Awssdk S3 List objects
- Host a static website on Amazon S3
- Java Awssdk CloudFront Invalidation
- DigitalOcean Spaces Create Access Key
- Java Awssdk Common Credentials Providers
- Java Awssdk ProfileCredentialsProvider
- Java Awssdk Creating and using EnvironmentVariableCredentialsProvider
- Java Awssdk Creating and using SystemPropertyCredentialsProvider
- Java Awssdk S3 Upload object with S3TransferManager
- Java Awssdk S3 S3TransferManager download object
- Java Manipulate DigitalOcean Spaces using S3TransferManager
- Java Create, list and delete S3 Bucket
- Aws Console create IAM User
- Create Amazon S3 Bucket
- Configure custom domain for Amazon S3 static website
- Create a CloudFront distribution for S3 Bucket
- Configure Amazon CloudFront Error Pages
- Amazon S3 Bucket policies
- Amazon AWS Policy Generator - policygen
- Migrate DNS service to Amazon Route 53
- Transfer domain registration to Amazon Route 53
- Request an SSL certificate from Amazon ACM
Show More