What TLS Termination Means
TLS termination means nginx is the endpoint that performs the actual TLS handshake with the client — negotiating the cipher suite, validating the certificate chain, and decrypting incoming traffic — before forwarding the now-plaintext request onward, typically over a private network to a backend that never has to handle certificates or TLS negotiation at all. Centralizing this at nginx means certificate renewal, protocol version support, and cipher policy are managed in exactly one place instead of being duplicated (and inevitably drifting out of sync) across every backend service.
Cricket analogy: It's like a stadium's single accredited security checkpoint verifying every spectator's ticket and ID before they enter, so individual gate stewards inside the ground never need to check credentials themselves.
Configuring Certificates
server {
listen 443 ssl;
server_name secure.example.com;
ssl_certificate /etc/nginx/ssl/secure.example.com.fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/secure.example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1h;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security "max-age=63072000" always;
location / {
proxy_pass http://127.0.0.1:3000;
}
}
server {
listen 80;
server_name secure.example.com;
return 301 https://$host$request_uri;
}A minimal TLS-terminating server block listens on port 443 with the ssl parameter, points ssl_certificate at the full certificate chain (leaf plus intermediates, in that order) and ssl_certificate_key at the corresponding private key file, and typically pairs with a second server block on port 80 that issues a permanent redirect to the HTTPS version of the same host so plaintext requests never linger. Keeping the private key file readable only by root or the nginx user, and never committing it to version control, is a baseline operational requirement rather than an optional hardening step.
Cricket analogy: It's like a ground's official gate needing both the printed match ticket and the matching ID card presented together — one without the other, and security won't let you through, just as a cert without its matching private key can't complete a handshake.
Hardening Protocols and Ciphers
Modern nginx TLS configuration should explicitly restrict ssl_protocols to TLSv1.2 and TLSv1.3, disabling the long-deprecated SSLv3, TLSv1.0, and TLSv1.1 which carry known vulnerabilities like POODLE and BEAST; ssl_ciphers further narrows the negotiable cipher suites to modern authenticated-encryption options, typically letting TLSv1.3 use its own hardcoded strong suite set. Adding the Strict-Transport-Security response header (HSTS) with a long max-age tells browsers to refuse ever connecting to the site over plain HTTP again for the specified duration, closing the window for downgrade or SSL-stripping attacks even if a user types the bare domain without https://.
Cricket analogy: It's like a board banning outdated protective gear that's failed modern safety testing, mandating only certified helmets and pads that meet the current standard for every player stepping onto the field.
Re-Encryption and Handshake Performance
Terminating TLS at nginx and forwarding plaintext to the backend is simplest and fastest, but in environments requiring encryption for the entire path (common in PCI-DSS or zero-trust network setups), nginx can instead re-encrypt the request with a second, separate TLS session to the backend using proxy_pass https:// along with proxy_ssl_certificate directives — this costs more CPU for the extra handshake but ensures traffic is never in plaintext anywhere on the wire. Independent of that choice, enabling ssl_session_cache and ssl_session_tickets lets nginx resume a previous client's TLS session without a full handshake on reconnect, and ssl_stapling lets nginx include a cached OCSP revocation response in its own handshake so clients don't need a separate round trip to a certificate authority to check revocation status.
Cricket analogy: Re-encrypting to the backend is like a ground running two separate, independently verified security checks — one at the outer gate and another at the inner pavilion door — rather than trusting the outer check alone for the entire venue.
ssl_stapling requires nginx to be able to reach the certificate authority's OCSP responder itself (usually via resolver + a DNS resolver directive) so it can fetch and cache the signed revocation response to staple into future handshakes; if that lookup fails, nginx falls back to handshakes without a stapled response rather than failing requests outright.
Terminating TLS but forwarding plaintext to backends over a network segment you don't fully control (rather than a private VPC or loopback interface) exposes decrypted traffic to interception between nginx and the backend, defeating much of the purpose of using HTTPS in the first place.
- TLS termination means nginx performs the client-facing handshake and decryption, centralizing certificate and cipher management in one place.
- ssl_certificate must point to the full chain (leaf plus intermediates) and ssl_certificate_key to the matching private key.
- A plain-HTTP server block should redirect to HTTPS with a 301 so plaintext requests never linger.
- ssl_protocols should be restricted to TLSv1.2 and TLSv1.3, disabling deprecated versions vulnerable to POODLE and BEAST.
- HSTS (Strict-Transport-Security) tells browsers to never connect over plain HTTP again for the specified max-age.
- Re-encrypting to the backend with proxy_pass https:// secures the full path but costs extra CPU for a second handshake.
- ssl_session_cache and ssl_stapling improve handshake performance by enabling session resumption and cached OCSP responses.
Practice what you learned
1. What does 'TLS termination' mean in the context of an nginx reverse proxy?
2. What should ssl_certificate point to?
3. Why should ssl_protocols be restricted to TLSv1.2 and TLSv1.3?
4. What does the Strict-Transport-Security (HSTS) header instruct browsers to do?
5. When would you re-encrypt traffic with proxy_pass https:// to the backend instead of forwarding plaintext?
Was this page helpful?
You May Also Like
Reverse Proxy Basics
Learn what a reverse proxy does, how nginx's proxy_pass directive rewrites request paths, and how to preserve client context with forwarded headers.
Upstream Servers and Health Checks
Configure nginx upstream pools with passive and active health checks, backup servers, and persistent keepalive connections.
Load Balancing Algorithms
Understand nginx's round robin, weighted round robin, least_conn, and ip_hash load-balancing algorithms and when to use each.
Related Reading
Related Study Notes in DevOps
Browse all study notesAnsible Study Notes
DevOps · 30 topics
DevOpsAdvanced Kubernetes Study Notes
Kubernetes · 30 topics
DevOpsAdvanced Bash Scripting Study Notes
Bash · 30 topics
DevOpsApache Kafka Study Notes
Kafka · 30 topics
DevOpsDocker & Kubernetes Study Notes
YAML · 40 topics
DevOpsCI/CD Tools & Pipelines Study Notes
YAML · 37 topics