2026年11月14日
2026年11月14日
Nginx SSL Session Cache: ssl_session_cache Setup and Resumption Tests
This article is a localized edition of the Japanese original. Read the Japanese original
The Nginx SSL session cache lets a browser that has already completed a TLS connection reconnect in fewer steps by reusing the result of the previous key exchange (session resumption). The configuration centers on two lines, ssl_session_cache and ssl_session_timeout; put them in the http block and they apply to every HTTPS site.
Here is the short answer.
http {
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1h;
# ssl_session_tickets is on by default
}
shared:SSL:10mis a 10MB cache shared by all worker processes. According to the official documentation, 1MB stores about 4,000 sessions.- The default for
ssl_session_timeoutis 5 minutes. Extend it to match how often visitors return. - Since Nginx 1.23.2, when a shared cache is configured, the TLS session ticket keys are also generated, stored and periodically rotated inside it. Reloading the configuration no longer invalidates tickets.
- To confirm resumption, check that
openssl s_clientprintsReused, or that$ssl_session_reusedin the access log isr.
The behavior in this article was tested with Nginx 1.30.6 (OpenSSL 3.5.7) as of November 2026.
Two ways to resume a session
TLS session resumption comes in two forms: the server keeps the session state, or the client carries it.
| Method | How it works | Nginx setting |
|---|---|---|
| Session ID (cache) | The server stores session state in a cache, and the client sends the ID to resume | ssl_session_cache |
| Session ticket | The server encrypts the session state and hands it to the client, which presents it to resume | ssl_session_tickets, ssl_session_ticket_key |
In TLS 1.3, resumption data is delivered as a "ticket" the server sends after the handshake. With Nginx (OpenSSL), TLS 1.3 resumption still worked with ssl_session_tickets off as long as a shared cache existed, using tickets that keep the state on the server side (verified in the test steps below).
What each directive means and its default
This is a summary of the official documentation (ngx_http_ssl_module). Each directive can go in the http or server block.
ssl_session_cache
The syntax is ssl_session_cache off | none | [builtin[:size]] [shared:name:size]; and the default is none.
| Value | Meaning |
|---|---|
off |
Strictly prohibits the cache and tells clients that sessions may not be reused |
none (default) |
Tells clients sessions may be reused but does not actually store them in a cache |
builtin[:size] |
OpenSSL's built-in cache. Separate per worker process; size is in sessions (20480 if omitted). Can cause memory fragmentation |
shared:name:size |
A cache shared by all workers. Size is in bytes; 1MB holds about 4,000 sessions. The same name can be used in several server blocks |
The official documentation says builtin and shared can be combined, but using only shared should be more efficient. The cache name (SSL in the example) is any string you like.
ssl_session_timeout
This is how long a client can reuse a session. The default is 5m (5 minutes). A longer value raises the share of returning visitors who can resume, but more sessions stay in the cache, so review the cache size at the same time. When the cache fills up, the oldest entries are discarded.
ssl_session_tickets
This turns resumption through session tickets on or off; the default is on. Even without a shared cache, resumption works while tickets are enabled. In that case, though, the ticket key is generated at random at startup, so the key changes on every configuration reload or restart, and earlier tickets stop working. With a shared cache configured (1.23.2 and later), the key is stored in the cache, rotated periodically and carried over across reloads.
ssl_session_ticket_key
This specifies a file holding the key that encrypts tickets. It is meant for when several servers must share the same key; on a single server you do not need it. The file is 80 bytes (AES256) or 48 bytes (AES128) of random data, created like this.
sudo openssl rand 80 | sudo tee /etc/nginx/ticket_current.key > /dev/null
sudo chmod 600 /etc/nginx/ticket_current.key
If you list several keys, only the first is used to encrypt, and the rest are used only to decrypt. Use this to rotate keys.
ssl_session_ticket_key /etc/nginx/ticket_current.key;
ssl_session_ticket_key /etc/nginx/ticket_previous.key;
If this key leaks, the security of connections that used tickets encrypted with it is compromised. Make the key files readable only by root, and if you cannot rotate them on a regular schedule yourself, skip this directive and rely on the automatic rotation of the shared cache.
Recommended configuration
This example is for a single web server running WordPress or similar. Put it in the http block of /etc/nginx/nginx.conf (or at the top of a file in conf.d).
http {
# Session cache shared by all workers (10MB holds about 40,000 sessions)
ssl_session_cache shared:SSL:10m;
# How long a session can be reused (default 5 minutes)
ssl_session_timeout 1h;
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# ...
}
}
After editing, check the syntax and then reload.
sudo nginx -t
sudo systemctl reload nginx
If you write ssl_session_cache in each server block and run several sites on the same IP and port, the value from the default server may be used. To use the same value for all sites, the clearest approach is to write it once in the http block.
How this differs from settings seen in older articles
- OCSP stapling such as
ssl_stapling on;is a mechanism for checking certificate revocation and has nothing to do with the session cache. Also, Let's Encrypt shut down its OCSP service in August 2025, sossl_staplingdoes not work with its certificates. - Connection lists such as
ss -tando not show the state of the session cache. Use the methods in the next section instead.
Verifying session resumption
Check with openssl s_client (TLS 1.2)
With -reconnect, the client reconnects 5 times using the same session. If the first line is New and the rest are Reused, resumption works.
echo | openssl s_client -connect example.com:443 -servername example.com -tls1_2 -reconnect 2>/dev/null | grep -E '^(New|Reused),'
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Reused, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Reused, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
(remaining lines omitted)
Check with openssl s_client (TLS 1.3)
In TLS 1.3 the resumption ticket arrives after the handshake, so with -reconnect every line showed New. Save the session to a file on the first connection and use it for the second. The sleep 1 | keeps the connection from closing before the ticket is received.
sleep 1 | openssl s_client -connect example.com:443 -servername example.com -sess_out /tmp/tls13.sess > /dev/null 2>&1
sleep 1 | openssl s_client -connect example.com:443 -servername example.com -sess_in /tmp/tls13.sess 2>/dev/null | grep -E '^(New|Reused),'
If you see Reused, TLSv1.3, …, resumption works.
Check in the access log
To see whether real visitors resume sessions, log the variable $ssl_session_reused (r if resumed, . otherwise).
http {
log_format tls '$remote_addr [$time_local] "$request" $status '
'$ssl_protocol $ssl_session_reused';
server {
# ...
access_log /var/log/nginx/tls.log tls;
}
}
# Get a rough count of resumed connections
awk '{print $NF}' /var/log/nginx/tls.log | sort | uniq -c
Note that browsers reuse the same connection (keep-alive, HTTP/2), so the value becomes r only when a new TLS connection is established.
Behavior confirmed in testing
These are the results of checking resumption for each combination of settings on Nginx 1.30.6.
| Settings | TLS 1.2 | TLS 1.3 | Resumption after reload |
|---|---|---|---|
| No cache, tickets default (on) | Resumes | Resumes | Does not resume (key is regenerated) |
No cache, ssl_session_tickets off |
Does not resume | Does not resume | — |
shared:SSL:10m, tickets default (on) |
Resumes | Resumes | Resumes |
shared:SSL:10m, ssl_session_tickets off |
Resumes | Resumes | — |
Ticket-based resumption works even with the defaults, but configuring a shared cache keeps resumption from breaking on every reload.
Notes for multi-server setups
When several Nginx servers sit behind a load balancer, each session cache exists only inside its own server.
- If a client's connection is routed to a different server, neither the cache nor tickets can resume it, and a full handshake takes place (the connection still succeeds, just a little slower).
- To resume across all servers, place the same key file on every server with
ssl_session_ticket_key, and rotate it on all of them at the same time. - If the load balancer terminates HTTPS, TLS session resumption is configured on the load balancer, and these Nginx settings do not apply.
FAQ
How large should the cache be?
As a guide, 1MB holds about 4,000 sessions, so estimate from the number of new visitors who connect within ssl_session_timeout. For a typical site, 10m is usually enough, and it uses 10MB of memory.
Should ssl_session_tickets be off?
Some configuration guides recommend off, on the grounds that if the ticket key stays unchanged for a long time, a leaked key would also affect past traffic. With Nginx 1.23.2 or later and a shared cache, the key is rotated automatically. Even with it off, as the tests show, a shared cache lets both TLS 1.2 and 1.3 resume.
Do I need to clear the cache after renewing a certificate?
No. After renewing, run nginx -t and systemctl reload nginx, and new connections will use the new certificate.
Summary
- The basic setup is
ssl_session_cache shared:SSL:10m;plusssl_session_timeoutin thehttpblock; extend the 5-minute default as needed. - With a shared cache, Nginx 1.23.2 and later store and rotate ticket keys automatically. Use
ssl_session_ticket_keywhen several servers must share a key. - Verify with
openssl s_client -reconnectfor TLS 1.2,-sess_outand-sess_infor TLS 1.3, and$ssl_session_reusedfor real visitors.
Related articles:
- Setting up SSL/TLS and HTTPS in Nginx
- Configuring the Apache SSL session cache
- Enabling HTTP/2 in Nginx
References: nginx – ngx_http_ssl_module, OpenSSL – openssl-s_client, Let's Encrypt – Ending OCSP Support in 2025
Revision history: 2026-11-10 full revision (removed descriptions of nonexistent uses, ssl_stapling steps unrelated to the session cache, and an incorrect check using ss; replaced them with each directive's default, ticket keys, and tested resumption checks).
Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)