Domain redirects for CloudFront

In 2019, we wrote about www-redirects with Lambda@Edge. That solution still works, but AWS CloudFront released a new feature: CloudFront Functions. With those functions, it’s easier and cheaper to redirect users to the right domain.

CloudFront Functions and Lambda@Edge are not full replacements for each other. There are major differences between the two. With CloudFront Functions you can hook into viewer-request and viewer-response, but not origin-request and origin-response. The Javascript environment has limited functionality. And no network access, so you can’t fetch data from an API or an AWS service.

📖 Read more about the differences in the AWS documentation.

Despite these limitations, it’s very useful for small request and response modifications. One of them is redirecting viewers to another domain or preventing traffic to the default cloudfront.net domain.

Create a CloudFront Function

The AWS documentation is overwhelming, but in my experience very complete. The only problem is how to find the information you’re looking for. Instead of writing down all the steps, I’ll point you to the right pages in the documentation.

📖 This page explains creating and associating a CloudFront function.

Use the code below and with the event type “Viewer Request”. Change the value of mainDomain to your needs. Or leave it like that, we’ll be very happy with the traffic you generate.

function handler(event) {
    var request = event.request;
    var headers = request.headers;
    var uri = request.uri;
    var mainDomain = "grrr.tech";

    if (headers.host.value !== mainDomain) {
        return {
            statusCode: 301,
            statusDescription: "Moved Permanently",
            headers: {
                location: { value: "https://" + mainDomain + uri },
            },
        };
    }

    return request;
}

This function reads the domain from the HTTP request. When that doesn’t match the main domain, a redirect response is created. Otherwise, CloudFront can continue handling the request.

Debugging

It’s not possible to log errors, because CloudFront functions aren’t allowed to communicate with the outside world. AWS offers a test tool. It’s useful to find syntax errors. But be careful when creating a test request. When your test request doesn’t match a live request, your function might fail in production.

Another option is to add a custom header to the response. Run curl -I https://your-distribution-url.cloudfront.net to print the response headers. And what about using the body, doesn’t that make more sense? Yes, but CloudFront functions aren’t allowed to change the body. That’s another difference with Lambda@Edge.

function handler(event) {
    var request = event.request;
    var headers = request.headers;
    var uri = request.uri;

    return {
        statusCode: 200,
        statusDescription: "OK",
        headers: {
            "x-debug-header": { value: uri },
        },
    };
}

Further reading

For a good understanding of CloudFront, the image below helped me a lot. It shows the order of events and the flow of data. I use it regularly to validate my ideas.

CloudFront events that trigger Lambda functions.

📖 The image explained by AWS