In DNS, example.com needs to be an A record with Alias set to Yes, pointing to the CloudFront endpoint.
This means example.com no longer points to your origin server, so you have to use a different name as the origin host. One option is to use the EC2 public DNS name for the instance.
By default, CloudFront will set the origin domain name in the Host:
header when sending the request to the instance. You can override this in Cache Behavior by whitelisting the Host
header, so that example.com is sent inside the request to the origin, even though the DNS entry used to actually find the origin differs.
If $ dig example.com
doesn't return a large number of IP addresses, then you aren't currently actually using CloudFront.
HTTP responses that come back from CloudFront will also contain extra headers, including X-Amz-Cf-id
, X-Cache
, Via
, and sometimes Age
.
Presumably, if the service on the ELB only answers to www.example.com
then that's the hostname you're going to be pointing to CloudFront -- so, your solution is straightforward: in the Cache Behavior settings, whitelist the Host
header for forwarding to the origin.
In this configuration, CloudFront passes through the Host
header sent by the browser, which must be added to the list of Alternate Domain Names in the distribution's configuration. Requests for dzzzexample.cloudfront.net
will fail, because your origin won't understand them, but that's usually good, because you don't want to have search engines indexing your content under the CDN domain name.
However, that might not be your plan. If that configuration won't work for your application, you need a Lambda@Edge Origin Request trigger to modify the Host
header.
'use strict';
// force a specific Host header to be sent to the origin
exports.handler = (event, context, callback) => {
const request = event.Records[0].cf.request;
request.headers.host[0].value = 'www.example.com';
return callback(null, request);
};
Note that the Host
header is immutable in an Origin Request trigger unless you configure the Cache Behavior to whitelist the Host
header as described above. In this case, you're whitelisting the Host
header set by the Lambda@Edge trigger, rather than the one from the browser, but the CloudFront configuration is the same.
You can't use Host
in the static Custom Origin Headers configuration in CloudFront -- that's not a supported configuration. The Lambda trigger has the same effect that setting would have, if it were permitted.
Best Answer
If you set the Origin Protocol to HTTPS Only, the traffic between CloudFront and the ELB will be secured by TLS, and you can configure the actual origin domain name either way. The
Cloudfront-Forwarded-Proto
header will indicate the protocol used between CloudFront and the viewer (since in this configuration, the load balancer will always setX-Forwarded-Proto: https
).CloudFront insists that the TLS negotiation between itself and the Origin be trustworthy. A factor commonly overlooked is that TLS (SSL) certificates do two things: provide for encryption of the connection (obvious) and provide for authentication of the server -- attestation that the server is authorized to be a server for the requested hostname, and is not an impostor (less obvious). This is why you get browser warnings if the server's certificate's subject and/or subject alternative name doesn't match the hostname in the browser's address bar.
CloudFront allows a limited exception to this requirement, allowing certificate validation to succeed as long as one of two conditions is met:
Host
header that CloudFront is forwarding from the browser to the ELB.Otherwise, CloudFront returns
502 Bad Gateway
.The first condition isn't possible if you use the ELB hostname as the Origin Domain Name, which is why the CloudFront console prompts you to whitelist the
Host
header for forwarding if it sees that your target is an ELB.But as long your environment looks like this...
www.example.com
points to CloudFront and is configured in the distribution's Alternate Domain Name, andHost
header is configured for whitelisting, andwww.example.com
...then it works, with one exception: the
dzczcexample.cloudfront.net
domain can't be used in the browser to access your origin through CloudFront. In some configurations, this is desirable, because you don't actually want your content accessible via that second entry point.Otherwise, your best bet is indeed to do what you have suggested -- mapping a hostname in a domain that you control onto the ELB in DNS, and configuring that hostname as the origin domain name in CloudFront.
CloudFront can use any Internet-accessible hostname as its origin -- the origin doesn't have to be inside AWS. You could, for a random example, use a Google Cloud Storage bucket as an Origin in CloudFront. The integration between CloudFront and the Origin is a loose one -- by that, I mean that CloudFront has no special awareness of ELB. It just resolves the hostname via public DNS and makes connections.
Note also, if you want to ensure that only your CloudFront distribution can talk to your origin, you will want to configure a secret Custom Origin Header in CloudFront, and the Origin needs to reject requests that lack this value. While it is possible to use the ELB security group to allow access only from the CloudFront address space, that space grows fairly often and you need a way to keep your security groups updated to allow new address ranges... but it is my opinion that this provides a false sense of security, since anyone can technically create a CloudFront distribution and point it anywhere, including your ELB. Using a custom header avoids this.