CDN SSL/TLS Configuration Best Practices: Balancing Security and Performance
When a CDN handles HTTPS traffic, its SSL/TLS configuration decides two things: how safe the data is between the edge node and the user, and how many network round trips the handshake costs. These are often framed as an either/or — security or speed — but a well-tuned TLS config can deliver both at once. It comes down to four pieces: certificates, protocol versions, cipher suites, and session reuse.
1. Certificate Selection and Deployment
1.1 Choosing a Certificate Type
| Certificate Type | Use Case | Validation Level | Cost |
|---|---|---|---|
| DV (Domain Validation) | Personal/small sites | Low | Free-Low |
| OV (Organization Validation) | Business sites | Medium | Medium |
| EV (Extended Validation) | Finance/E-commerce | High | High |
| Wildcard certificate | Multiple subdomains | Varies | Med-High |
For the vast majority of content sites, a DV certificate is enough. The padlock in the address bar and the absence of the "not secure" warning are covered by both DV and EV; OV/EV mainly add organization info shown to visitors, and their effect on conversion is small. Worth noting: browser vendors have been removing the green-bar EV display from the address bar, further shrinking EV's "trust signal" — so you can comfortably start with DV.
1.2 Certificate Management on the CDN
Prefer automatic management — it's less work and never expires silently:
Cloudflare: Auto SSL
AWS CloudFront: ACM auto-renewal
Azure: App Service managed certificates
Alibaba Cloud: Free DV certificates
If you upload manually, include the full intermediate chain — uploading only the leaf cert produces "incomplete certificate chain" errors, and some older clients will refuse the connection outright.
1. Purchase or generate certificate from CA
2. Upload to CDN console
3. Configure certificate chain (full chain)
4. Set up auto-renewal reminders
1.3 Let's Encrypt Integration
Most CDNs support automatic Let's Encrypt issuance:
- Cloudflare: built-in free cert with auto-renewal
- Bunny CDN: auto Let's Encrypt
- AWS: import via ACM
Reference: Let's Encrypt docs https://letsencrypt.org/docs/; Cloudflare SSL guide https://developers.cloudflare.com/ssl/
2. TLS Protocol Version Configuration
| Protocol | Security | Performance | Recommendation |
|---|---|---|---|
| TLS 1.3 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ✓ Enable |
| TLS 1.2 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ✓ Enable |
| TLS 1.1 | ⭐⭐⭐ | ⭐⭐⭐ | ✗ Disable |
| TLS 1.0 | ⭐⭐ | ⭐⭐ | ✗ Disable |
| SSL 3.0 | ✗ | ⭐ | ✗ Disable |
The biggest TLS 1.3 change is the handshake: it shrinks from 1-RTT to 0-RTT with session resumption, saving 1-2 round trips. On mobile networks each round trip can be 50-100ms of perceived difference.
Cloudflare: SSL/TLS → Edge Certificates → Minimum TLS Version: 1.2
CloudFront: Security Policy → TLSv1.2_2021
Nginx + CDN: ssl_protocols TLSv1.2 TLSv1.3;
Going from "allow TLS 1.0" to "minimum 1.2" while keeping 1.3 is today's sweet spot for compatibility and security. Unless your audience includes very old browsers (IE on Windows XP era), there's no reason to leave 1.0/1.1 on.
One detail people miss is 0-RTT in TLS 1.3: it saves a handshake but introduces replay risk. For order and payment endpoints that need idempotency, disable it or allow it only on GETs, so a captured request can't be replayed.
3. Cipher Suite Configuration
TLS 1.3 cipher suites are mandatory and need no config; the effort goes into TLS 1.2, where you shouldn't trust the default order:
# TLS 1.3 Cipher Suites (no configuration needed)
TLS_AES_128_GCM_SHA256
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
# TLS 1.2 Cipher Suites (recommended)
ECDHE-ECDSA-AES128-GCM-SHA256
ECDHE-RSA-AES128-GCM-SHA256
ECDHE-ECDSA-CHACHA20-POLY1305
ECDHE-RSA-CHACHA20-POLY1305
Always prioritize ECDHE (forward secrecy) with GCM or ChaCha20. RSA static keys, CBC, RC4, and 3DES either lack forward secrecy or have known attacks — disable them:
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
All RC4, 3DES, CBC mode ciphers
Reference: Mozilla SSL config generator https://ssl-config.mozilla.org/; TLS 1.3 RFC 8446 https://datatracker.ietf.org/doc/html/rfc8446
4. Performance Optimization
4.1 OCSP Stapling
By default the client checks certificate revocation status with the CA (an OCSP request) after receiving the cert. OCSP Stapling has the CDN do that lookup and staple the result into the handshake response, so the client skips the extra request:
# Nginx Configuration
ssl_stapling on;
ssl_stapling_verify on;
4.2 Session Resumption
When the same user opens many connections (a page with dozens of resource requests), session reuse drops later handshakes to 1-RTT or even 0-RTT:
# Nginx Configuration
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets on;
4.3 HSTS
HSTS tells browsers "HTTPS only from now on," eliminating downgrade attacks at the root and saving the round trip of a 301 redirect:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Reference: MDN HSTS https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
5. CDN Configuration Reference
| CDN | Certificate Management | Min TLS | HSTS Support | OCSP |
|---|---|---|---|---|
| Cloudflare | Free automatic | Configurable | ✓ | ✓ |
| CloudFront | ACM free | Configurable | ✓ | ✓ |
| Fastly | Requires upload | Configurable | ✓ | ✓ |
| Alibaba Cloud CDN | Free/upload | Configurable | ✓ | ✓ |
| Bunny CDN | Let's Encrypt | TLS 1.2+ | ✓ | ✓ |
6. A Troubleshooting Case
A site was snappy for Chrome users but showed "connection not secure" for a slice of older Android WebView clients. Logs showed those clients were still on TLS 1.0/1.1 and only understood CBC suites. Setting the CDN minimum to 1.2 made that whole group unable to connect — the config wasn't wrong, the audience simply had legacy clients. The best prevention for this class of problem is a full scan at https://www.ssllabs.com/ before launch, so you know exactly which client versions you're choosing not to serve. The fix: minimum 1.2 globally, with a temporary 1.1 allowlist domain for legacy clients, tightened up after a six-month transition.
16IDC Tips
- Test on a staging domain first and run it through SSL Labs before going to production.
- HSTS preload is hard to undo once submitted — run
max-age=31536000without preload for a few months first. - Most CDN consoles alert you near certificate expiry; mirror the reminder to both email and Slack as a belt-and-suspenders measure.
- Run sslscan or cipherscan periodically against production, aligned with the CDN's version upgrade plan — don't wait for a vulnerability announcement to remember.