CrtMgr Blog - SSL/TLS Certificate Management Insights

Expert insights on SSL/TLS certificate management, types, deployment, and best practices

How to Install SSL Certificate on Nginx Server

Nginx SSL TLS Web Server Installation Guide

Nginx is one of the most popular web servers, powering millions of websites worldwide. This guide walks you through installing SSL/TLS certificates on Nginx, from obtaining certificates to optimal configuration.

Prerequisites

Before you begin, ensure you have:

  • Root or sudo access to your server
  • Nginx installed and running
  • A domain name pointing to your server
  • Basic command line knowledge

Check your Nginx version:

nginx -v

Method 1: Installing Let’s Encrypt Certificate with Certbot

Let’s Encrypt provides free SSL certificates with automated renewal. This is the recommended approach for most websites.

Step 1: Install Certbot

Ubuntu/Debian:

sudo apt update
sudo apt install certbot python3-certbot-nginx

CentOS/RHEL:

sudo yum install certbot python3-certbot-nginx

Fedora:

sudo dnf install certbot python3-certbot-nginx

Step 2: Obtain Certificate

Certbot can automatically configure Nginx for you:

sudo certbot --nginx -d example.com -d www.example.com

Follow the prompts:

  • Enter your email address (for renewal notifications)
  • Agree to Terms of Service
  • Choose whether to redirect HTTP to HTTPS (recommended)

Certbot will:

  • Validate domain ownership
  • Obtain the certificate
  • Update Nginx configuration
  • Reload Nginx

Step 3: Test Automatic Renewal

Let’s Encrypt certificates expire after 90 days. Certbot sets up automatic renewal:

# Test renewal process
sudo certbot renew --dry-run

# View renewal timer (systemd)
sudo systemctl status certbot.timer

Step 4: Verify Installation

Visit your website using https://:

# Test SSL configuration
curl -I https://example.com

# Check certificate details
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates

Method 2: Installing Commercial SSL Certificate

If you purchased an SSL certificate from a commercial CA (DigiCert, GlobalSign, Sectigo, etc.), follow these steps.

Step 1: Generate Certificate Signing Request (CSR)

Create a private key and CSR:

# Generate private key (RSA 2048-bit)
sudo openssl genrsa -out /etc/ssl/private/example.com.key 2048

# Secure the private key
sudo chmod 600 /etc/ssl/private/example.com.key

# Generate CSR
sudo openssl req -new -key /etc/ssl/private/example.com.key -out /etc/ssl/certs/example.com.csr

During CSR generation, provide:

  • Country Name: Two-letter country code (e.g., US, GB, PL)
  • State/Province: Full name (e.g., California, Mazowieckie)
  • City: Full city name
  • Organization Name: Your company name
  • Organizational Unit: Department (optional)
  • Common Name: Your domain (e.g., example.com)
  • Email Address: Contact email

Step 2: Submit CSR to Certificate Authority

  1. Copy the CSR content:
cat /etc/ssl/certs/example.com.csr
  1. Paste it into your CA’s certificate request form
  2. Complete domain validation (email, DNS, or file-based)
  3. Download the issued certificate and intermediate certificates

Step 3: Install Certificate Files

Upload the certificate files to your server:

# Primary certificate
sudo nano /etc/ssl/certs/example.com.crt

# Intermediate certificates (chain)
sudo nano /etc/ssl/certs/example.com-chain.crt

# Or combine them into one file
cat example.com.crt example.com-chain.crt > example.com-fullchain.crt
sudo mv example.com-fullchain.crt /etc/ssl/certs/

Set proper permissions:

sudo chmod 644 /etc/ssl/certs/example.com*.crt
sudo chmod 600 /etc/ssl/private/example.com.key

Configuring Nginx for SSL

Basic SSL Configuration

Edit your Nginx site configuration:

sudo nano /etc/nginx/sites-available/example.com

Add SSL configuration:

server {
    listen 80;
    server_name example.com www.example.com;
    
    # Redirect all HTTP to HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;
    
    # SSL Certificate paths
    ssl_certificate /etc/ssl/certs/example.com-fullchain.crt;
    ssl_certificate_key /etc/ssl/private/example.com.key;
    
    # SSL Configuration
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
    
    # SSL Session
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_tickets off;
    
    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/ssl/certs/example.com-chain.crt;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    
    # Security Headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    
    # Your application configuration
    root /var/www/example.com;
    index index.html index.htm;
    
    location / {
        try_files $uri $uri/ =404;
    }
}

Test Configuration

Before restarting Nginx, test the configuration:

sudo nginx -t

If successful, reload Nginx:

sudo systemctl reload nginx

Optimal Nginx SSL Configuration

Strong SSL Settings

For maximum security (A+ rating on SSL Labs):

# Modern configuration (supports TLS 1.2 and 1.3 only)
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:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;

# Diffie-Hellman parameter for DHE ciphersuites
ssl_dhparam /etc/ssl/certs/dhparam.pem;

# HSTS (force HTTPS for 1 year, including subdomains)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

Generate DH parameters (this takes time):

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Performance Optimization

# SSL Session Resumption
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;

# Enable HTTP/2
listen 443 ssl http2;

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/ssl/certs/chain.pem;

Multiple Domains

For hosting multiple SSL sites:

# Site 1
server {
    listen 443 ssl http2;
    server_name example.com www.example.com;
    
    ssl_certificate /etc/ssl/certs/example.com-fullchain.crt;
    ssl_certificate_key /etc/ssl/private/example.com.key;
    
    # ... rest of configuration
}

# Site 2
server {
    listen 443 ssl http2;
    server_name another.com www.another.com;
    
    ssl_certificate /etc/ssl/certs/another.com-fullchain.crt;
    ssl_certificate_key /etc/ssl/private/another.com.key;
    
    # ... rest of configuration
}

Troubleshooting Common Issues

Certificate Chain Issues

Problem: Browser shows “Incomplete certificate chain”

Solution: Include intermediate certificates:

# Combine certificate and chain
cat certificate.crt intermediate.crt > fullchain.crt

# Or use the CA's bundle file
ssl_certificate /etc/ssl/certs/fullchain.crt;

Mixed Content Warnings

Problem: Page loaded over HTTPS contains HTTP resources

Solution: Update all URLs to use HTTPS or protocol-relative URLs:

<!-- Bad -->
<script src="http://example.com/script.js"></script>

<!-- Good -->
<script src="https://example.com/script.js"></script>

<!-- Also good (protocol-relative) -->
<script src="//example.com/script.js"></script>

ERR_SSL_PROTOCOL_ERROR

Problem: Browser cannot establish SSL connection

Solutions:

  1. Check if Nginx is listening on port 443
  2. Verify firewall allows port 443
  3. Test SSL configuration: nginx -t
  4. Check certificate paths are correct
# Check if Nginx listens on 443
sudo netstat -tlnp | grep :443

# Test firewall
sudo ufw status
sudo ufw allow 443/tcp

# Check certificate files exist
ls -la /etc/ssl/certs/example.com*
ls -la /etc/ssl/private/example.com.key

Certificate Expiration

Monitor your certificates using CrtMgr or set up manual checks:

# Check expiration date
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates

# Create monitoring script
#!/bin/bash
DOMAIN="example.com"
DAYS_WARN=30
EXPIRY=$(echo | openssl s_client -connect $DOMAIN:443 -servername $DOMAIN 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))

if [ $DAYS_LEFT -lt $DAYS_WARN ]; then
    echo "Warning: Certificate for $DOMAIN expires in $DAYS_LEFT days"
fi

Security Best Practices

  1. Keep Private Keys Secure

    • Use restrictive permissions (600)
    • Never commit to version control
    • Consider hardware security modules (HSM) for sensitive applications
  2. Regular Updates

    • Keep Nginx updated
    • Update SSL/TLS configuration as standards evolve
    • Monitor security advisories
  3. Use Strong Protocols

    • Disable SSLv3, TLS 1.0, TLS 1.1
    • Enable TLS 1.2 and TLS 1.3 only
    • Use strong cipher suites
  4. Enable HSTS

    • Force HTTPS connections
    • Prevent protocol downgrade attacks
    • Consider HSTS preload list
  5. Monitor Certificate Expiration

    • Use monitoring tools like CrtMgr
    • Set up renewal alerts
    • Test renewal processes regularly

Testing Your SSL Configuration

Online Tools

Command Line Testing

# Test SSL connection
openssl s_client -connect example.com:443 -servername example.com

# Check certificate chain
openssl s_client -connect example.com:443 -servername example.com -showcerts

# Test specific TLS version
openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 -tls1_3

# Check OCSP stapling
openssl s_client -connect example.com:443 -status

Conclusion

Installing SSL certificates on Nginx is straightforward, whether using free Let’s Encrypt certificates or commercial ones. Key points to remember:

  • Use Certbot for Let’s Encrypt (easiest method)
  • Follow security best practices for configuration
  • Enable HTTP/2 for better performance
  • Set up proper monitoring for certificate expiration
  • Test your configuration with SSL Labs

With proper SSL configuration, your Nginx server will provide secure, fast HTTPS connections to your users. Use tools like CrtMgr to monitor your certificates and ensure they never expire unexpectedly.

Related Articles