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.csrInstall 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 -datesWildcard 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.comcoverswww.example.combut notsub.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
doneConvert 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 - nginx
- ssl
- certificate
- csr
- key
- pem