HxHippy

SSL Certificate Management

Managing SSL/TLS certificates for Nginx including generation and renewal.

Last updated: 2025-01-15

Certificate Types

Type Use Case
Self-signed Development, internal
Let's Encrypt Public websites (free)
Commercial High assurance, EV, wildcard

Generate Self-Signed Certificate

# Create directory
mkdir -p /etc/nginx/ssl

# Generate private key and certificate
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/nginx/ssl/self-signed.key \
  -out /etc/nginx/ssl/self-signed.crt \
  -subj "/C=US/ST=State/L=City/O=Organization/CN=example.com"

# Generate with SAN (Subject Alternative Names)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/nginx/ssl/self-signed.key \
  -out /etc/nginx/ssl/self-signed.crt \
  -subj "/CN=example.com" \
  -addext "subjectAltName=DNS:example.com,DNS:www.example.com,IP:192.168.1.1"

Generate CSR (Certificate Signing Request)

For commercial certificates:

# Generate key and CSR
openssl req -new -newkey rsa:2048 -nodes \
  -keyout /etc/nginx/ssl/example.com.key \
  -out /etc/nginx/ssl/example.com.csr \
  -subj "/C=US/ST=State/L=City/O=Organization/CN=example.com"

# View CSR contents
openssl req -text -noout -in /etc/nginx/ssl/example.com.csr

Install Commercial Certificate

# You'll receive from CA:
# - example.com.crt (your certificate)
# - ca-bundle.crt or chain.crt (intermediate certificates)

# Create full chain
cat example.com.crt ca-bundle.crt > /etc/nginx/ssl/fullchain.pem

# Or if separate files
cp example.com.crt /etc/nginx/ssl/cert.pem
cp ca-bundle.crt /etc/nginx/ssl/chain.pem
# Use in nginx
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/example.com.key;

# Or with separate chain
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
ssl_trusted_certificate /etc/nginx/ssl/chain.pem;

Verify Certificate

# Check certificate details
openssl x509 -in cert.pem -text -noout

# Check expiry date
openssl x509 -in cert.pem -noout -dates

# Verify chain
openssl verify -CAfile chain.pem cert.pem

# Check key matches certificate
openssl x509 -noout -modulus -in cert.pem | openssl md5
openssl rsa -noout -modulus -in key.pem | openssl md5
# Should match!

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

Wildcard Certificates

# Wildcard covers *.example.com
server {
    listen 443 ssl;
    server_name *.example.com;

    ssl_certificate /etc/nginx/ssl/wildcard.example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/wildcard.example.com.key;
}

Note: Wildcards cover one level only. *.example.com covers www.example.com but not sub.www.example.com.

Multiple Certificates (SNI)

# Site 1
server {
    listen 443 ssl;
    server_name site1.com;

    ssl_certificate /etc/nginx/ssl/site1.com.crt;
    ssl_certificate_key /etc/nginx/ssl/site1.com.key;
}

# Site 2
server {
    listen 443 ssl;
    server_name site2.com;

    ssl_certificate /etc/nginx/ssl/site2.com.crt;
    ssl_certificate_key /etc/nginx/ssl/site2.com.key;
}

Certificate Renewal Monitoring

#!/bin/bash
# /usr/local/bin/check-certs.sh

CERTS="/etc/nginx/ssl/*.crt /etc/letsencrypt/live/*/cert.pem"
WARN_DAYS=30

for cert in $CERTS; do
    if [ -f "$cert" ]; then
        expiry=$(openssl x509 -enddate -noout -in "$cert" | cut -d= -f2)
        expiry_epoch=$(date -d "$expiry" +%s)
        now_epoch=$(date +%s)
        days_left=$(( ($expiry_epoch - $now_epoch) / 86400 ))

        if [ $days_left -lt $WARN_DAYS ]; then
            echo "WARNING: $cert expires in $days_left days"
        fi
    fi
done

Convert Certificate Formats

# PEM to DER
openssl x509 -in cert.pem -outform DER -out cert.der

# DER to PEM
openssl x509 -in cert.der -inform DER -out cert.pem

# PEM to PKCS12
openssl pkcs12 -export -out cert.pfx -inkey key.pem -in cert.pem

# PKCS12 to PEM
openssl pkcs12 -in cert.pfx -out cert.pem -nodes
intermediate SSL/TLS Updated 2025-01-15
  • nginx
  • ssl
  • certificate
  • csr
  • key
  • pem