Skip to content

TLS Termination

Real traffic is almost never plain HTTP. Nginx is typically the place the TLS handshake actually happens — the app behind it often never sees an encrypted connection at all.

TL;DR — in 30 seconds:

  • When nginx terminates TLS, it completes the client's handshake itself and talks to the app behind it in plain HTTP over a trusted internal network — the app never holds a certificate.
  • Three directives in a server block do it: listen 443 ssl, ssl_certificate, and ssl_certificate_key.
  • Redirecting HTTP → HTTPS needs its own server block on port 80 — a TLS-only listener can't accept the unencrypted connection needed to issue that redirect.

1. What "terminating TLS" means

When nginx terminates TLS, it is the endpoint the client's TLS handshake actually completes with: nginx decrypts the incoming HTTPS connection, and from that point on can talk to the app behind it in plain HTTP over a trusted internal network. The app itself never has to hold a certificate or handle a handshake at all.

sequenceDiagram
    participant Client
    participant N as nginx
    participant App as Upstream app
    Client->>N: TLS handshake (HTTPS)
    N-->>Client: Encrypted connection established
    N->>App: Plain HTTP request
    App-->>N: Plain HTTP response
    N-->>Client: Encrypted response

2. The directives that make it possible

Directive What it does
listen 443 ssl Opens an HTTPS listener on this server block
ssl_certificate Path to the certificate (public key) presented to the client
ssl_certificate_key Path to the matching private key

These three directives, inside a server block, are the minimum needed for that server block to terminate TLS for incoming connections.

3. The HTTP → HTTPS redirect

A plain-HTTP server block on port 80 exists purely to send clients on to HTTPS — it accepts the unencrypted connection first (a TLS-only listener can't even receive it), then issues a redirect:

server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

This is a separate server block, not a directive added to the port-443 one — the redirect has to be served over plain HTTP, before any TLS handshake with that block could even begin.

4. How this connects

  • Once TLS is terminated, what nginx does with the now-decrypted request is exactly the routing and proxying covered in Reverse proxy & static content and the next page, Proxying & load balancing.
  • The TLS handshake itself sits on top of the TCP handshake covered in the Networking module's HTTP/TCP/SSH page — nginx's listen 443 ssl is doing, at the application layer, what that page described in the abstract.

You can defend this when you can explain what changes for the app behind nginx once TLS is terminated at nginx (rather than passed through), and why the HTTP→HTTPS redirect needs its own server block.