Few things are more frustrating than a CDN spitting out 502 Bad Gateway errors while your origin server looks perfectly healthy over SSH. I ran into this exact headache after updating an edge configuration: public traffic died instantly with 502s, even though curling the origin IP directly worked fine.
The problem usually hides in the encrypted hop between the CDN edge node and your origin. Here is how to trace the TLS handshake, fix Server Name Indication (SNI) mismatches, align your Nginx ciphers, and eliminate upstream proxy timeouts.

How the CDN-to-Origin Handshake Breaks
When someone visits your site, their browser negotiates a TLS session with the CDN edge. The edge then opens a second, completely separate TCP and TLS connection to your origin server to pull cache misses or dynamic pages. A 502 means that second leg failed.
In practice, the TLS handshake between the CDN and origin fails for one of four reasons:
- Certificate Subject Mismatch: Your origin serves a certificate issued for an internal hostname or default domain instead of what the CDN asked for.
- Missing or Broken SNI: The edge does not send the right Server Name Indication during
ClientHello, so your web server serves a fallback default cert. - Cipher or Protocol Mismatch: Your origin server disables older TLS versions or elliptic curves that the CDN’s egress proxies still rely on.
- Origin Firewall Blocks: Your server or cloud firewall silently drops port 443 traffic coming from the CDN’s edge IP blocks.
If you recently set up your reverse proxy using our guide to connect a domain to your host through StackPath CDN, verifying this backhaul connection is your first debugging step.
Step 1: Test Origin Connectivity with cURL and OpenSSL
Do not debug this in a browser. Browsers hit the edge IPs and mask the actual TLS negotiation happening behind the scenes. Open your terminal and use openssl s_client to connect directly to the origin IP while explicitly sending the public domain via SNI.
Run this command against your origin IP on port 443:
openssl s_client -connect 198.51.100.24:443 -servername example.com -showcertsLook closely at the output:
Verify return code: 0 (ok): The origin cert is valid and trusted by the CA store.Verify return code: 18 (self signed certificate): The CDN will abort if it runs in strict verification mode.SSL routines:ssl3_get_server_certificate:certificate verify failed: Your origin is missing the intermediate certificate chain.
Next, reproduce the exact HTTP request your CDN edge sends when fetching from origin. Force the IP resolution with cURL’s --resolve flag:
curl -Iv https://example.com/healthz --resolve example.com:443:198.51.100.24If cURL throws an SSL error or hangs past 5 seconds, the problem is definitely on your origin box, not the edge. Check the OpenSSL s_client documentation if you need extra debugging flags.
Step 2: Fix SNI Mismatches and Origin Host Headers
This is the most common 502 trigger if you host multiple virtual hosts (vhosts) on the same box. When the CDN connects to your origin IP, it must pass the domain in both the TLS SNI header and the HTTP Host header.
If your CDN edge sends the raw IP (like 198.51.100.24) as the SNI value, Nginx or Apache serves its default catch-all certificate. If that cert does not match your domain, the CDN drops the connection immediately.
Here is an Nginx vhost configuration that properly handles incoming CDN traffic with the full certificate chain:
server { listen 443 ssl http2; server_name example.com www.example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # Prevent serving this vhost to unknown SNI requests if ($host != $server_name) { # Optional: return 421 Misdirected Request or let proxy_pass handle } location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }
}Always point ssl_certificate to fullchain.pem, never cert.pem. CDNs validate strictly and will reject handshakes if your origin omits the intermediate CA bundle. If you manage certificates across different registrars, check our guide on how to install custom SSL certificates properly to ensure your bundles are complete.
Step 3: Align SSL/TLS Protocols and Cipher Suites
Modern CDNs like StackPath, Cloudflare, and Fastly will drop connections if your origin only supports ancient ciphers or locks negotiation down to TLS 1.0. On the flip side, if you lock your origin to TLS 1.3 only with ultra-restrictive ciphers, older CDN egress nodes might fail to find a matching cipher.
Standardize your TLS configuration in Nginx like this:
# /etc/nginx/conf.d/ssl.conf
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;This baseline aligns with the Mozilla Intermediate TLS guidelines. It supports almost every modern edge proxy while maintaining security standards per RFC 8446.
Test the syntax and reload Nginx to apply the changes:
sudo nginx -t && sudo systemctl reload nginxStep 4: Fix Upstream Reverse Proxy Timeouts
A 502 Bad Gateway is not always an SSL issue. It also happens when your upstream app server (PHP-FPM, Node.js, Gunicorn) takes too long to process a request, causing Nginx to drop the connection back to the CDN.
When the edge gets tired of waiting, it logs a 502 or 504. Give your backend enough breathing room by tuning buffer and timeout limits in your location block:
location / { proxy_pass http://127.0.0.1:8080; # Handshake and connection timeouts proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; # Buffer tuning to prevent header truncation proxy_buffer_size 128k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k;
}To learn how to handle backend caching headers and keep origin load manageable, check our walkthrough on CORS and Cache-Control headers for CDN assets.
Step 5: Check Strict Origin Certificate Verification
Most CDNs let you pick how strictly they validate origin SSL certificates:
- Off / Flexible: The CDN connects to your origin over plain HTTP on port 80 (insecure, prone to redirect loops).
- Full: The CDN connects over HTTPS (port 443) but ignores whether the cert is self-signed or expired.
- Full (Strict): The CDN requires a valid, unexpired certificate signed by a recognized CA that matches the requested hostname.
If your CDN is in Strict mode and your origin certificate expired yesterday, your visitors get an instant 502.
Check your origin certificate validity dates directly from your server:
echo | openssl s_client -connect 198.51.100.24:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates -subject -issuerMake sure notAfter is in the future and the issuer is a recognized CA like Let’s Encrypt, DigiCert, or Sectigo.
A Real-World Gotcha: The Port 443 Redirect Loop
Here is a bug that bit me in production: the CDN was set to fetch from origin over plain HTTP (port 80), but the origin Nginx config had an aggressive HTTP-to-HTTPS redirect enabled:
# Problematic origin config
server { listen 80; server_name example.com; return 301 https://$host$request_uri; # Caused infinite edge loops
}When the CDN requested an asset over port 80, Nginx answered with a 301 Moved Permanently to https://.... The CDN followed the redirect, but its origin rule was hardcoded to fetch over HTTP, sending the request back to port 80. After bouncing back and forth until hitting the max redirect limit, the CDN gave up and served a 502.
Here is how to fix it:
- Set your CDN origin protocol rule strictly to HTTPS Only on port 443.
- Check the
X-Forwarded-Protoheader in your redirect rules so Nginx knows the request was already encrypted at the edge:
server { listen 80; server_name example.com; # Only redirect if the edge itself received plain HTTP if ($http_x_forwarded_proto = "http") { return 301 https://$host$request_uri; }
}If you run high-traffic infrastructure, pairing this setup with an origin shield to prevent server overload will stop cache purge cascades from hammering your origin.
Verification Checklist: Confirming End-to-End Handshakes
Before closing the ticket, run through this list:
- [ ] Origin port 443 is open and reachable from all CDN edge IP subnets.
- [ ] Origin SSL certificate uses the complete bundle (
fullchain.pem). - [ ] Web server vhost matches the SNI host header sent by the edge.
- [ ] TLS 1.2 and 1.3 are enabled with standard ECDHE ciphers.
- [ ] Upstream processes (PHP-FPM, Node, Python) are alive and listening.
- [ ] Host firewalls (UFW, iptables, AWS Security Groups) allow CDN egress IPs.
For more edge proxy options, consult the official Nginx proxy module documentation.
Frequently Asked Questions
What is the difference between a 502 Bad Gateway and a 504 Gateway Timeout?
A 502 Bad Gateway means the CDN edge got an invalid or broken response from the origin (like a failed TLS handshake or a dropped TCP connection). A 504 Gateway Timeout means the origin accepted the connection, but took longer to respond than the CDN’s configured timeout limit.
Can I use a self-signed SSL certificate on my origin with a CDN?
Yes, but only if your CDN SSL setting is set to “Full” (unverified) instead of “Strict”. In Strict mode, the CDN edge will reject the self-signed cert and serve a 502 error to your users.
Why does my site work over HTTP but return 502 over HTTPS through the CDN?
Your origin server is likely not listening on port 443, has an incomplete certificate chain, or lacks a virtual host block matching the SNI hostname passed by the edge over HTTPS.
How do I test if my origin firewall is blocking CDN edge IPs?
Tail your origin access logs (e.g., tail -f /var/log/nginx/access.log) while making a request through the CDN. If the CDN returns a 502 and zero log lines appear on your server, your firewall or security group is dropping the CDN’s packets before they reach Nginx.
Next Steps
Once your SSL handshake is reliable, protect your backend against traffic spikes by setting up an origin shield cache architecture.

