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

Basic SSL server Block

Code explanation:

  • fullchain.pem — server cert + intermediate chain browsers trust
  • privkey.pem — private key; must stay secret
  • listen [::]:443 — IPv6 HTTPS (optional but recommended)

Always test:

bash
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 -dates

Enable HTTP/2

nginx
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:

bash
curl -I --http2 https://example.com/

Modern TLS Settings (Certbot Defaults)

Certbot’s options-ssl-nginx.conf typically includes:

nginx
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;

If configuring manually (check current Mozilla SSL guidelines):

nginx
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):

nginx
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:

nginx
proxy_set_header X-Forwarded-Proto $scheme;

When client uses HTTPS, $scheme is https—Spring Boot and Express generate correct absolute URLs.

Spring Boot:

properties
server.forward-headers-strategy=framework

Express:

javascript
app.set("trust proxy", 1);

HSTS (Optional, Production)

Tell browsers to use HTTPS only:

nginx
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:

nginx
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?

bash
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.