Serving WordPress behind Amazon CloudFront over HTTPS keeps the public site, login page, and admin redirect chain on one secure hostname while letting CloudFront terminate viewer TLS at the edge. It also avoids the common breakage where browsers reach the CDN on HTTPS but WordPress still emits plain-HTTP redirects, cookies, or asset URLs.
CloudFront decides how browsers reach the distribution through Viewer Protocol Policy and how the distribution reaches the origin through Origin Protocol Policy, origin request policies, and optional custom origin headers. WordPress makes its own scheme decision through WP_HOME, WP_SITEURL, FORCE_SSL_ADMIN, and the request variables that feed is_ssl(), so the CDN and the origin need to agree on the public hostname and on which trusted header proves the original viewer protocol.
A stable deployment starts with a CloudFront distribution that already presents a certificate for the public hostname and receives that hostname in DNS. From there, the practical fix is to keep WordPress aligned to the final HTTPS URL, enforce viewer HTTPS at the edge, forward the public Host header when the origin uses a different DNS name, and map a trusted forwarded-proto signal to $_SERVER['HTTPS'] before WordPress loads. URL cleanup for old content and edge-cache purges stay as separate follow-up tasks.
<?php define( 'WP_HOME', 'https://www.example.com' ); define( 'WP_SITEURL', 'https://www.example.com' );
If /wp-config.php/ already defines WP_HOME or WP_SITEURL, update the constants there; otherwise update the stored site URLs separately so WordPress stops generating the old origin hostname or plain HTTP links.
Redirect HTTP to HTTPS is the usual choice because legacy HTTP requests are upgraded at the edge before the request reaches WordPress.
Match Viewer is safe only when the behavior already enforces viewer HTTPS, because CloudFront forwards the viewer protocol choice to the origin.
When CloudFront connects to a custom origin over HTTPS, the origin certificate must match the origin domain name or the forwarded Host header, or CloudFront can return 502 Bad Gateway.
CloudFront always sends a Host header, but the default value is the origin domain name. Attach an origin request policy that includes the viewer Host header so WordPress, the web server, and any origin-side redirects stay aligned to www.example.com instead of an internal load balancer or origin hostname.
If the behavior already redirects or restricts viewers to HTTPS, adding an origin custom header such as X-Forwarded-Proto: https is the simplest option because CloudFront overwrites the value before it sends the origin request.
If the same origin must handle both HTTP and HTTPS viewer behaviors, forward CloudFront-Forwarded-Proto in an origin request policy instead of hard-coding https.
<?php
if (
( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && strpos( $_SERVER['HTTP_X_FORWARDED_PROTO'], 'https' ) !== false ) ||
( isset( $_SERVER['HTTP_CLOUDFRONT_FORWARDED_PROTO'] ) && strpos( $_SERVER['HTTP_CLOUDFRONT_FORWARDED_PROTO'], 'https' ) !== false )
) {
$_SERVER['HTTPS'] = 'on';
}
define( 'FORCE_SSL_ADMIN', true );
The WordPress is_ssl() guidance still relies on setting $_SERVER['HTTPS'] when a trusted reverse proxy or load balancer terminates TLS before PHP sees the request.
Trust forwarded headers only when the origin is reachable exclusively from CloudFront or another controlled proxy. A directly reachable origin must not accept client-supplied forwarded-proto headers.
$ curl -I http://www.example.com/ HTTP/1.1 301 Moved Permanently Location: https://www.example.com/ $ curl -I https://www.example.com/wp-admin/ HTTP/2 302 location: https://www.example.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.example.com%2Fwp-admin%2F&reauth=1 server: CloudFront
A redirect back to http://, to the origin hostname, or to a mixed-scheme wp-admin URL means the public URL, forwarded Host header, or trusted scheme mapping is still misaligned.
If CloudFront keeps serving an old redirect after the origin-side fix, invalidate the affected paths or wait for the cached response to expire.