Skip to content
Back to Blog
Security

SSL/TLS Certificate Management at Scale

Automate SSL/TLS certificate issuance, renewal, and deployment using Lets Encrypt, ACME protocol, and cert-manager in production.

Sep 2025
11 min read

Introduction

SSL/TLS certificates are the foundation of secure communication on the internet. Every time you see HTTPS in your browser, a certificate is working behind the scenes to encrypt traffic and verify identity. As an infrastructure engineer, you'll manage certificates for web servers, internal services, APIs, and more.

How TLS Works (Quick Overview)

When a client connects to a server:

  1. Client sends "Hello" with supported TLS versions and cipher suites
  2. Server responds with its certificate and chosen cipher
  3. Client verifies the certificate against trusted Certificate Authorities (CAs)
  4. Both sides derive encryption keys using asymmetric cryptography
  5. All subsequent data is encrypted symmetrically

Certificate Types

TypeUse CaseCost
DV (Domain Validation)Basic HTTPSFree (Let's Encrypt)
OV (Organization Validation)Business sitesPaid
EV (Extended Validation)High-trust sitesExpensive
Wildcard *.domain.comMultiple subdomainsVaries
SAN (Multi-domain)Multiple domainsVaries

Installing OpenSSL

BASH
# Ubuntu/Debian
apt install openssl

# Verify version
openssl version
# OpenSSL 3.0.2 15 Mar 2022

Generating a Self-Signed Certificate

For internal/test use:

BASH
# Generate private key + self-signed cert in one command
openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt   -days 365 -nodes   -subj "/C=IR/ST=Tehran/L=Tehran/O=Company/CN=server.company.local"

# Verify the certificate
openssl x509 -in server.crt -text -noout

Getting a Free Certificate with Let's Encrypt

Certbot automates Let's Encrypt certificate issuance and renewal:

BASH
# Install certbot
apt install certbot python3-certbot-nginx

# Get certificate for nginx (automatic configuration)
certbot --nginx -d example.com -d www.example.com

# Get certificate only (manual nginx config)
certbot certonly --nginx -d example.com

# Certificates are stored in:
# /etc/letsencrypt/live/example.com/fullchain.pem  (cert + chain)
# /etc/letsencrypt/live/example.com/privkey.pem    (private key)

Auto-Renewal

Let's Encrypt certs expire in 90 days. Certbot sets up automatic renewal:

BASH
# Test renewal (dry run, doesn't actually renew)
certbot renew --dry-run

# Check renewal timer
systemctl status certbot.timer

# Manual renewal
certbot renew

Generating CSR for Paid Certificates

When buying from a commercial CA, you submit a Certificate Signing Request:

BASH
# Step 1: Generate private key
openssl genrsa -out company.key 4096

# Step 2: Generate CSR
openssl req -new -key company.key -out company.csr   -subj "/C=IR/ST=Tehran/O=Company Ltd/CN=www.company.com"

# Step 3: Verify CSR content
openssl req -in company.csr -text -noout

# Step 4: Submit company.csr to your CA (DigiCert, Sectigo, etc.)
# Step 5: CA sends back company.crt — install it

Nginx SSL Configuration

NGINX
server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # Modern TLS settings
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # HSTS - tell browsers to always use HTTPS
    add_header Strict-Transport-Security "max-age=63072000" always;

    # OCSP Stapling - speeds up TLS handshake
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 1.1.1.1 valid=300s;
}

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

Building an Internal CA (PKI)

For internal services (not public internet), build your own CA:

BASH
# Create CA directory structure
mkdir -p /etc/ssl/myca/{certs,private,newcerts}
echo "01" > /etc/ssl/myca/serial
touch /etc/ssl/myca/index.txt

# Generate CA private key (keep this VERY secure)
openssl genrsa -aes256 -out /etc/ssl/myca/private/ca.key 4096

# Generate CA certificate (valid 10 years)
openssl req -new -x509 -days 3650   -key /etc/ssl/myca/private/ca.key   -out /etc/ssl/myca/certs/ca.crt   -subj "/C=IR/O=Company Internal CA/CN=Company Root CA"

# Sign a server certificate with your CA
openssl ca -config /etc/ssl/openssl.cnf   -in server.csr -out server.crt   -days 365

Useful OpenSSL Commands

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

# Check remote server certificate
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -text

# Check certificate matches private key (MD5 should match)
openssl x509 -noout -modulus -in cert.pem | md5sum
openssl rsa -noout -modulus -in key.pem | md5sum

# Convert PFX to PEM (common for Windows certificates)
openssl pkcs12 -in cert.pfx -out cert.pem -nodes

# Convert PEM to PFX
openssl pkcs12 -export -out cert.pfx -inkey key.pem -in cert.pem -certfile ca.pem

Certificate Monitoring

Set up monitoring to alert before certificates expire:

BASH
#!/bin/bash
# check-cert-expiry.sh
DOMAIN="example.com"
DAYS_WARN=30

EXPIRY=$(echo | openssl s_client -connect $DOMAIN:443 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: $DOMAIN cert expires in $DAYS_LEFT days!"
fi

Summary

  • Use Let's Encrypt for public-facing services — it's free and auto-renews
  • Build an internal CA for internal services and device authentication
  • Always use TLS 1.2 or 1.3 — disable older versions
  • Monitor certificate expiry proactively — expired certs cause outages
  • Never put private keys in version control