Terminating TLS at the CDN edge is a standard practice, but the real magic is how it fundamentally changes the security and performance calculus for your origin servers.

Let’s watch this in action. Imagine a user in London requesting www.example.com/image.jpg.

  1. User’s Browser -> CDN Edge (London): The browser initiates a TLS handshake with the CDN edge server closest to it. This handshake uses the CDN’s certificate, which is valid for www.example.com. The connection is encrypted end-to-end between the user and the CDN.
  2. CDN Edge (London) -> Origin Server: The CDN edge server, having received the unencrypted HTTP request from the user’s browser (because the TLS was terminated at the edge), now needs to fetch image.jpg. It makes a new connection to the origin server. This connection can be either:
    • HTTP: The CDN edge connects to the origin over plain HTTP. This is common if the origin doesn’t have a public-facing certificate or if performance is paramount.
    • HTTPS (Origin-Terminated TLS): The CDN edge initiates a new TLS handshake with the origin server. The origin server presents its own certificate. This is crucial for securing the internal path between the CDN and the origin.

Here’s a simplified view of the CDN configuration that makes this happen.

# CDN Edge Server Configuration Snippet

server {
    listen 443 ssl http2;
    server_name www.example.com;

    # CDN's certificate for www.example.com
    ssl_certificate /etc/nginx/ssl/cdn.example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/cdn.example.com.key;

    # TLS termination happens here.
    # The connection to the origin will be handled by the proxy_pass directive.

    location / {
        proxy_pass https://origin.example.com:443; # Example: Origin uses HTTPS
        # OR
        # proxy_pass http://origin.example.com:80; # Example: Origin uses HTTP

        # If proxy_pass uses HTTPS, the CDN's origin_ssl_certificate
        # and origin_ssl_certificate_key are used for the handshake
        # with the origin.
        # origin_ssl_certificate /etc/nginx/ssl/cdn_to_origin.crt;
        # origin_ssl_certificate_key /etc/nginx/ssl/cdn_to_origin.key;

        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;
    }
}

The problem this solves is twofold: origin load and origin complexity.

  • Origin Load: Every TLS handshake is computationally expensive. By terminating TLS at the CDN edge, you offload all of these handshakes from your origin servers. The CDN, with its specialized hardware and global presence, handles the bulk of the cryptographic work. Your origin servers only need to serve HTTP or establish a single, potentially persistent, TLS connection to the CDN, drastically reducing their CPU load.
  • Origin Complexity: Your origin servers don’t need to manage public-facing SSL certificates for every hostname or subdomain. They might only need one certificate for internal CDN communication, or no certificate at all if the CDN connects via HTTP. This simplifies certificate management, renewal, and deployment significantly.

The crucial lever you control here is the proxy_pass directive and any associated SSL settings for the origin connection. You decide whether the CDN connects to the origin via plain HTTP or a new TLS connection. If it’s TLS, the CDN uses its own set of certificates for that origin connection, distinct from the certificate it presented to the end-user.

When the CDN connects to the origin using HTTPS, it’s performing its own TLS handshake. This handshake involves the CDN presenting a certificate to the origin (if configured) and validating the origin’s certificate. This "inner" TLS connection ensures the data is encrypted between the CDN and the origin, even if the "outer" connection between the user and the CDN was terminated. This internal encryption is vital if your origin is hosted on a less trusted network or if you have compliance requirements.

The most surprising thing about this setup is that the Host header, which the end-user sent to the CDN, is typically forwarded to the origin. This allows the origin server to host multiple hostnames on a single IP address, even if the CDN is handling the public-facing SSL for those hostnames. The CDN’s proxy_set_header Host $host; directive ensures the origin knows which hostname the request was originally intended for.

The next step is understanding how to configure the CDN to use HTTP/2 or HTTP/3 for the connection to the origin server to further optimize performance.

Want structured learning?

Take the full Cdn course →