Handling Redirects in a DNS + CloudFront + Load Balancer + EC2 Stack
If you’re hosting a website on AWS, there’s often a need to set up various kinds of redirects for the site:
- HTTP to HTTPS
- WWW to non-WWW or vice-versa
- example.IN/US/UK to example.COM
This article explores a few different ways of doing this with their pros & cons.
HTTP to HTTPS
After DNS resolution, all traffic first hits CloudFront. HTTP to HTTPS redirection can be accomplished at all layers from here on. CloudFront, ALB & web server, are all capable of this. But if you have no other redirects to make, CloudFront is the best & easiest solution here. Just set the “Viewer Protocol Policy” in the CloudFront distribution’s cache behavior to “Redirect HTTP to HTTPS”:
But this isn’t a good solution if you have other redirects to make. For example, to redirect http://www.example.com to https://example.com, this config would first cause CloudFront to issue a 301 redirect from http://www.example.com to https://www.example.com & then the ALB or web server would issue yet another 301 redirect to https://example.com. In such cases, it’s best to leave the “Viewer Protocol Policy” to “HTTP & HTTPS” & handle all redirects at ALB.
Redirects at ALB
Your ALB listener can do a lot more than just forwarding traffic to target groups. You can create host-based redirect rules in the listener to combine multi-step redirections into one. Here’s an example:
That’s an HTTP listener. Notice how it can redirect HTTP to HTTPS, WWW to non-WWW & example.IN to example.COM, all in one go. There’s just one exception: It can’t redirect http://example.com to https://example.com (assuming you have set CloudFront to always talk to your origin over HTTP, irrespective of the viewer protocol).
One solution would be to create an HTTPS listener, copy all of the above redirect rules to it & add to the HTTP listener, a rule to redirect http://example.com to https://example.com. Make sure you set CloudFront’s “Origin Protocol Policy” to “Match Viewer”.
That’s a lot of work, especially when you consider the fact that you’ll have to import or request a certificate for the HTTPS listener in the ALB’s region. The certificate you already attached to CloudFront won’t work because that’s limited to N. Virginia.
A workaround for all this is to create a rule in the HTTP listener to redirect example.com only if it was requested over HTTP. And here it is:
This rule makes clever use of the CloudFront-Forwarded-Proto header to determine whether the viewer requested the site over HTTP & only then, redirect them to HTTPS.
CloudFront Caches 301s
In all this endeavor, there’s one big pitfall you must be very careful of. Once the ALB returns a 301 to CloudFront, CloudFront will cache that response & never again forward requests to ALB, even for https://example.com. This is because CloudFront cache doesn’t differentiate based on protocol or host. To force CloudFront to maintain separate caches for different hosts & protocols, configure the CloudFront distribution’s cache behavior to cache based on whitelisted headers & whitelist the CloudFront-Forwarded-Proto & Host headers:
Harish KM is a Cloud Evangelist and a Full Stack Engineer at QloudX. Harish is very passionate about cloud native solutions and using the best tools for projects. This means that he is an expert in a multitude of application languages and is up to date with all the new offerings and services from cloud providers, especially AWS.
It saves my time. Thank you
I want your help…my server has an api running on docker in Port 6000 proxied in nginx this api is used to give metatag for dynamic content in my website it works perfectly even application load balancer when i configure cloudfront i cannot get the index.html produced from the api resulting in no metatag