From 7efd2f0a614cd8293c4c01d5dc4f24606d2a1bda Mon Sep 17 00:00:00 2001 From: Evrard-Nil Daillet Date: Wed, 13 May 2026 16:52:29 +0200 Subject: [PATCH] perf: enable TLS session resumption and 0-RTT in ingress nginx Flip the existing ssl_session_tickets and ssl_early_data directives from off to on in both nginx config generators (setup_nginx_conf in entrypoint.sh and generate-nginx-upstream.sh). The session cache size (shared:SSL:50m) and timeout (1d) were already configured. For repeat clients that don't keep TLS connections alive (curl, mobile, some SDKs), this eliminates ~1 RTT per reconnect: tickets give 1-RTT TLS 1.3 resumption, ssl_early_data gives 0-RTT. From a typical client at ~100ms RTT to a CPU CVM, that is ~100ms saved per cold handshake. 0-RTT replay risk is mitigated by forwarding the Early-Data header to backends in every proxied location, so cloud-api / chat-api / inference-proxy can reject Early-Data on non-idempotent methods. None of them act on this header today; follow-up audits are tracked in the PR description. Scope is intentionally narrow: no base-image bump, no UDP/QUIC listen directives, no layout changes. There is a parallel PR adding HTTP/3 + Alt-Svc; this one only touches SSL session / ticket / early-data directives to minimize merge conflict. Verified: docker build succeeds; nginx -t passes for all four config-generation paths (single-target +/- rate-limit, upstream LB +/- rate-limit) using the project's own pinned base image. --- scripts/entrypoint.sh | 19 +++++++++++++++---- scripts/generate-nginx-upstream.sh | 19 +++++++++++++++---- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh index 90cda3f..5d6f9b4 100644 --- a/scripts/entrypoint.sh +++ b/scripts/entrypoint.sh @@ -93,6 +93,8 @@ limit_req_status 429; ${PROXY_CMD}_set_header X-Real-IP \$remote_addr; ${PROXY_CMD}_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; ${PROXY_CMD}_set_header X-Forwarded-Proto \$scheme; + # Forward TLS 0-RTT indicator so backends can reject Early-Data on non-idempotent methods + ${PROXY_CMD}_set_header Early-Data \$ssl_early_data; # Timeout configuration ${PROXY_CMD}_read_timeout 600; @@ -137,16 +139,21 @@ server { resolver 8.8.8.8 8.8.4.4 valid=300s; resolver_timeout 5s; - # SSL session configuration + # SSL session configuration — shared cache + tickets for 1-RTT resumption. + # 50m ~= 200k sessions, far more than any single CVM needs. + # ssl_session_tickets: nginx rotates ticket keys on reload — sufficient for a + # single-replica CVM. Cluster deployments would need an external rotated key file. ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; - ssl_session_tickets off; + ssl_session_tickets on; # SSL buffer size (optimized for TLS 1.3) ssl_buffer_size 4k; - # Disable SSL renegotiation - ssl_early_data off; + # TLS 1.3 0-RTT — saves the final RTT on resumed sessions. + # WARNING: 0-RTT data is replayable. The Early-Data header is forwarded to + # backends below so they can reject 0-RTT on non-idempotent methods. + ssl_early_data on; ${client_max_body_size_conf} # WebSocket support - handles both /ws/ and /socket.io/ paths @@ -161,6 +168,8 @@ ${client_max_body_size_conf} ${PROXY_CMD}_set_header X-Real-IP \$remote_addr; ${PROXY_CMD}_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; ${PROXY_CMD}_set_header X-Forwarded-Proto \$scheme; + # Forward TLS 0-RTT indicator so backends can reject Early-Data on non-idempotent methods + ${PROXY_CMD}_set_header Early-Data \$ssl_early_data; ${PROXY_CMD}_cache_bypass \$http_upgrade; @@ -178,6 +187,8 @@ ${rate_limit_location_conf} ${PROXY_CMD}_set_header X-Real-IP \$remote_addr; ${PROXY_CMD}_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; ${PROXY_CMD}_set_header X-Forwarded-Proto \$scheme; + # Forward TLS 0-RTT indicator so backends can reject Early-Data on non-idempotent methods + ${PROXY_CMD}_set_header Early-Data \$ssl_early_data; # Timeout configuration for long-running requests ${PROXY_CMD}_read_timeout 600; # 10 minutes diff --git a/scripts/generate-nginx-upstream.sh b/scripts/generate-nginx-upstream.sh index bcbd3f6..7d1638b 100644 --- a/scripts/generate-nginx-upstream.sh +++ b/scripts/generate-nginx-upstream.sh @@ -108,6 +108,8 @@ ${KEEPALIVE_HEADERS} ${PROXY_CMD}_set_header X-Real-IP \$remote_addr; ${PROXY_CMD}_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; ${PROXY_CMD}_set_header X-Forwarded-Proto \$scheme; + # Forward TLS 0-RTT indicator so backends can reject Early-Data on non-idempotent methods + ${PROXY_CMD}_set_header Early-Data \$ssl_early_data; # Timeout configuration ${PROXY_CMD}_read_timeout 600; @@ -171,16 +173,21 @@ server { resolver 8.8.8.8 8.8.4.4 valid=300s; resolver_timeout 5s; - # SSL session configuration + # SSL session configuration — shared cache + tickets for 1-RTT resumption. + # 50m ~= 200k sessions, far more than any single CVM needs. + # ssl_session_tickets: nginx rotates ticket keys on reload — sufficient for a + # single-replica CVM. Cluster deployments would need an external rotated key file. ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; - ssl_session_tickets off; + ssl_session_tickets on; # SSL buffer size (optimized for TLS 1.3) ssl_buffer_size 4k; - # Disable SSL renegotiation - ssl_early_data off; + # TLS 1.3 0-RTT — saves the final RTT on resumed sessions. + # WARNING: 0-RTT data is replayable. The Early-Data header is forwarded to + # backends below so they can reject 0-RTT on non-idempotent methods. + ssl_early_data on; ${CLIENT_MAX_BODY_SIZE_CONF} # WebSocket support - handles both /ws/ and /socket.io/ paths @@ -195,6 +202,8 @@ ${CLIENT_MAX_BODY_SIZE_CONF} ${PROXY_CMD}_set_header X-Real-IP \$remote_addr; ${PROXY_CMD}_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; ${PROXY_CMD}_set_header X-Forwarded-Proto \$scheme; + # Forward TLS 0-RTT indicator so backends can reject Early-Data on non-idempotent methods + ${PROXY_CMD}_set_header Early-Data \$ssl_early_data; ${PROXY_CMD}_cache_bypass \$http_upgrade; @@ -217,6 +226,8 @@ ${KEEPALIVE_HEADERS} ${PROXY_CMD}_set_header X-Real-IP \$remote_addr; ${PROXY_CMD}_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; ${PROXY_CMD}_set_header X-Forwarded-Proto \$scheme; + # Forward TLS 0-RTT indicator so backends can reject Early-Data on non-idempotent methods + ${PROXY_CMD}_set_header Early-Data \$ssl_early_data; # Timeout configuration for long-running requests ${PROXY_CMD}_read_timeout 600; # 10 minutes