CrtMgr Blog - SSL/TLS Certificate Management Insights

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

SSL/TLS Troubleshooting Guide - Practical Solutions

SSL TLS Troubleshooting Certificates HTTPS

It’s 3 AM. PagerDuty fires. Your checkout page is down. You SSH in, check Nginx — it’s running fine. Then you notice it: NET::ERR_CERT_DATE_INVALID. The certificate expired six hours ago. Everyone’s been asleep. Sales have been zero for six hours.

Sound familiar? Certificate problems are among the most common causes of unexpected downtime, and they’re almost entirely preventable. This guide is the field manual I wish I’d had: practical diagnosis, concrete fixes, and enough context to understand why these problems happen — not just how to patch them this time.

If you’re setting up a fresh Nginx server and want to get SSL right from the start, see our Nginx SSL installation guide first. But if you’re already in a production incident, read on.

Diagnostic Tools

OpenSSL - Essential Tool

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

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

# Certificate details  
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -text

Testssl.sh - Comprehensive Analysis

# Installation
git clone https://github.com/drwetter/testssl.sh.git
cd testssl.sh

# Test
./testssl.sh example.com

Problem 1: Expired Certificate

Symptoms: NET::ERR_CERT_DATE_INVALID

Diagnosis:

openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates

Solution:

# Let's Encrypt
certbot renew
systemctl reload nginx

# Automatic renewal
echo "0 3 * * * certbot renew --quiet" | crontab -

Problem 2: Incomplete Certificate Chain

Symptoms: unable to get local issuer certificate

Diagnosis:

openssl s_client -connect example.com:443 -showcerts
# You should see certificate + intermediate + root

Nginx Solution:

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

Manual fullchain creation:

cat your-cert.crt intermediate.crt > fullchain.crt

Problem 3: Hostname Mismatch

Symptoms: NET::ERR_CERT_COMMON_NAME_INVALID

Diagnosis:

openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -text | grep -A2 "Subject Alternative Name"

Solution:

# Add all domains to certificate
certbot certonly --nginx -d example.com -d www.example.com -d api.example.com

Problem 4: Mixed Content

Symptoms: Mixed Content Warning in browser console

Diagnosis:

curl -s https://example.com | grep -o 'http://[^"]*'

Nginx Solution:

add_header Content-Security-Policy "upgrade-insecure-requests;" always;

Code Solution:

<!-- Instead of http:// use // -->
<img src="//example.com/image.jpg">

Problem 5: Self-Signed Certificate

Symptoms: NET::ERR_CERT_AUTHORITY_INVALID

Diagnosis:

openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -issuer -subject
# issuer == subject? It's self-signed!

Production Solution:

# Replace with Let's Encrypt
certbot certonly --nginx -d example.com

Problem 6: TLS Version Mismatch

Symptoms: ERR_SSL_VERSION_OR_CIPHER_MISMATCH

Diagnosis:

nmap --script ssl-enum-ciphers -p 443 example.com

Nginx Solution:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;

Problem 7: Port 443 Blocked

Symptoms: Timeout, connection refused

Diagnosis:

# Test connection
telnet example.com 443
nc -zv example.com 443

# Check firewall
sudo iptables -L -n | grep 443

Solution:

# Open port 443
sudo ufw allow 443/tcp
sudo firewall-cmd --permanent --add-service=https

Problem 8: SNI Issues

Symptoms: Wrong certificate for domain

Diagnosis:

# Test with SNI
openssl s_client -connect example.com:443 -servername example.com

# Test without SNI
openssl s_client -connect example.com:443 -noservername

Nginx Solution:

# Each domain needs its own server block
server {
    listen 443 ssl http2;
    server_name example.com;
    ssl_certificate /path/to/example.com.crt;
    ssl_certificate_key /path/to/example.com.key;
}

Problem 9: OCSP Stapling Issues

Diagnosis:

openssl s_client -connect example.com:443 -status 2>/dev/null | grep -A 17 "OCSP response"

Nginx Solution:

ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /path/to/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 10s;

Problem 10: Certificate Revoked

Symptoms: NET::ERR_CERT_REVOKED

Diagnosis:

openssl ocsp -issuer chain.pem -cert cert.pem -url http://ocsp.example.com

Solution: Certificate has been revoked - you must obtain a new one:

# Generate new key!
openssl genrsa -out new-key.pem 2048

# Get new certificate
certbot certonly --nginx -d example.com --force-renewal

Quick Troubleshooting Checklist

  1. Expiration date - has the certificate expired?
  2. Certificate chain - are you using fullchain?
  3. Hostname - is the domain in SAN?
  4. Issuer - is the CA trusted?
  5. TLS version - do you support TLS 1.2+?
  6. Port 443 - is it open?
  7. DNS - does the domain point to the correct IP?
  8. Server logs - what do error logs say?

Online Tools

Monitoring and Prevention

The best strategy is to prevent problems. A good Prometheus and Grafana monitoring setup for SSL certificates will catch expiring certificates weeks before they become incidents. But if you want a quick script to get started right now:

# Monitoring script
#!/bin/bash
DOMAIN="example.com"
DAYS_LEFT=$(echo | openssl s_client -connect $DOMAIN:443 2>/dev/null | openssl x509 -noout -checkend $((30*86400)))
if [ $? -ne 0 ]; then
  echo "Certificate expires soon!" | mail -s "SSL Alert" admin@example.com
fi

Or use a dedicated tool like CrtMgr, which automatically monitors certificates and sends alerts before expiration. Either way, the goal is the same: never be surprised by an expired certificate again.

Most SSL/TLS problems collapse into a handful of root causes: expired certificates (automate renewals — seriously, just do it), incomplete chain (always use fullchain.pem), hostname mismatches (add all domains to SAN upfront), and mixed content (the CSP header is your friend). None of these are hard to fix; they’re just easy to overlook under pressure.

The real goal is to stop troubleshooting and start preventing. Methodical monitoring beats reactive firefighting every time.


Good troubleshooting = methodical approach + right tools. Great operations = catching problems before they become incidents.

Related Articles