Domain Redirection In A Snap 🔃
Tags: javascript, aws, lambda, cloudfront
Published: 2022-10-25 10:08:29

At our company, we have two domain names, exampleCorp.ae and exampleCorp.me. I was given a task to redirect users based on where they are geographically located when they visit our website.
Both of these domains lead to the same S3 bucket hosting our website which happens to be fronted by CloudFront.
If the users are from the UAE, they must be redirected to exampleCorp.ae. Everyone else around the globe must be redirected to exampleCorp.me.

I found several ways to achieve this. The first thing that might come to mind is Route 53 geolocation which is a very good solution. But what if you don't have Route 53 implemented and just had Cloudfront?

## CloudFront Functions And Lambda@Edge:

According to the [aws docs](https://aws.amazon.com/blogs/aws/introducing-cloudfront-functions-run-your-code-at-the-edge-with-low-latency-at-any-scale/): Our CDNs can now perform direct computing! Take a look at Image 1. It's going to be the foundation of all the upcoming logic. This means that our requests can be manipulated on the spot without any middleware or any actual server... Another success story for the serverless concepts 🏆.

Image 1:
![cloudfront global architecture](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z671x6rgr5k93dmzylma.png)

Cool, but what do we want to compute or manipulate? What are the inputs we want to give? And what is the difference between these two computing services?

Let's start with the differences:

Image 2:
![cloudfront-functions-and-lambda-edge-comparison](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lijud7qod4cvcrpnmxpq.png)

Lambda@Edge is extremely powerful, but if we can do it with less cost, then why not use Cloudfront functions? At the end of the day, we have a computing system that is going to process our algorithm. 

I want to know what the user asked to visit in the request, is it exampleCorp.me or exampleCorp.ae? 
I also want to know from which country the request originated.

Amazing so now I have 2 variables, each having 2 relevant options.

- Host:

1. exampleCorp.me
2. exampleCorp.ae

- Country:

1. UAE
2. everything else but UAE

Seems like our algorithm is starting to take shape. But how will I pick up these variables?

Go To: Cloudfront > Distributions and select the distribution where your S3 will be the origin.

![cloudfront behavior](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/73rw9qwhyd8g3m1c1l2h.png)

Click on create behavior.

1. Set your path pattern. When matched the cache behavior will apply. e.g: /* or /index.html
2. Select your correct origin.
3. Scroll down to this section:

![cache key and origin request](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ggmym88budv8n04q39mw.png)

4. Keep the Cache policy as is and in the Origin request policy click on Create policy, do as this image:

![Create origin request policy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iir38r5uwlml5x8qe2o9.png)

Now every time our path pattern is matched, a new header is appended to our request having the country where the request actually originated as value.

All we have to do is intercept the request and write our algorithm!

Go Back to the cache behavior you just created and scroll down to the last section. You should see something like this.

Image 3:
![cloudfront events](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/izz0xvo3ezj89q0gpzgg.png)

Here we are going to add our function that will redirect the users based on the variables that we now supposedly receive in the request. The function we'll write is going to be triggered by 1 of the 4 CloudFront events. I'll go with Viewer Request.

Duplicate the tab you are in and go to CloudFront functions.

![Cloudfront functions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eas4jdvit7nw0u2thssk.png)

Create a new one, name it, describe it (optional), and click on create. You cannot rename it afterward so watch out.
Now paste this code

```
function handler(event) {
  console.log("Inside our cloudfront function !!");
  var request = event.request;
  var requestURI = request.uri;
  var referer = request.headers.host.value;
  // this is added thanks to the cache behavior we created
  var country = request.headers["cloudfront-viewer-country"].value;

  if (country === "AE" && !referer.includes("exampleCorp.ae")) {
    /*this condition means that if the country of origin is UAE but the users are trying to access something other than "exampleCorp.ae" */
    console.log("inside 1st condition");
    var redirectResponse = {
      statusCode: 302,
      statusDescription: "Found",
      headers: {
        location: { value: `https://exampleCorp.ae${requestURI}` },
      },
    };
    return redirectResponse;
  } else if (country !== "AE" && referer.includes("exampleCorp.ae")) {
    /*this condition means that if the country of origin is not UAE but the users are trying to access "exampleCorp.ae" */
    console.log("inside 2nd condition");
    var redirectResponse = {
      statusCode: 302,
      statusDescription: "Found",
      headers: {
        location: { value: `https://exampleCorp.me${requestURI}` },
      },
    };
    return redirectResponse;
  } else {
    /*this means that the user has actually the correct request and nothing needs to be modified so we return the initial request */
    return request;
  }
}

```
check the cloudfront-viewer-country values [here](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-cloudfront-headers.html#:~:text=ISO%203166%2D1,.)

Save the changes made to your function and Publish it. If you don't you won't be able to link it to CloudFront.

Go back to the previous tab and associate the function you just published to the CloudFront event Viewer Request:

![viewer request cloudfront](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x0hdpu6rewccokcn6k2q.png)

Save your changes and you are done! Congratulations!!
You can see your logs in the CloudWatch following these [steps](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/AccessLogs.html).

Feel free to use both for whatever suits your scenario. Just keep in mind that Cloudfront Functions will be triggered on **Viewer Request** or **Viewer Response** as for the lambda@edge it supports any of the 4 triggers (look at Image 2).