Send custom Host header with CloudFront

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.