{"id":1224,"date":"2026-09-25T22:34:57","date_gmt":"2026-09-25T22:34:57","guid":{"rendered":"https:\/\/virtualserversvps.com\/blog\/?p=1224"},"modified":"2026-09-25T22:34:57","modified_gmt":"2026-09-25T22:34:57","slug":"tls-session-resumption-ocsp-stapling-single-vcpu-vps","status":"publish","type":"post","link":"https:\/\/virtualserversvps.com\/blog\/tls-session-resumption-ocsp-stapling-single-vcpu-vps\/","title":{"rendered":"TLS Session Resumption and OCSP Stapling on a Single-vCPU VPS: Reduce Handshake CPU Without Weakening Security"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">On a small VPS, the RSA or ECDSA signing operation in a TLS 1.3 handshake is often the most expensive thing your CPU does per request. Full handshakes from cold clients can consume 5&ndash;15% of a single vCPU at just a few hundred requests per second. The fix is not a larger instance &mdash; it is session resumption, ticket key rotation, and OCSP stapling configured so that the expensive asymmetric work happens once per client rather than once per connection. This is the configuration and the measurement to prove it worked.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Where the CPU Actually Goes<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In TLS 1.3, a full handshake costs one or two signature operations on the server plus a key exchange. An abbreviated handshake via PSK resumption costs a symmetric operation and no signature at all. Measure the difference directly:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># openssl speed: know your signature cost before tuning\nopenssl speed -seconds 2 rsa2048 ecdsap256        # legacy paths\n# on a 1-vCPU KVM guest: rsa2048 ~50-120 sign\/s, ecdsap256 ~600-1500 sign\/s\n\n# full handshake vs resumption, per-connection cost\nfor i in 1 2 3; do\n  openssl s_client -connect example.com:443 -tls1_3 -no_ticket \/dev\/null \\\n    | grep -i 'New, TLSv1.3'\n  openssl s_client -connect example.com:443 -tls1_3 \/dev\/null \\\n    | grep -i 'Reused, TLSv1.3'\ndone<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Track server-side resumption rate rather than guessing. Nginx exposes it through the log format; Prometheus through <code>nginx_vts<\/code> or the stub_status counters:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># nginx: add resumption indicators to the access log\nlog_format tls '$remote_addr $ssl_protocol $ssl_curve $ssl_session_reused '\n               '$ssl_session_id \"$request\" $request_time';\naccess_log \/var\/log\/nginx\/tls.log tls;\n\n# what fraction of connections resumed?\nawk '{print $4}' \/var\/log\/nginx\/tls.log | sort | uniq -c | sort -rn\n# expect \"r\" (reused) to dominate for repeat visitors<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Session Tickets: Rotation Without Breaking Resumption<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">TLS 1.3 uses stateless session tickets, so no server-side cache is needed &mdash; but the ticket key must be shared across workers and rotated on a schedule (Nginx uses a 128-bit key plus a 4-byte name). The classic mistake is enabling tickets with the default single key and never rotating, which lets a stolen key decrypt recorded sessions indefinitely:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \/etc\/nginx\/nginx.conf\nssl_session_cache   shared:SSL:20m;    # 20 MB ~ 80k sessions per worker set\nssl_session_timeout 4h;\nssl_session_tickets on;\n\n# TLS 1.3 requires an explicit ticket key for stable resumption across\n# reloads and multi-worker setups on older nginx builds:\nssl_session_ticket_key \/etc\/nginx\/ticket.key;   # 80 bytes, mode 0600\n\n# generate with correct entropy and permissions\nsudo head -c 80 \/dev\/urandom &gt; \/etc\/nginx\/ticket.key\nsudo chmod 600 \/etc\/nginx\/ticket.key\nsudo chown root:root \/etc\/nginx\/ticket.key<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Rotate the key on a schedule, keeping the previous key for one full <code>ssl_session_timeout<\/code> window so in-flight sessions remain resumable:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\n# \/etc\/cron.monthly\/rotate-ticket-key\nset -euo pipefail\nKEY=\/etc\/nginx\/ticket.key\ncp -p \"$KEY\" \"${KEY}.old\"\nhead -c 80 \/dev\/urandom &gt; \"$KEY.new\"\nchmod 600 \"$KEY.new\"; chown root:root \"$KEY.new\"\nmv \"$KEY.new\" \"$KEY\"\nnginx -t &amp;&amp; systemctl reload nginx\n# remove the .old key after ssl_session_timeout has elapsed \u2014 nginx\n# keeps it in memory for the running generation only\nfind \/etc\/nginx -name 'ticket.key.old' -mtime +1 -delete<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">OCSP Stapling: Remove the Client-Side Fetch<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Without stapling, a client must contact the CA&#8217;s OCSP responder, adding a round trip and, more importantly for you, adding a dependency that fails when the responder is slow &mdash; a common cause of intermittent TLS stalls. Stapling embeds a signed, cached OCSP response in the handshake. Verify it works before and after:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \/etc\/nginx\/conf.d\/tls.conf\nssl_stapling on;\nssl_stapling_verify on;\nssl_trusted_certificate \/etc\/nginx\/ca-chain.pem;   # full chain incl. root\nresolver 1.1.1.1 [2606:4700:4700::1111] valid=300s ipv6=off;\nresolver_timeout 5s;\n\n# verify: look for a non-empty \"OCSP Response Status: successful\"\nopenssl s_client -connect example.com:443 -status -servername example.com \/dev\/null \\\n  | sed -n '\/OCSP Response Status\/,\/^---\/p'\n\n# if it says \"no response sent\", check the nginx error log \u2014 usually a\n# missing ssl_trusted_certificate or an unreachable resolver<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Configuration<\/th><th>Handshake CPU (1 vCPU)<\/th><th>Client-visible latency<\/th><\/tr><\/thead><tbody><tr><td>Full handshake, RSA-2048, no stapling<\/td><td>~1.0x baseline<\/td><td>+1 RTT to OCSP responder<\/td><\/tr><tr><td>Full handshake, ECDSA P-256<\/td><td>~0.15x of RSA cost<\/td><td>+1 RTT<\/td><\/tr><tr><td>Resumption enabled, ECDSA<\/td><td>~0.03x<\/td><td>0 extra RTT<\/td><\/tr><tr><td>Resumption + stapling, ECDSA<\/td><td>~0.03x<\/td><td>0 extra RTT, no CA dependency<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Measure the Effect Properly<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use a load test that includes a realistic mix of new and returning clients, and watch CPU, not just requests per second:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># 30s run, 50 connections, HTTP\/2, TLS 1.3, ECDSA certificate\nh2load -n 30000 -c 50 -m 10 --tls13 https:\/\/example.com\/ -t 2\n\n# CPU consumed by nginx during the same window\npidstat -p $(pgrep -o nginx) 1 30 | tail -5\n\n# syscall-level view of crypto work\nsudo perf top -p $(pgrep -o nginx) --stdio 2&gt;\/dev\/null | head -20\n# expect the top frames to be in the handshake path, then drop away\n# once resumption dominates<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Certificates are part of this budget too: ECDSA P-256 halves handshake cost versus RSA-2048, and you can serve both with an <code>ssl_certificate<\/code> pair for compatibility. Once handshake CPU drops, the next bottleneck is usually application-side &mdash; if that turns out to be the case, the architecture guidance on <a href=\"https:\/\/virtualserversvps.com\/\">virtualserversvps.com<\/a> covers where to place caching and TLS termination. And if you are still deciding how much CPU to buy in the first place, <a href=\"https:\/\/virtualserversvps.com\/\">the hosting overview at virtualserversvps.com<\/a> is a useful sanity check on whether a bigger instance or better TLS configuration is the cheaper answer.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Checklist<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>Benchmark with <code>openssl speed<\/code> to know your per-signature cost.<\/li><li>Enable <code>ssl_session_cache<\/code> with an explicit shared zone and a 4-hour timeout.<\/li><li>Set and rotate <code>ssl_session_ticket_key<\/code> monthly; never leave the default key in place.<\/li><li>Enable <code>ssl_stapling<\/code> plus <code>ssl_stapling_verify<\/code> with a working resolver and full trusted chain.<\/li><li>Serve ECDSA and verify with <code>h2load<\/code> plus <code>pidstat<\/code> that CPU per request actually fell.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">TLS tuning is pure measurement: two configuration changes, one verification command each, and a CPU graph that proves the improvement is real rather than imagined.<\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>On a small VPS, the RSA or ECDSA signing operation in a TLS 1.3 handshake is often the most expensive thing your CPU does per request. Full handshakes from cold&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":0,"footnotes":""},"categories":[4],"tags":[],"class_list":["post-1224","post","type-post","status-publish","format-standard","hentry","category-security-compliance"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>TLS Session Resumption and OCSP Stapling on a Single-vCPU VPS: Reduce Handshake CPU Without Weakening Security - Virtual Servers VPS Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/virtualserversvps.com\/blog\/tls-session-resumption-ocsp-stapling-single-vcpu-vps\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"TLS Session Resumption and OCSP Stapling on a Single-vCPU VPS: Reduce Handshake CPU Without Weakening Security\" \/>\n<meta property=\"og:description\" content=\"TLS Session Resumption and OCSP Stapling on a Single-vCPU VPS: Reduce Handshake CPU Without Weakening Security\" \/>\n<meta property=\"og:url\" content=\"https:\/\/virtualserversvps.com\/blog\/tls-session-resumption-ocsp-stapling-single-vcpu-vps\/\" \/>\n<meta property=\"og:site_name\" content=\"Virtual Servers VPS Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-25T22:34:57+00:00\" \/>\n<meta name=\"author\" content=\"Virtual-Servers-Vps-Editor\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Virtual-Servers-Vps-Editor\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/tls-session-resumption-ocsp-stapling-single-vcpu-vps\/\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/tls-session-resumption-ocsp-stapling-single-vcpu-vps\/\",\"name\":\"TLS Session Resumption and OCSP Stapling on a Single-vCPU VPS: Reduce Handshake CPU Without Weakening Security - Virtual Servers VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\"},\"datePublished\":\"2026-09-25T22:34:57+00:00\",\"author\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\"},\"breadcrumb\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/tls-session-resumption-ocsp-stapling-single-vcpu-vps\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/virtualserversvps.com\/blog\/tls-session-resumption-ocsp-stapling-single-vcpu-vps\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/tls-session-resumption-ocsp-stapling-single-vcpu-vps\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/virtualserversvps.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"TLS Session Resumption and OCSP Stapling on a Single-vCPU VPS: Reduce Handshake CPU Without Weakening Security\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/\",\"name\":\"Virtual Servers VPS Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/virtualserversvps.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\",\"name\":\"Virtual-Servers-Vps-Editor\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g\",\"caption\":\"Virtual-Servers-Vps-Editor\"},\"sameAs\":[\"https:\/\/virtualserversvps.com\/blog\"],\"url\":\"https:\/\/virtualserversvps.com\/blog\/author\/virtualserversvps\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"TLS Session Resumption and OCSP Stapling on a Single-vCPU VPS: Reduce Handshake CPU Without Weakening Security - Virtual Servers VPS Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/virtualserversvps.com\/blog\/tls-session-resumption-ocsp-stapling-single-vcpu-vps\/","og_locale":"en_US","og_type":"article","og_title":"TLS Session Resumption and OCSP Stapling on a Single-vCPU VPS: Reduce Handshake CPU Without Weakening Security","og_description":"TLS Session Resumption and OCSP Stapling on a Single-vCPU VPS: Reduce Handshake CPU Without Weakening Security","og_url":"https:\/\/virtualserversvps.com\/blog\/tls-session-resumption-ocsp-stapling-single-vcpu-vps\/","og_site_name":"Virtual Servers VPS Blog","article_published_time":"2026-09-25T22:34:57+00:00","author":"Virtual-Servers-Vps-Editor","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Virtual-Servers-Vps-Editor","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/virtualserversvps.com\/blog\/tls-session-resumption-ocsp-stapling-single-vcpu-vps\/","url":"https:\/\/virtualserversvps.com\/blog\/tls-session-resumption-ocsp-stapling-single-vcpu-vps\/","name":"TLS Session Resumption and OCSP Stapling on a Single-vCPU VPS: Reduce Handshake CPU Without Weakening Security - Virtual Servers VPS Blog","isPartOf":{"@id":"https:\/\/virtualserversvps.com\/blog\/#website"},"datePublished":"2026-09-25T22:34:57+00:00","author":{"@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0"},"breadcrumb":{"@id":"https:\/\/virtualserversvps.com\/blog\/tls-session-resumption-ocsp-stapling-single-vcpu-vps\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/virtualserversvps.com\/blog\/tls-session-resumption-ocsp-stapling-single-vcpu-vps\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/virtualserversvps.com\/blog\/tls-session-resumption-ocsp-stapling-single-vcpu-vps\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/virtualserversvps.com\/blog\/"},{"@type":"ListItem","position":2,"name":"TLS Session Resumption and OCSP Stapling on a Single-vCPU VPS: Reduce Handshake CPU Without Weakening Security"}]},{"@type":"WebSite","@id":"https:\/\/virtualserversvps.com\/blog\/#website","url":"https:\/\/virtualserversvps.com\/blog\/","name":"Virtual Servers VPS Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/virtualserversvps.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0","name":"Virtual-Servers-Vps-Editor","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g","caption":"Virtual-Servers-Vps-Editor"},"sameAs":["https:\/\/virtualserversvps.com\/blog"],"url":"https:\/\/virtualserversvps.com\/blog\/author\/virtualserversvps\/"}]}},"_links":{"self":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/1224","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/comments?post=1224"}],"version-history":[{"count":1,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/1224\/revisions"}],"predecessor-version":[{"id":1226,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/1224\/revisions\/1226"}],"wp:attachment":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/media?parent=1224"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/categories?post=1224"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/tags?post=1224"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}