3

As per this Amazon's article I was trying to make the whole WordPress website work behind AWS CloudFront. Not just the static files but the whole website (it can be done with setting up proper cache behaviors). However if you use the bare domain (example.com, without www) it seems that's impossible.

Namely, if the origin of a CloudFront distribution is example.com, and if you put a CNAME for example.com in that same distribution CloudFront will sporadically produce 403 Error. After some digging I found out that this is expected behavior since with this setup, where origin and the CNAME values are the same, CloudFront will look for the origin onto itself and produce error.

So how can one use naked domain and use CloudFront as a proxy at the same time?


Update:

I've implemented the origin.example.com solution suggested in the comments. I was getting an error but now it works.

  1. The origin in the CF distribution is origin.example.com.
  2. CNAME in the CF distribution is example.com.
  3. In the Cache Behavior settings in the CF distribution the Host header is whitelisted.
  4. In DNS origin.example.com points to the server's IP with an A record.
  5. In DNS example.com points to the CF distribution with an ALIAS-A record.

The only beef I have with this workaround is that this way the origin server's IP address is discoverable on the net. A script kiddie can accidentally access origin.example.com and the server's true IP address is in the open, thus you're prone to DDoS. One of the many benefits of a proxy is that with it you're hiding the true server's IP address.

I'm currently using Cloudflare as a proxy mainly because of that reason. In the past I was hit with massive DDoS attack and my server's IP address was null-routed by the host, so I had to quickly hide behind Cloudflare and change the server's static IP. No headaches since then. I wanted to switch to CloduFront but using the bare domain seems not viable.

Vila
  • 345
  • 2
  • 5
  • 12
  • CloudFront considers the origin cert valid if it matches the `Host` header, if you configured the cache behavior to whitelist the `Host` header for forwarding the origin. It doesn't need to match the hostname you're using for routing. But note the `age: 227`. This is a cached error. See my comment about setting the Error Caching Minimum TTL. – Michael - sqlbot May 13 '18 at 12:49
  • @Michael-sqlbot I didn't forget that, I've created a custom 503 error page with zero TTL. I assume I don't have to repeat the process for every single one error page type. – Vila May 13 '18 at 20:00
  • No, just the error you're getting should be sufficient. It's not clear why/how your error page has an `age` header. – Michael - sqlbot May 13 '18 at 21:57
  • I've nailed it @Michael-sqlbot. It was a trivial matter. I was placing `origin.example.com` in Route 53, and I was supposed to put it in my current DNS server. The domain is not connected to Route 53, it's connected to my current DNS server. Thanks for your help. – Vila May 14 '18 at 07:49
  • I have one more sub-question @Michael-sqlbot. It is very important if one wants to use a proxy. If I switch to CloudFront, and thus to Route 53, if someone scans `origin.example.com` will the origin server's IP address be discovered? As of now I'm behind Cloudflare and if I access `origin.example.com` directly it presents Invalid SSL Error, which is fine, and it shows the Cloudflare's IP address. If I go away from Cloudfllare what happens in this case? – Vila May 14 '18 at 08:15
  • Yes, if someone discovers the name `origin.example.com` and looks it up in DNS, they will get the answer. If they try to access it, it should behave the same way it is behaving, now. – Michael - sqlbot May 14 '18 at 10:37

3 Answers3

2

You have to create another hostname in DNS, pointed to the instance, such as origin.example.com. But the instance does not need to know about this name.

Create a CloudFront origin using this new hostname as the origin domain name, and then in the Cache Behavior, whitelist the Host header for forwarding to the origin.

In DNS, point example.com only to CloudFront.

CloudFront will then use the alternate name to find the instance's actual IP address, but will preserve the original hostname (example.com) in the request that is sent to the origin.

Michael - sqlbot
  • 169,571
  • 25
  • 353
  • 427
  • I have some questions: When adding behaviour besides the `default` you need to enter a path pattern. So I assume the path pattern for `origin.example.com` will be just `*`? All other behaviors (`default`, for example `*.jpg`, etc.) should use `example.com` as origin or not? In which position this new forwarding behaviour needs to be placed? At the top so it takes first precedence? Does this forwarding approach has effect on speed, possibly SEO etc.? Is this way the instance's IP discoverable, thus annulling the proxy effect? – Vila May 12 '18 at 21:26
  • I see you have a longer explanation [here](https://stackoverflow.com/a/50138403/1148508) but I'm still getting an error. – Vila May 12 '18 at 23:47
  • Set your [Error Caching Minimum TTLs to 0](https://stackoverflow.com/a/35541525/1695906) and then do a [cache invalidation](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Invalidation.html) for `/*`. Wait for the invalidation to complete and the distribution to switch from `In Progress` to `Deployed`, then test again. If you continue to get errors, capture the entire response including the headers, and edit it into your question, please. – Michael - sqlbot May 13 '18 at 00:29
  • I've done what you've suggested but to no avail. I've included the response in the question. – Vila May 13 '18 at 09:35
2

If anyone else runs into this issue, the problem may be with the certificate. If your certificate is for "*.example.com" make sure it also has "example.com" added. If not, create a new one.

bonuspig
  • 21
  • 2
0

When using CloudFront to cache an entire web site, use an A-ALIAS record for both the naked domain (example.com) and for www (www.example.com) that resolves to the CloudFront Domain Name. If you are using SSL on CloudFront, ensure that both domain names are in the certificate.

John Hanley
  • 74,467
  • 6
  • 95
  • 159
  • I think that doesn't solve the problem. CloudFront won't be able to find the instance. You need an actual A record that points to the server's IP address. – Vila May 12 '18 at 21:02
  • I forgot to mention setting up the origin domain. You need a dns entry that contains the A record with the IP address of the actual server. The exception is if the server is part of an ELB/ALB (which is what I usually setup). – John Hanley May 12 '18 at 23:11
  • Still, can't get to work.I'm pointing `origin.example.com` with an A record to the server's IP address as per the @michael-sqlbot answer. Since it is a live site I'm changing my local `hosts` file to affect DNS locally in order to see the changes. In my local `hosts` file `example.com` has one of the CF distribution IPs, and `origin.example.com` has server's IP. – Vila May 12 '18 at 23:37
  • @Vila the `origin.example.com` record needs to actually go into DNS. CloudFront can't see your hosts file. – Michael - sqlbot May 13 '18 at 00:30
  • Don't use IP addresses for CloudFront. What is the TTL value for your DNS records? You have to wait at least that time to see changes propagate. I use Chrome and it remembers too much for too long so I have to flush its cache when testing. – John Hanley May 13 '18 at 03:43
  • Note: For your conclusion that you must use AWS servers with CloudFront. This is not true. I often setup Azure instances as origins for CloudFront. – John Hanley May 13 '18 at 03:46
  • @Michael-sqlbot, yes the `origin.example.com` is in the DNS. With `hosts` I'm telling the `example.com` to use one of the CloudFront IPs discovered with `dig xxx.cloudfront.net`. And maybe the problem is there since I'm unable to test this in real life but through `hosts`. – Vila May 13 '18 at 09:44
  • @JohnHanley I don't use IPs for CloudFront. I point `origin.example.com` to the server's IP address. The server is outside of AWS altogether. DNS TTL is 300, so that's not a problem. When testing I'm clearing Chrome's cache, plus I'm also testing with Firefox. As far as my previous conclusion in my question, I've edit it out since I see there are people who obviously have a working solution. – Vila May 13 '18 at 09:49