Lambda Edge redirect users based on their location

If you have a use case where you wish to show users different content based on their location, then you can do that by using a combination of CloudFront and lambda edge functions.

In this post, I will go through a step-by-step process on how you can do that. I will redirect a user from the UK to a UK-specific page and the others to the rest of the world-specific page.

You can configure CloudFront to add specific HTTP headers whose values are based on characteristics of the viewer request. With these headers, your origin can receive information about the viewer’s device type, geographic location, and more, without the need for custom code to determine this information. If your origin returns different responses based on the information in these headers, you can include them in the cache key so that CloudFront caches the different responses separately.

Source AWS

What that means is that if we serve our application from CloudFront and configure its headers correctly then we can get access to these values in our lambda edge’s origin request lifecycle method

  • CloudFront-Viewer-Country **** This contains the two-letter country code for the viewer’s country. For a list of country codes, see ISO 3166–1 alpha-2.
  • CloudFront-Viewer-City **** This contains the name of the viewer’s city.
  • CloudFront-Viewer-Country-Name **** This contains the name of the viewer’s country.
  • CloudFront-Viewer-Country-Region **** This contains a code (up to three characters) that represents the viewer’s region. The region is the first-level subdivision (the broadest or least specific) of the ISO 3166–2 code.
  • CloudFront-Viewer-Country-Region-Name **** This contains the name of the viewer’s region. The region is the first-level subdivision (the broadest or least specific) of the ISO 3166–2 code.
  • CloudFront-Viewer-Latitude – This contains the viewer’s approximate latitude.
  • CloudFront-Viewer-Longitude **** This contains the viewer’s approximate longitude.
  • CloudFront-Viewer-Metro-Code **** This contains the viewer’s metro code. This is present only when the viewer is in the United States.
  • CloudFront-Viewer-Postal-Code – This contains the viewer’s postal code.
  • CloudFront-Viewer-Time-Zone – this Contains the viewer’s time zone, in IANA time zone database format (for example, America/Los_Angeles).

Create a static website on S3

For the purpose of this post, I have built a simple web application using NextJS which has 2 routes –/uk & /row. The site is bundled and hosted on S3 as a static website. You can have your web application built & bundled in any library of your choice.

Once you have the bundle ready, go to S3 and create a new bucket and upload the contents of the bundle to this bucket.

Then, go to the properties of the bucket and enable static website hosting like this

https://miro.medium.com/v2/resize:fit:700/1*n3tIIWMDJQqy8Q1FthMRUg.png

After this, grant public access to the content of this bucket by turning these off like this

https://miro.medium.com/v2/resize:fit:700/1*zSUnKpDhAJ3TR1q5NxWaxA.png

And lastly, add this bucket policy to grant read access –

bucket policy

Now, you should be able to access your web application by going to the URL provided on the properties of this bucket under the static website hosting like this

https://miro.medium.com/v2/resize:fit:700/1*6fQTA5sA-pmuklVzisBlCg.png

Configure CloudFront with custom headers

Create a new distribution and select your S3 bucket with the static website as the origin domain

https://miro.medium.com/v2/resize:fit:700/1*4D3VRKSOHcqbnoMdOJdvFg.png

Then add these custom headers by selecting legacy settings like this. I have selected the ones I wanted to test with, but it is really up to your use case on what you need.

https://miro.medium.com/v2/resize:fit:700/1*hLRGPd-wuWyyaRdVEt2Blg.gif

Add lambda edge function

At this point, our CloudFront is ready and loaded with header values that we can access in our lambda edge functions. Head over to the lambda service on your AWS console and make sure that you are in the us-east-1 region. Lambda edge must be deployed in that region.

Create a new function from scratch like this

https://miro.medium.com/v2/resize:fit:700/1*zm-4kjzPRLcc85M3azwwTw.png

lambda from scratch

You will see a code editor on the console itself, where you can paste this code and adapt it according to your setup & requirements

I am only interested in knowing the country code of the end-user, which I am extracting from CloudFront’s request headers. Once, I have that, I am redirecting all users from GB/UK to /uk page and the rest will be redirected to /row page.

Attach lambda edge to CloudFront

This is the final step that will allow us to execute this lambda function on CloudFront’s origin request function. This is how AWS defines its CloudFront’s events –

After CloudFront receives a request from a viewer (viewer request)Before CloudFront forwards the request to the origin (origin request)After CloudFront receives the response from the origin (origin response)Before CloudFront forwards the response to the viewer (viewer response)

Source AWS

https://miro.medium.com/v2/resize:fit:545/1*ZitRPstFKx3016JsykcjXA.png

From AWS — Using AWS Lambda with CloudFront Lambda@Edge

Now, to attach the functions, there are 2 ways. You can either copy the arn of lambda function into CloudFront’s behaviors section like this

https://miro.medium.com/v2/resize:fit:700/1*aB5J_noWpFpjx3-ZGd8Iqg.png

or, you can add it as a trigger, directly from the lambda console itself like this

https://miro.medium.com/v2/resize:fit:700/1*eHQcrFcwbAedLPBJ93hY7Q.gif

Add a trigger to CloudFront

If you get a permission error from lambda edge, then you have to add lambdaedge as a trusted entity into your function’s IAM role like this

Wait for your CloudFront distribution to be redeployed, and once that is done, your redirect service should be ready. This is how it looks for me 🎉