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.
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.keySubmit 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.keyImportant: 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 443Verify 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.crtcontains 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 thatlisten 443 sslis 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