Wildcard Domain Redirect using AWS CloudFront Functions

May 12, 2021 - 5 min read

If you have more than a single domain for your site, the simplest option would be to use your registrar’s redirect feature. But why take the easy route when you can do it the fancy way?

In this post, I’ll guide you through the process of using AWS CloudFront Functions to not only redirect your apex domain but also preserve both the subdomain and path. Here are two examples:

Redirect just the apex domain: 😃
https://example.comhttps://example.net

Redirect and preserve subdomain and path: 😲
https://www.example.com/bloghttps://www.example.net/blog

Redirect a subdomain that doesn’t even exist: 🤯
https://some-crazy-subdomain.example.comhttps://some-crazy-subdomain.example.net

CloudFront Functions is not like Lambda@Edge

CloudFront Functions are for super simple tasks only. Unlike Lambda@Edge, which gives you a full Node.js (or Python) environment, you only get access to a slim ES5 compatible runtime. This means that you cannot use “modern” features such as const and let or object destructuring. Additionally, you can’t even access the request/response body, and you’re only able to execute code for a maximum of 1 ms.

But on the upside, setting up a function is significantly easier, and they are executed in all edge locations rather than only in a few regions.

You can read the full introduction and comparison on the AWS Blog.

Creating the function

First, visit the Functions page in your CloudFront console and click Create function.

Then enter a name for your function—I chose domain-redirect.

Screenshot of function creation screen

After you’ve created the function, paste the following code (don’t worry, I’ll explain it in a moment) and press save.

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

  var splitHost = request.headers.host.value.split('.');
  splitHost[splitHost.length - 2] = 'example';
  splitHost[splitHost.length - 1] = 'com';
  var adjustedHost = splitHost.join('.');

  var response = {
    statusCode: 302,
    statusDescription: 'Found',
    headers: {
      location: {
        value: `https://${adjustedHost}${request.uri}`,
      },
    },
  };

  return response;
}

The required format for CloudFront Functions looks like the one in the code snippet. Strangely, they differ from regular Lambda and Lambda@Edge functions when it comes to the statusCode field name and the way that headers are specified. As I already explained, the idea of this function is to update just the target host address to include another apex domain. To achieve this, we redirect the user using the Location header and an appropriate status code. Usually, you use either 301, 302, 307, or 308 for redirects. You can read more about these status codes on MDN. Depending on your use case, you might want to change the code to use your status code of choice.

To change the apex domain, we first extract the domain that was accessed from the Host request header. Then, because domains always consist of at least two parts separated by dots, we take advantage of this and use the split method to create an array that contains all the segments. Next, we replace both the second last and last segments with the ones corresponding to our target domain. Remember to adjust this to redirect to your own domain! Finally, we join the array back into a single string using the join method and a dot as a separator.

Regarding the path (found in request.uri in the function code), we don’t change it and simply append it to our adjusted host. You might have also noticed that I hard-coded the protocol to be https. I chose to do so because every website in 2021 should use it by default anyway, and if yours is not, then you are clearly doing something wrong and need to change that immediately!

Linking the function

Now you have to associate the function with a distribution and have it trigger on Viewer Request.

If you haven’t created a distribution yet, create one as explained by the documentation using a custom domain name while also making sure to add a wildcard subdomain like *.example.com. Note that most settings are irrelevant as they will be bypassed by the function. Depending on your domain registrar, you may not be able to add a CNAME record for the apex domain. In that case, you’ll have to use another DNS provider like either AWS Route 53, which directly integrates with CloudFront, or one that allows you to enter a CNAME at the apex level and will then flatten it, like Cloudflare.

In either case, associate the function with the distribution and have it trigger on Viewer Request.

Screenshot of function creation screen During the initial setup

Screenshot of function creation screen Afterwards through the functions interface

Limitations

Due to the way that wildcard SSL certificates work, you will face an error whenever you try to access a multi-level subdomain like https://sub.sub.example.com through https. If you wanted to secure that subdomain as well, you could either add it to the certificate specifically or add the subdomain above as a wildcard. In this example, this would be *.sub.example.com.

You might have noticed that I only considered domains with one ending segment. If you were to apply this function, for example, to a .co.uk domain, it would actually replace the apex domain name itself.