SSL certificate maximum validity is being reduced to 200 days from March 2026. Read more →
Nginx / Linux Advanced ~4 min. read

Nginx SSL/TLS Configuration Guide

A comprehensive guide to configuring SSL/TLS certificates in Nginx on Linux, including OCSP stapling, secure cipher suites, and HTTP to HTTPS redirection.

Nginx SSL/TLS Configuration Guide

Overview

Nginx is one of the most popular web servers and reverse proxies in the world. This guide covers the entire SSL/TLS setup process: from generating a CSR with OpenSSL to certificate installation, chain bundling, and hardening your configuration with modern TLS settings, OCSP stapling, and HSTS.

Prerequisites

  • Nginx 1.18+ installed (older versions may not support TLS 1.3)
  • OpenSSL installed on the server
  • Root or sudo access
  • A domain name pointing to the server's IP address
  • An SSL certificate from FairSSL (DV, OV, or EV)

Step 1: Generate a Private Key and CSR with OpenSSL

# Create directory for certificate files
sudo mkdir -p /etc/nginx/ssl/eksempel.dk

# Generate 2048-bit RSA key and CSR
sudo openssl req -new -newkey rsa:2048 -nodes \
  -keyout /etc/nginx/ssl/eksempel.dk/privkey.key \
  -out /etc/nginx/ssl/eksempel.dk/eksempel.csr \
  -subj "/C=DK/ST=Hovedstaden/L=Koebenhavn/O=Eksempel A\/S/CN=www.eksempel.dk"

# Set restrictive permissions on the private key
sudo chmod 600 /etc/nginx/ssl/eksempel.dk/privkey.key
sudo chown root:root /etc/nginx/ssl/eksempel.dk/privkey.key

Submit the contents of the CSR file through your FairSSL.com control panel to order the certificate.

Step 2: Prepare Certificate Files and Chain Bundling

Once FairSSL has issued the certificate, you will typically receive:

  • Domain Certificate: eksempel_dk.crt
  • Intermediate/CA Bundle: ca-bundle.crt

Nginx requires the primary certificate and the intermediate certificate to be combined into a single file (the full chain). The order is critical – your domain certificate first, followed by the intermediate:

# Create fullchain file (certificate + intermediate)
cat eksempel_dk.crt ca-bundle.crt | sudo tee /etc/nginx/ssl/eksempel.dk/fullchain.crt > /dev/null

# Copy the private key (if not already in place)
sudo cp privkey.key /etc/nginx/ssl/eksempel.dk/privkey.key

# Set correct permissions
sudo chmod 644 /etc/nginx/ssl/eksempel.dk/fullchain.crt
sudo chmod 600 /etc/nginx/ssl/eksempel.dk/privkey.key

Important: Do not include the root certificate in the full chain file. Browsers already have root certificates pre-installed in their trust stores.

Step 3: Configure the Nginx Server Block for HTTPS

Create or edit your server block configuration (typically located in /etc/nginx/sites-available/):

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name www.eksempel.dk eksempel.dk;

    # Certificate and key
    ssl_certificate     /etc/nginx/ssl/eksempel.dk/fullchain.crt;
    ssl_certificate_key /etc/nginx/ssl/eksempel.dk/privkey.key;

    # TLS protocols (TLS 1.2 and 1.3 only)
    ssl_protocols TLSv1.2 TLSv1.3;

    # Cipher suites (modern and secure)
    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;

    # SSL session caching
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    # HSTS (HTTP Strict Transport Security)
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

    # Document root and other configuration
    root /var/www/eksempel.dk/public;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

Step 4: HTTP to HTTPS Redirection

Add a separate server block to redirect all incoming HTTP traffic to HTTPS:

server {
    listen 80;
    listen [::]:80;
    server_name www.eksempel.dk eksempel.dk;

    # Redirect all traffic to HTTPS
    return 301 https://$host$request_uri;
}

Step 5: Enable OCSP Stapling

OCSP stapling improves the TLS handshake speed by serving the certificate's validity status directly from your server:

# Add inside the server block (within the SSL configuration):
ssl_stapling on;
ssl_stapling_verify on;

# Point to the intermediate certificate for OCSP verification
ssl_trusted_certificate /etc/nginx/ssl/eksempel.dk/fullchain.crt;

# DNS resolver (use your provider or public resolvers)
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;

Step 6: Testing and Restarting

# Test the Nginx configuration for syntax errors
sudo nginx -t

# Reload the configuration (no downtime)
sudo systemctl reload nginx

# Or full restart
sudo systemctl restart nginx

# Verify Nginx is listening on port 443
sudo ss -tlnp | grep 443

Verify the certificate installation:

# Show certificate info and chain
openssl s_client -connect www.eksempel.dk:443 -servername www.eksempel.dk < /dev/null 2>/dev/null | openssl x509 -noout -subject -dates -issuer

# Test OCSP stapling
openssl s_client -connect www.eksempel.dk:443 -servername www.eksempel.dk -status < /dev/null 2>/dev/null | grep -A 5 "OCSP Response"

# Test with curl
curl -vI https://www.eksempel.dk 2>&1 | grep -E "SSL|TLS|subject|issuer"

You should also use the FairSSL.com SSL scanner or Qualys SSL Labs for a comprehensive online evaluation of your TLS configuration.

Troubleshooting

  • "nginx: [emerg] cannot load certificate": The certificate file is empty, corrupted, or in the wrong format. Ensure fullchain.crt contains valid PEM blocks (beginning with -----BEGIN CERTIFICATE-----).
  • "PEM routines:get_name:no start line": The file contains invalid characters or has incorrect encoding. Ensure the file is saved in UTF-8/ASCII without a BOM.
  • Browser shows "Not Secure": The full chain file is missing the intermediate certificate. Recreate the file using cat cert.crt intermediate.crt > fullchain.crt.
  • OCSP stapling isn't working: It can take a few minutes after a restart for Nginx to fetch the OCSP response. Check with openssl s_client -status. Also, ensure your resolver is correctly configured.
  • ERR_SSL_PROTOCOL_ERROR: Ensure port 443 is open in your firewall (sudo ufw allow 443) and that listen 443 ssl is correctly configured in your server block.
  • Certificate expired: Set a reminder or use monitoring. Check the expiry date with openssl x509 -enddate -noout -in /etc/nginx/ssl/eksempel.dk/fullchain.crt.

Strengthen your TLS security

Use the Mozilla SSL Configuration Generator to generate a secure TLS configuration with modern cipher suites and protocol settings.

Mozilla SSL Configuration Generator guide

Ready to create a free account?

Create a free account and issue your first certificate in under 10 minutes.