How to Fix SSL Certificate Errors on a VPS: Let’s Encrypt Renewal, Mixed Content, and Common Issues
SSL certificate errors display a browser warning to every visitor and can block access entirely. On VPS deployments with Let’s Encrypt, certificate errors most commonly stem from renewal failures, DNS misconfiguration, web server configuration mistakes, or port conflicts. This guide diagnoses and fixes the most common SSL issues systematically.
Diagnostic First Steps
# Check certificate status and expiry
sudo certbot certificates
# Test SSL from command line
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com
# Check certificate details
openssl s_client -connect yourdomain.com:443 2>/dev/null | \
openssl x509 -noout -text | grep -A2 "Subject:\|Issuer:\|Not After"
# Test with curl
curl -vI https://yourdomain.com 2>&1 | grep -E "SSL|certificate|expire"
Issue 1: Certificate Renewal Failure
# Check Certbot timer
sudo systemctl status certbot.timer
# Test renewal (dry run — no changes made)
sudo certbot renew --dry-run
# View detailed error logs
sudo tail -100 /var/log/letsencrypt/letsencrypt.log
Fix: Port 80 Not Accessible
sudo ufw status | grep 80
sudo ufw allow 80/tcp
# Check what's listening on port 80
sudo ss -tlnp | grep :80
# Stop conflicting web server (e.g. Apache)
sudo systemctl stop apache2
Fix: DNS Not Pointing to This VPS
dig +short yourdomain.com A
curl -s https://ifconfig.me
# These two IPs must match for HTTP challenge to succeed!
Force Renewal
sudo certbot renew --force-renewal --cert-name yourdomain.com
sudo systemctl reload nginx
Issue 2: Certificate Expired — Emergency Recovery
sudo systemctl start nginx
sudo ufw allow 80/tcp
# Re-issue certificate
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# If nginx plugin fails, use standalone mode (stops Nginx temporarily)
sudo systemctl stop nginx
sudo certbot certonly --standalone -d yourdomain.com -d www.yourdomain.com
sudo systemctl start nginx
sudo systemctl reload nginx
Issue 3: ERR_SSL_PROTOCOL_ERROR
# Is port 443 listening?
sudo ss -tlnp | grep :443
# Open in UFW if missing
sudo ufw allow 443/tcp
# Validate Nginx SSL configuration syntax
sudo nginx -t
# Verify certificate files exist
ls -la /etc/letsencrypt/live/yourdomain.com/
# Check which certificate Nginx is configured to use
grep -r "ssl_certificate" /etc/nginx/sites-enabled/
Issue 4: Incomplete Certificate Chain (NET::ERR_CERT_AUTHORITY_INVALID)
# WRONG — missing intermediate CA:
ssl_certificate /etc/letsencrypt/live/yourdomain.com/cert.pem;
# CORRECT — includes the full chain:
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
Issue 5: Mixed Content Warnings
Mixed content means an HTTPS page loads HTTP resources. Fix with a redirect and HSTS header:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
# ...
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}
For WordPress mixed content (HTTP URLs stored in the database):
wp --allow-root --path=/var/www/yourdomain.com \
search-replace 'http://yourdomain.com' 'https://yourdomain.com' --all-tables
wp --allow-root --path=/var/www/yourdomain.com option update siteurl 'https://yourdomain.com'
wp --allow-root --path=/var/www/yourdomain.com option update home 'https://yourdomain.com'
Issue 6: Let’s Encrypt Rate Limits
# Check existing valid certificates first
sudo certbot certificates
# Renew without hitting rate limits
sudo certbot renew --reuse-key --force-renewal
# Testing? Use staging environment (no rate limits, but not browser-trusted):
sudo certbot --nginx --staging -d yourdomain.com
SSL Best Practice Configuration
# Add to Nginx server block for A+ SSL rating
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;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# OCSP Stapling (speeds up SSL handshake by pre-fetching revocation status)
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;
Verify Renewal is Configured Correctly
# Both must return 'enabled' and 'active'
sudo systemctl is-enabled certbot.timer
sudo systemctl is-active certbot.timer
# Test renewal monthly to catch problems early
sudo certbot renew --dry-run --quiet
Getting Started
SSL certificate management is a routine maintenance task on any Ubuntu VPS at VPS.DO. Configure UFW to allow ports 80 and 443, install Certbot, and the renewal timer handles everything from there. VPS.DO’s emergency KVM console provides access if SSH breaks during SSL troubleshooting.
Conclusion
SSL errors break down into a small number of root causes: port accessibility, DNS configuration, expired certificates, and Nginx configuration mistakes. The diagnostic commands in this guide identify the root cause within minutes. The most impactful preventive measure is ensuring the Certbot renewal timer is active — a certificate that renews automatically before expiry never produces a visitor-facing error.