TLS (Transport Layer Security)
TLS (Transport Layer Security) is the protocol that turns a plain byte stream into a secure channel: the server proves its identity with a certificate, traffic is encrypted, and tampering is detected. HTTP over TLS is HTTPS. TLS 1.3 is current; TLS 1.2 is still required.
Full Explanation
TLS (Transport Layer Security) turns a reliable byte stream into a secure channel: the server proves its identity with a certificate, the traffic is encrypted, and any change made in transit is detected. HTTP carried over that channel is HTTPS. TLS 1.3 is the current version, defined in RFC 8446. TLS 1.2 is older, but not obsolete. BCP 195 is the current best-practice document for TLS. It says implementations MUST support TLS 1.2, SHOULD support TLS 1.3, and MUST prefer 1.3 when they have it.
Three things TLS is not. It is not a cipher. A handshake protocol negotiates the parameters. A record protocol then protects the traffic using them. It is not client identification. The server side of the channel is always authenticated. The client side is authenticated only optionally. That option is what mutual TLS turns on. And it is not a synonym for SSL. SSL 2.0 and SSL 3.0 are its dead predecessors. Implementations MUST NOT negotiate either one (RFC 6176, RFC 7568). The phrase "SSL certificate" still survives in product menus, however. For CDN work, remember one thing: the edge is where TLS ends. That is why the edge is where the certificate lives. It is where the handshake latency and CPU cost are paid. It is where the encrypted leg to your origin either begins, or does not exist at all.
How it works
A TLS connection is negotiated once, then used. The handshake protocol authenticates the peers, negotiates the cryptographic parameters and establishes shared keying material. The record protocol then takes those keys and uses them to protect every byte of application traffic that follows. A TLS 1.3 handshake runs like this.
- The client sends a ClientHello. It offers its protocol versions, its symmetric cipher and hash pairs, and its key-exchange key shares. It also adds extensions: SNI names the hostname it is asking for, and ALPN names the application protocol it wants to speak inside the tunnel.
- The server replies with a ServerHello, choosing from what the client offered. The two key shares then produce the shared secret, normally by (EC)DHE. TLS 1.3 removed the static RSA and static Diffie-Hellman suites. So every key exchange it negotiates provides forward secrecy. If the client offered no group the server will use, the server answers with a HelloRetryRequest instead. That costs one extra round trip.
- The server sends its certificate chain and a CertificateVerify signature. That signature is computed over the whole handshake, with the private key belonging to that certificate. The client accepts the server only if two things hold. The chain must reach a trust anchor the client was configured with. The identity in the certificate must be an acceptable match for the origin in the URL. Every handshake message after the ServerHello is already encrypted.
- Both sides send Finished, a MAC over the entire handshake. It confirms that both ends derived the same keys. It also binds each endpoint's identity to those keys. Because it covers the whole transcript, an active attacker cannot push the peers into parameters they would not have chosen unattacked.
TLS 1.3 calls that ordinary handshake the 1-RTT handshake. The client can send its request one round trip after it starts. The server may then issue a session ticket. A returning client that presents it resumes with a pre-shared key, instead of a fresh certificate exchange. It can go one step further with 0-RTT. That means sending application data in the very first flight. Doing so saves that remaining round trip at connection setup, in exchange for weaker security properties. QUIC is the transport under HTTP/3. It reuses this same handshake and nothing older: clients MUST NOT offer TLS versions below 1.3.
Why it matters for a CDN
A CDN is a TLS termination point. It holds a certificate for your hostname. It completes the handshake with the visitor at an edge server near them. So your origin never negotiates TLS with the public. The browser sees one HTTPS connection. But that connection is really two independent legs: visitor-to-edge and edge-to-origin. Every property you care about has to hold on both.
- The round trip moves closer to the user. A handshake costs at least one round trip before the request can be sent. It also costs a public-key signature on the server. Terminating a few milliseconds from the visitor takes that round trip off the long path to the origin. The edge can then carry the request onward over a connection it already has open.
- One address, many certificates. An edge IP fronts thousands of unrelated hostnames. So it needs to know the hostname before it can choose a certificate. That is what SNI is for: it supports deployment of multiple TLS-protected virtual servers on a single address, and a server receiving it may use it to guide certificate selection.
- Your "server" is a fleet. Several servers can offer the same service with different TLS configurations. Where that happens, an attacker can steer a client toward whichever one is weakest. So BCP 195 says providers SHOULD ensure that all servers providing the same service provide equivalent levels of security. In practice, a version change or a replacement certificate is a fleet-wide rollout. It is not in effect until the last edge node has it.
- Certificates expire faster every year. The CA/Browser Forum Baseline Requirements now cap publicly trusted TLS certificates at 200 days for certificates issued on or after 15 March 2026. The cap drops to 100 days from 15 March 2027, and to 47 days from 15 March 2029. At that cadence, renewal has to be automated, normally with ACME. The CDN has to be inside that automation, rather than a manual step beside it.
What CDNs do
- Cloudflare terminates at the edge. Custom certificates are a Business and Enterprise feature. For those, Cloudflare encrypts the private key and distributes it to all of its data centres, so termination happens locally. Geo Key Manager restricts where those keys may be used. Keyless SSL retains the key on your own infrastructure instead. The edge-to-origin leg is a separate setting. Migrated zones default to Automatic SSL/TLS. That mode probes the origin, applies the most secure encryption mode it supports, and will not move to a less secure one on its own. The manual modes run from Flexible, which is cleartext to the origin, through Full, which is HTTPS without validating the origin certificate, to Full (strict) and Strict, which do validate it.
- Fastly terminates per domain. You upload a key and certificate, or let Fastly obtain and manage one. Then you enable that domain on the certificate before Fastly will terminate for it. TLS 1.3 is now its default TLS version, with a documented downgrade to TLS 1.2 for older clients. Fastly supports 0-RTT only between itself and clients, not between itself and your origin. By default it answers only idempotent requests over 0-RTT: GET and HEAD without query parameters.
- AWS CloudFront terminates on the distribution. Termination is governed by a security policy that fixes the minimum protocol version and the viewer cipher list. Every policy in its table offers TLS 1.3. TLSv1.3_2025 offers only TLS 1.3. Older policies additionally permit TLS 1.1, TLS 1.0 or SSLv3. You pick the policy only when you attach a custom certificate. With the default *.cloudfront.net certificate, CloudFront sets it to TLSv1 for you. A distribution on dedicated-IP legacy client support is limited to TLSv1 or SSLv3, unless AWS Support changes it. CloudFront does not document 0-RTT early data.
Watch out for
- 0-RTT is not a free round trip. RFC 8446 is explicit that early data is not forward secret and has no guarantees of non-replay between connections. It goes further: an application protocol MUST NOT use 0-RTT data without a profile that defines its use. For HTTP, that profile is RFC 8470. An intermediary forwarding a request before its client handshake finished MUST send it with Early-Data: 1. A server unwilling to risk a replay answers 425 (Too Early). If you switch 0-RTT on at the edge, confirm your origin handles both.
- TLS 1.0 and 1.1 are deprecated. Unused is not the same as unoffered. RFC 8996 moved both to Historic, because they lack support for current recommended algorithms. BCP 195 says implementations MUST NOT negotiate them. One edge node, or one legacy security policy, that still accepts TLS 1.0 is the one an attacker will aim at.
- Terminating TLS does not encrypt what happens next. The edge-to-origin leg can be cleartext, as in Cloudflare's Flexible mode. If it is, anything on the path between the CDN and your origin can read and rewrite it. Meanwhile the padlock in the browser still looks perfect.
- Validating the origin is a separate decision from encrypting to it. HTTPS to the origin without certificate validation stops passive reading. It does not stop an attacker who can answer in the origin's place. That is the whole difference between Cloudflare's Full and Full (strict).
- Certificate and hostname mistakes fail closed. A certificate can be expired, or its identity can fail to match the hostname requested. Either mistake causes a hard handshake failure, not a degraded page. A replacement only counts once it has propagated to every edge location.
- Older options carry older limits. Cloudflare's Keyless SSL, for instance, is an Enterprise paid add-on. It does not support TLS 1.3. So choosing it constrains the protocol you can offer.
- TLS is not metadata privacy. It does not hide the length of the data it transmits. It is susceptible to traffic analysis based on observing the length and timing of encrypted packets. Record padding exists, but an application has to ask for it. Object sizes and request patterns still leak. That matters most when an edge serves a small, fixed catalogue.
Best practice
- Support TLS 1.2 and TLS 1.3, and prefer 1.3. Refuse SSL 2.0, SSL 3.0, TLS 1.0 and TLS 1.1 outright, as BCP 195 requires.
- Set the minimum version and cipher list explicitly at the edge, for example with a CloudFront security policy. Do not just inherit whatever a default allows. Apply the same configuration everywhere, so no node is the weak one.
- Re-encrypt the edge-to-origin leg with its own TLS session. Validate the origin certificate too, rather than only encrypting to it.
- Restrict 0-RTT to requests that are safe to replay. Keep the RFC 8470 signalling intact all the way to the origin. Leave it off for anything that changes state.
- Automate issuance and renewal with ACME. Monitor expiry independently of the CDN, because the maximum certificate lifetime is on a published schedule, down to 47 days.
- Pair TLS with HSTS, so browsers stop attempting cleartext in the first place. BCP 195 says web servers SHOULD use HSTS to indicate they accept TLS-only clients.
Examples
# Check TLS version and cipher
$ curl -vI https://example.com 2>&1 | grep -E 'SSL|TLS'
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
# Nginx: modern TLS config
server {
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_certificate /etc/ssl/cert.pem;
ssl_certificate_key /etc/ssl/key.pem;
# HSTS: tell browsers to always use HTTPS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}
# Test SSL config
$ openssl s_client -connect example.com:443 -tls1_3
# Or use ssllabs.com for a full audit
Frequently Asked Questions
TLS (Transport Layer Security) is the protocol that turns a plain byte stream into a secure channel: the server proves its identity with a certificate, traffic is encrypted, and tampering is detected. HTTP over TLS is HTTPS. TLS 1.3 is current; TLS 1.2 is still required.
# Check TLS version and cipher
$ curl -vI https://example.com 2>&1 | grep -E 'SSL|TLS'
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
# Nginx: modern TLS config
server {
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_certificate /etc/ssl/cert.pem;
ssl_certificate_key /etc/ssl/key.pem;
# HSTS: tell browsers to always use HTTPS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}
# Test SSL config
$ openssl s_client -connect example.com:443 -tls1_3
# Or use ssllabs.com for a full audit
Related CDN concepts include:
- SNI (Server Name Indication) (SNI) — A TLS extension that carries the hostname the client wants inside the plaintext ClientHello, so …