SSL Configuration and HTTP/2
Introduction
After Certbot installs certificates, you may still need to understand listen 443 ssl, certificate paths, and modern TLS settings. HTTP/2 multiplexes requests over one connection—often enabled with a single directive. This chapter explains manual SSL blocks, security-oriented defaults, and how HTTPS interacts with reverse proxies.
Prerequisites
- HTTPS and Let's Encrypt
- Certificate files present under
/etc/letsencrypt/live/(or your CA paths)
Basic SSL server Block
Code explanation:
fullchain.pem— server cert + intermediate chain browsers trustprivkey.pem— private key; must stay secretlisten [::]:443— IPv6 HTTPS (optional but recommended)
Always test:
sudo nginx -t && sudo systemctl reload nginx
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -datesEnable HTTP/2
listen 443 ssl http2;
listen [::]:443 ssl http2;Code explanation:
- HTTP/2 requires TLS in browsers
- One connection carries many requests—helps pages with many assets
- Browsers fall back to HTTP/1.1 if unsupported
Verify with browser DevTools → Network → Protocol column, or:
curl -I --http2 https://example.com/Modern TLS Settings (Certbot Defaults)
Certbot’s options-ssl-nginx.conf typically includes:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;If configuring manually (check current Mozilla SSL guidelines):
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;Code explanation:
- Disable TLS 1.0/1.1—obsolete and insecure
- TLS 1.3 preferred by modern clients
- Session cache reduces handshake cost
Optional DH params (Certbot creates /etc/letsencrypt/ssl-dhparams.pem):
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;Include Pattern After Certbot
Do not duplicate conflicting ssl_protocols unless you know the override effect.
HTTPS Reverse Proxy Notes
X-Forwarded-Proto must reflect HTTPS for apps:
proxy_set_header X-Forwarded-Proto $scheme;When client uses HTTPS, $scheme is https—Spring Boot and Express generate correct absolute URLs.
Spring Boot:
server.forward-headers-strategy=frameworkExpress:
app.set("trust proxy", 1);HSTS (Optional, Production)
Tell browsers to use HTTPS only:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;Warning
Enable HSTS Only When HTTPS Is Stable
Misconfigured HTTPS + HSTS locks users out until max-age expires. Test thoroughly first.
OCSP Stapling (Awareness)
Reduces client cert validation latency:
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;Certbot setups may enable related pieces—verify with SSL Labs test when hardening production.
Mixed Content
HTML served over HTTPS must load CSS/JS/images over HTTPS too—otherwise browsers block mixed content. Fix asset URLs in frontend builds (https:// or relative paths).
FAQ
self-signed certificate for dev?
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout dev.key -out dev.crt -subj "/CN=localhost"Browsers show warnings—acceptable for local testing only.
One cert for many subdomains?
SAN cert with multiple -d flags in Certbot, or wildcard via DNS challenge.
ssl on port 8443?
listen 8443 ssl;—clients must specify port in URL unless redirected from 443.
HTTP/3 (QUIC)?
Requires ngx_http_v3_module or newer builds—not in all distro packages yet.
Certificate expired?
Run sudo certbot renew; check timer; ensure Nginx reloads after renewal.
SSL Labs grade?
Use external SSL Server Test to audit configuration after changes—aim for A/A+ with modern profiles.