# Nginx SSL Configuration Generator (TLS 1.2/1.3, HSTS)

> Secure Nginx HTTPS server block: TLS 1.2/1.3, modern ciphers, HSTS, redirect, http2 and optional X25519MLKEM768.

Source: https://ssl.sh/tools/tls-config-generator/nginx/
Last updated: 2026-11-10

Get a secure Nginx HTTPS server block with TLS 1.2/1.3, HSTS and a redirect, tuned for your Nginx and OpenSSL versions.

The Nginx preset of the [TLS config generator](https://ssl.sh/tools/tls-config-generator/) writes a hardened HTTPS server block for Nginx. Choose the profile and options, then copy the server blocks into your site configuration, test with `nginx -t` and reload.

## Example: intermediate profile

```nginx
server {
    listen 80;
    listen [::]:80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name example.com;

    ssl_certificate     /etc/ssl/example.com/fullchain.pem;
    ssl_certificate_key /etc/ssl/example.com/privkey.pem;

    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;
    ssl_session_tickets off;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
    ssl_prefer_server_ciphers off;

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

    root /var/www/example.com;
}
```

## Version requirements

- **TLS 1.3**: nginx 1.13.0+ built with OpenSSL 1.1.1+. Check with `nginx -V`.
- **`http2 on;`**: nginx 1.25.1+. On older versions remove the line and write `listen 443 ssl http2;`.
- **Post-quantum**: `ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1:secp384r1;` needs OpenSSL 3.5+. With an older OpenSSL nginx refuses to start, so tick the option only after checking.

## Test and reload

```bash
sudo nginx -t && sudo systemctl reload nginx
curl -sI https://example.com | grep -i strict-transport
```

Then run the [SSL checker](https://ssl.sh/tools/ssl-checker/) to confirm the protocols and chain.

## Common mistakes

- **Only the leaf in `ssl_certificate`**: browsers may cope, but curl, Java and mobile apps fail. Use `fullchain.pem` (see the [chain builder](https://ssl.sh/tools/chain-builder/)).
- **`add_header` in a `location` block**: it replaces all `add_header` lines inherited from the server block, so HSTS silently disappears there. Repeat the HSTS line inside that location.
- **Key and certificate do not match**: nginx stops with "key values mismatch"; check with the [key matcher](https://ssl.sh/tools/key-matcher/).


## FAQ

**Where do I put this configuration?**

In the server block of your site, typically /etc/nginx/conf.d/example.com.conf or /etc/nginx/sites-available/example.com (linked from sites-enabled). Settings such as ssl_protocols can also go in the http block to apply to every site.

**How do I know which OpenSSL my nginx uses?**

Run nginx -V. The output includes 'built with OpenSSL x.y.z' and, if different, 'running with OpenSSL ...'. TLS 1.3 needs 1.1.1+, X25519MLKEM768 needs 3.5+.

**Should I enable ssl_stapling?**

Only if your CA runs OCSP. Let's Encrypt certificates issued since May 2025 contain no OCSP URL, so nginx logs a warning and staples nothing. For CAs that still run OCSP it saves clients a lookup.

**Why ssl_prefer_server_ciphers off?**

Every cipher in the intermediate list is strong, so letting the client choose lets devices without AES hardware pick ChaCha20-Poly1305, which is faster for them.
