Nginx Cheatsheet

SSL/TLS

Use this Nginx reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Minimal HTTPS Server

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate     /etc/ssl/certs/example.com.crt;
    ssl_certificate_key /etc/ssl/private/example.com.key;

    location / {
        root /var/www/html;
    }
}

HTTP → HTTPS Redirect

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

HTTP/3 (QUIC)

Built in since nginx 1.25 (use current stable, 1.27+). QUIC runs over UDP — open UDP 443 in your firewall.

server {
    listen 443 quic reuseport;   # HTTP/3 over UDP (reuseport on ONE server only)
    listen 443 ssl;              # Keep TCP for HTTP/1.1 + HTTP/2
    http2 on;
    http3 on;
    server_name example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;   # QUIC always negotiates TLS 1.3

    # Tell browsers HTTP/3 is available (they upgrade on the next request)
    add_header Alt-Svc 'h3=":443"; ma=86400' always;
}
# Verify (curl built with HTTP/3 support)
curl --http3 -I https://example.com
nginx -V 2>&1 | grep -o with-http_v3_module

Directive Reference

DirectiveRecommended valuePurpose
ssl_certificatefullchain.pemPublic cert (+ intermediates)
ssl_certificate_keyprivkey.pemPrivate key
ssl_protocolsTLSv1.2 TLSv1.3Allowed protocol versions
ssl_ciphersECDHE/GCM suitesCipher whitelist
ssl_prefer_server_ciphersoffLet clients prefer TLS 1.3
ssl_session_cacheshared:SSL:10mShared session cache across workers
ssl_session_ticketsoffDisable for perfect forward secrecy
http2 ononEnable HTTP/2 (Nginx ≥ 1.25.1)
http3 ononEnable HTTP/3 with listen 443 quic (Nginx ≥ 1.25)

Let's Encrypt with Certbot

# Install certbot and the nginx plugin
sudo apt install certbot python3-certbot-nginx

# Issue cert and auto-configure nginx
sudo certbot --nginx -d example.com -d www.example.com

# Renew all certs (run via cron or systemd timer)
sudo certbot renew --dry-run
sudo certbot renew

# Cron entry (twice daily):
# 0 0,12 * * * root certbot renew --quiet

HSTS (HTTP Strict Transport Security)

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

Add preload only after testing — submit to hstspreload.org once stable.

add_header Inheritance Gotcha

add_header inherits from the enclosing level only if the current level has none. A single add_header inside a location silently drops every header set at server/http level — HSTS included.

server {
    add_header Strict-Transport-Security "max-age=31536000" always;

    location /api/ {
        add_header X-Api-Version "2";   # ← HSTS is now GONE for /api/
        # Fix: repeat the parent headers (or put them in a snippet and
        # include it in every location that declares its own add_header)
        add_header Strict-Transport-Security "max-age=31536000" always;
    }
}

Always use the always flag so headers are also sent on 4xx/5xx responses.

Security Headers

server_tokens off;   # Server: nginx (no version) in headers + error pages

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options    "nosniff" always;
add_header X-Frame-Options           "SAMEORIGIN" always;
add_header Referrer-Policy           "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy   "default-src 'self'" always;

Diffie-Hellman Parameters

# Generate a 2048-bit DH param file (do this once)
sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048
ssl_dhparam /etc/nginx/dhparam.pem;

Mutual TLS (Client Certificate Auth)

server {
    ssl_client_certificate /etc/ssl/ca/client-ca.crt;
    ssl_verify_client      on;            # Require valid client cert
    ssl_verify_depth       2;

    location /api/ {
        # $ssl_client_verify is "SUCCESS" when cert validated
        if ($ssl_client_verify != "SUCCESS") { return 403; }
    }
}

Multiple Certs on One IP (SNI)

# Server 1
server {
    listen 443 ssl;
    server_name site1.example.com;
    ssl_certificate /etc/ssl/site1.crt;
    ssl_certificate_key /etc/ssl/site1.key;
}

# Server 2 — same IP, different SNI hostname
server {
    listen 443 ssl;
    server_name site2.example.com;
    ssl_certificate /etc/ssl/site2.crt;
    ssl_certificate_key /etc/ssl/site2.key;
}

SNI is supported by all modern clients. No extra config needed.

Useful SSL Variables

VariableValue
$ssl_protocolTLSv1.3
$ssl_cipherNegotiated cipher suite
$ssl_client_verifySUCCESS, FAILED, NONE
$ssl_client_s_dnClient cert subject DN
$ssl_session_reused. if reused, r otherwise