Redirecting requests to a country-specific URL on AWS with CloudFront and Lambda
Tags: tutorial, aws, beginners, webdev
Published: 2020-05-04 19:45:53

---
title: Redirecting requests to a country-specific URL on AWS with CloudFront and Lambda
published: true
tags: tutorial, aws, beginners, webdev
---

Sometimes you need to be sure you show relevant content to visitors in different countries. Let's see how it can be done using Amazon Web Services.

#Prerequisites
In this tutorial, we will implement location-based redirects for an app distributed via Amazon CloudFront. I will store specific files on Amazon S3 but it could be any storage or web server. Finally, we will use AWS Lambda service to check country codes and return an appropriate response.

I added three files to the S3 bucket. Each of them is responsible for a particular locale:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qt1wd0iml9nvpo5wztjs.png)

Each file from the bucket has its own CloudFront distribution with the WEB distribution method. It might not make sense while they point to the same S3 bucket but in a real-world app each distribution would point to a different domain.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qz3b3ahy1ojrn4nkco6u.png)

#Setting Up Lambda Function
Open up Lambda service, select the region you need and hit *Create function*. Now we need to configure a function and name it:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wza0cyefp6dhg4hl8ncz.png)

The only thing that worth to be mentioned is the function's execution role. If this is your first Lambda function for CloudFront, you need to create a new role. Select **Basic Lambda@Edge permissions (for CloudFront trigger)** from the *Policy templates* dropdown and insert a role name for future usages. I named it **cloudfront_basic** but it might be any name. The role is required to let Lambda know what service is going to use the function. Go ahead and save your function.

It's time to get your hands dirty! Put the following code into the editor:
```
exports.handler = async (event) => {
    const getCustomResponseWithUrl = url => ({
        status: '302',
        statusDescription: '302 Found',
        headers: {
            location: [{
                key: 'Location',
                value: url,
            }],
        },
    });
    
    const request = event.Records[0].cf.request;
    const headers = request.headers;
    let response = request;
    
    if (headers['cloudfront-viewer-country']) {
        const countryCode = headers['cloudfront-viewer-country'][0].value;
        switch (countryCode) {
            case 'GB': {
                // generate a redirect response to the United Kingdom distribution
                response = getCustomResponseWithUrl('https://d1zywwhn3ytw4t.cloudfront.net');
                break;
            }
            case 'US': {
                // generate a redirect response to the United States distribution
                response = getCustomResponseWithUrl('https://d3gf6cz8gf6db6.cloudfront.net');
                break;
            }
            default: {
                // don't change the incoming request
                break;
            }
        }
    }

    return response;
};
```

All we need to do is to check if the country from the `cloudfront-viewer-country` header fits any of our conditions. If so, we need to generate a redirect response with a URL of the CloudFront distribution we want to redirect to. If not, just need to return the incoming request from the `event` object that is passed as the first argument to the handler function. Dead simple!

To make the function visible to CloudFront distributions we need to save it and publish a new version from the actions dropdown. Copy the function's **ARN**, it will be available in the top right corner. We'll need it a moment later.

#Adding Lambda Function to CloudFront distributions
Now it's time to make CloudFront distributions use the function. Go to CloudFront and open the distribution we created for requests that don't meet any condition(not from UK or US in our case). Open the behaviors tab and click *Create behavior*. Put `*` into the path to make it work for each path for simplicity. For the real-world app, you can add a more complex path pattern.
Next, select **Whitelist** for the `Cache Based on Selected Request Headers` setting. In the *Whitelist Headers* input, add **CloudFront-Viewer-Country** to the whitelisted headers list. It will make CloudFront add the `cloudfront-viewer-country` header that we use in the Lambda function.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6rv6w0q9nc18rvslrl66.png)

Finally, put the **ARN** of the Lambda function we copied and associate it with the **Origin Request** event:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/2p8sp99fb01935hmjxmz.png)

We're all set! Save the behavior we created. Wait for the distribution to deploy and that's it:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ce4nq70v5wbz93ic4efx.gif)

#Further reading
[CloudFront x Lamda examples](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-examples.html)
[CloudFront x Lamda requirements and restrictions](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-requirements-limits.html)
[Lamda function logging](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-logging.html)
[Create aliases for different lambda environments or setups](https://docs.aws.amazon.com/lambda/latest/dg/configuration-aliases.html)
**NOTE:** [Lambda aliases and environment variables are not supported by CloudFront](https://forums.aws.amazon.com/thread.jspa?threadID=268270)