Serve two static S3 websites from the same domain, based on geolocation

amazon-cloudfrontamazon-route53

My current setup is that www.domain.com serves an S3-hosted static website via CloudFront, so www.domain.com CNAME points to the CloudFront distribution, which in turn points to the S3 static website URL. The CloudFront distribution has www.domain.com as an Alternate Domain Name set up.

I'd like to use Route53's Geolocation feature to route requests from North America to the current CloudFront (A), while all other requests go to another CloudFront (B) hosting another S3 static website. Since I can't add www.domain.com as an Alternate Domain Name for two CloudFront distributions, I'm using the wildcard *.domain.com instead for CloudFront A.

The wildcard works, and e.g. eu.domain.com I set up serves the CloudFront B site correctly.

I've set up the Geolocation rules correctly in Route53, and dig returns the correct CloudFront endpoint. Likewise, Route53 web testbench gives the correct endpoints depending on the IP location. However, curl and web browsers give the wrong content – i.e. CloudFront A even though I'm in the EU.

Is there something wrong in my configuration? Is there a silent failover on the DNS level to the A distribution for some reason? Or some nasty cache? Can this be done at all? Thanks!

Best Answer

However, curl and web browsers give the wrong content

Actually, they give the right content, in context. (Stick with me, here...)

The problem -- technically speaking -- is that you are actually wanting/expecting a response that would in fact be incorrect -- behavior that would be wrong if it actually worked the way you expected, based on the request being made.

Take a look at the request headers using curl -v. They may be connecting to an address retrieved by querying eu.example.com but check this request header:

> Host: www.example.com

The browser is actually getting exactly what it asked for.

This is why you can't assign the same alternate domain name to two CloudFront distributions. CloudFront -- like essentially all web servers -- uses the Host: header sent by the browser to understand what site the browser wants to see. Web servers can't see the DNS path that got you to them. The fact that you can do this while connecting to an IP address returned for a different site is no real surprise -- pick any CloudFront IP and forge a Host: header for a different site, and it is pretty likely to work, because there are good odds that the CloudFront equipment listening on that address can find the configuration within CloudFront and service the request.

This configuration cannot be done using only CloudFront and Route 53.

You need a proxy server in EC2 in the target region in the EU to act as a target for the eu domain in DNS, rewrite the Host: header, and forward the modified request to CloudFront.