Fixing CloudFront 502 Errors: When the SSL Handshake Fails

intermediate☁️ AWS2026-06-09| AWS CloudFront with Custom Origins (EC2, ALB, Nginx, Apache, or NodeJS) using HTTPS.

Error Message

502 Bad Gateway: CloudFront was unable to establish a secure connection with the origin server.
#cloudfront#502-bad-gateway#ssl-handshake#aws-troubleshooting

The Scenario

You’ve set up an AWS CloudFront distribution to sit in front of your origin—maybe an Nginx server on EC2, an Application Load Balancer (ALB), or a custom NodeJS app. Everything works perfectly over HTTP. However, the moment you toggle the Origin Protocol Policy to HTTPS, your users are greeted with a frustrating error:

502 Bad Gateway: CloudFront was unable to establish a secure connection with the origin server.

This happens when the secure handshake between CloudFront’s edge locations and your backend fails. It has nothing to do with the certificate your users see in their browsers. Instead, the trust has broken down specifically between AWS and your server.

Why CloudFront is Rejecting Your Connection

CloudFront is notoriously picky about SSL certificates. While a browser might let you bypass a warning with a "Proceed anyway" click, CloudFront simply drops the connection to stay secure. Here are the usual suspects:

  • Self-signed certificates: CloudFront requires a certificate from a trusted Certificate Authority (CA). It will never trust a self-signed cert for a custom origin.
  • Expired certificates: If your certificate expired even five minutes ago, the handshake will fail instantly.
  • Broken Certificate Chains: Your server might be sending your domain certificate but forgetting the intermediate certificates. This leaves the chain incomplete.
  • Protocol Mismatch: Your server might only support old protocols like TLS 1.0, while CloudFront is looking for TLS 1.2 or 1.3.
  • SNI and Hostname Mismatch: If your CloudFront Origin Domain Name is origin.example.com, but your certificate only covers www.example.com, the handshake fails.

Quick Fix: The "Emergency" Path

If your site is down and you need to restore service immediately while you debug, you can temporarily bypass the SSL requirement. Only do this as a stopgap.

  • Open the CloudFront Console.
  • Navigate to your Distribution and click the Origins tab.
  • Select your origin and click Edit.
  • Switch the Origin Protocol Policy to "HTTP Only".
  • Save and wait for the distribution to deploy (usually 2–5 minutes).

This forces CloudFront to talk to your server over port 80, skipping the SSL handshake entirely.

Permanent Fix: Solving the SSL Handshake

1. Inspect the Origin Certificate with OpenSSL

Stop guessing and see exactly what your server is presenting to the world. Run this command from your terminal, replacing origin.example.com with your backend's actual address:

openssl s_client -connect origin.example.com:443 -servername origin.example.com -showcerts

Check the output for two specific things:

  • Verify return code: You want to see 0 (ok). Any other code means CloudFront will reject the connection.
  • Certificate chain: You should see at least two certificates in the output—your server certificate and the intermediate CA certificate.

2. Align the Hostnames

A common mistake involves using the default AWS assigned name. If your CloudFront origin points to my-load-balancer-12345.us-east-1.elb.amazonaws.com, but your SSL certificate is issued to api.myapp.com, the handshake will fail. CloudFront expects the certificate to match the Origin Domain Name field exactly.

To fix this, make sure the domain name you entered in the CloudFront Origin settings is listed in your certificate’s Subject Alternative Name (SAN) list.

3. Fix the Nginx or Apache Chain

If you're using Nginx, pointing to the certificate file isn't enough; you need the full chain. Ensure your ssl_certificate directive points to the fullchain.pem (or equivalent) provided by your CA.

# Example Nginx Config
server {
    listen 443 ssl;
    server_name origin.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # Use modern, secure protocols
    ssl_protocols TLSv1.2 TLSv1.3;
}

4. Check for Corrupted Files

I’ve seen cases where a certificate file was corrupted during a manual scp transfer or a botched automated script. If the text looks right but the handshake still fails, verify the file integrity.

I often use the Hash Generator on ToolCraft to compare the SHA-256 hash of the local certificate against the one on the server. Since it processes the file locally in your browser, you aren't uploading sensitive keys to a third-party server. If the hashes don't match, your file was mangled during the upload.

How to Verify the Fix

CloudFront caches 502 responses for 10 seconds by default. Wait a few moments after your server changes before testing again. You can use curl to test the distribution directly while forcing the correct Host header:

curl -I https://your-id.cloudfront.net -H "Host: your-public-domain.com"

Success looks like a 200 OK. If you still see a 502, check the X-Cache header. If it says Error from cloudfront, the handshake is still the bottleneck.

Final Checklist

  • Is it CA-signed? (No self-signed certs allowed).
  • Is the chain complete? (Must include intermediate certs).
  • Does the hostname match? (The Origin Domain Name must match the Cert CN/SAN).
  • Is the port open? (Ensure your Security Group allows port 443 from CloudFront IP ranges).

Related Error Notes