AI QA Monkey
AI Security Intelligence
Fix Guide

SSL/TLS Certificate Issues: Complete Fix Guide

SSL/TLS is the foundation of web security. It encrypts data in transit between the browser and your server, preventing eavesdropping, tampering, and impersonation. Google uses HTTPS as a ranking signal, and browsers now show prominent "Not Secure" warnings for HTTP pages.

In our analysis of 50,000+ scans, 12% of websites had at least one SSL/TLS issue — most commonly mixed content (8%), weak cipher suites (4%), and TLS 1.0/1.1 still enabled (3%).

Why SSL/TLS Matters

  • Data protection: Encrypts passwords, credit cards, personal data in transit
  • Authentication: Proves your server is who it claims to be
  • SEO ranking: Google prioritizes HTTPS sites
  • Compliance: PCI DSS 4.0 requires TLS 1.2+ for all payment pages
  • Browser trust: HTTP pages show "Not Secure" warnings

Fix: Expired Certificate CRITICAL

An expired certificate causes browsers to show a full-page security warning, blocking most visitors from accessing your site.

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

# Renew with Let's Encrypt (Certbot)
sudo certbot renew

# Force renewal (if not yet due)
sudo certbot renew --force-renewal

# Auto-renewal cron job (runs twice daily)
echo "0 0,12 * * * root certbot renew --quiet" | sudo tee /etc/cron.d/certbot-renew

# Restart web server after renewal
sudo systemctl reload apache2  # Apache
sudo systemctl reload nginx    # Nginx

Fix: Mixed Content HIGH

Mixed content occurs when an HTTPS page loads resources (images, scripts, stylesheets) over HTTP. Browsers block mixed active content (scripts) and warn about mixed passive content (images).

Quick Fix: Upgrade-Insecure-Requests Header

# Apache — Auto-upgrade HTTP resources to HTTPS
Header always set Content-Security-Policy "upgrade-insecure-requests"

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

Permanent Fix: Update All Resource URLs

# Search for HTTP references in your codebase
grep -rn "http://" --include="*.php" --include="*.html" --include="*.css" --include="*.js" .

# Common patterns to fix:
# <img src="http://..." → <img src="https://..."
# <script src="http://..." → <script src="https://..."
# <link href="http://..." → <link href="https://..."
# url("http://...") → url("https://...")
# background: url(http://...) → background: url(https://...)

# WordPress — Update URLs in database
wp search-replace 'http://yourdomain.com' 'https://yourdomain.com' --all-tables

Fix: Disable TLS 1.0/1.1 CRITICAL

TLS 1.0 (1999) and TLS 1.1 (2006) have known vulnerabilities (BEAST, POODLE) and are prohibited by PCI DSS 4.0. All modern browsers support TLS 1.2+.

# Apache — TLS 1.2+ only
SSLProtocol -all +TLSv1.2 +TLSv1.3

# Nginx — TLS 1.2+ only
ssl_protocols TLSv1.2 TLSv1.3;

# Verify TLS versions
# Check if TLS 1.0 is disabled (should fail):
openssl s_client -connect yourdomain.com:443 -tls1 2>&1 | grep -i "handshake"

# Check if TLS 1.1 is disabled (should fail):
openssl s_client -connect yourdomain.com:443 -tls1_1 2>&1 | grep -i "handshake"

# Check if TLS 1.2 works (should succeed):
openssl s_client -connect yourdomain.com:443 -tls1_2 2>&1 | grep -i "handshake"

Fix: Weak Cipher Suites HIGH

Weak ciphers (RC4, DES, 3DES, export ciphers) can be broken by attackers. Use only modern, strong cipher suites.

# Apache — Strong cipher configuration (Mozilla Intermediate)
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder off

# Nginx — Strong cipher configuration
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;

Fix: Certificate Chain Issues HIGH

An incomplete certificate chain means the server isn't sending intermediate certificates, causing trust errors on some devices.

# Check certificate chain
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null | grep -A 1 "Certificate chain"

# Fix: Concatenate certificates in correct order
# Order: Your cert → Intermediate cert(s) → Root cert (optional)
cat your_domain.crt intermediate.crt > fullchain.crt

# Apache
SSLCertificateFile /etc/ssl/certs/your_domain.crt
SSLCertificateChainFile /etc/ssl/certs/intermediate.crt
# Or use fullchain:
SSLCertificateFile /etc/ssl/certs/fullchain.crt

# Nginx
ssl_certificate /etc/ssl/certs/fullchain.crt;
ssl_certificate_key /etc/ssl/private/your_domain.key;

Fix: HTTP to HTTPS Redirect HIGH

# Apache — .htaccess
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

# Nginx
server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    return 301 https://$host$request_uri;
}

# Also add HSTS to prevent future HTTP requests
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

Free SSL with Let's Encrypt

# Install Certbot
sudo apt update
sudo apt install certbot

# Apache
sudo apt install python3-certbot-apache
sudo certbot --apache -d yourdomain.com -d www.yourdomain.com

# Nginx
sudo apt install python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

# Standalone (no web server integration)
sudo certbot certonly --standalone -d yourdomain.com

# Wildcard certificate (requires DNS validation)
sudo certbot certonly --manual --preferred-challenges dns -d "*.yourdomain.com" -d yourdomain.com

# Test auto-renewal
sudo certbot renew --dry-run

Testing Your SSL Configuration

# Quick SSL check
curl -vI https://yourdomain.com 2>&1 | grep -E "(SSL|TLS|certificate|expire)"

# Detailed check with openssl
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com

# Check supported protocols
nmap --script ssl-enum-ciphers -p 443 yourdomain.com

For a comprehensive check, use AI QA Monkey's free security scanner — it validates your SSL certificate, checks TLS versions, cipher suites, HSTS, and mixed content in one scan.

HSTS: preventing protocol downgrade attacks

HTTP Strict Transport Security (HSTS) instructs browsers to only connect to your site over HTTPS, even if the user types http://. Without HSTS, attackers on a shared network can intercept the initial HTTP request before it redirects to HTTPS — a classic SSL stripping attack.

# Apache — set HSTS with 1-year max-age
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

# Nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

# The three components:
# max-age=31536000      — Browsers remember HTTPS-only for 1 year
# includeSubDomains     — Applies to all subdomains too
# preload               — Submit domain to browser HSTS preload list (optional but recommended)
  • Start with a shorter max-age: When first deploying HSTS, use max-age=300 (5 minutes) to verify no HTTPS issues exist before committing to a year-long policy.
  • includeSubDomains risk: If any subdomain does not support HTTPS, includeSubDomains will break it. Confirm all subdomains are HTTPS-ready before adding this flag.
  • HSTS preload list: Submitting to the preload list (at hstspreload.org) means your domain is hardcoded in Chrome, Firefox, Safari, and Edge to use HTTPS even on the first visit — before any header is seen.

Certificate types: DV vs. OV vs. EV

Not all SSL certificates provide the same level of assurance. Understanding the difference helps in choosing the right certificate for your use case.

  • DV (Domain Validated): Verifies only that the applicant controls the domain. Issued in minutes. Free via Let's Encrypt. Suitable for most websites, blogs, and web applications. Shows a padlock in the browser but no organization name.
  • OV (Organization Validated): Verifies the organization behind the domain through business registration checks. Takes 1-3 days. Shows the organization name in certificate details. Appropriate for businesses that want to demonstrate a verified entity behind the certificate.
  • EV (Extended Validation): Highest level of verification — rigorous identity checks, legal registration, and physical presence confirmation. Takes up to a week. Historically showed a green address bar; modern browsers have removed this visual distinction but EV certificates still provide the highest assurance in certificate details. Required for some regulated industries.
  • Wildcard certificates: Cover a domain and all immediate subdomains (*.yourdomain.com). Useful when managing multiple subdomains. Note: wildcards do not cover second-level subdomains (*.sub.yourdomain.com) — a separate wildcard or SAN certificate is required.

Certificate transparency and CAA records

Two often-overlooked SSL hardening steps that significantly reduce the risk of certificate mis-issuance:

  • Certificate Transparency (CT) monitoring: All publicly trusted certificates are logged in public CT logs. Services like crt.sh let you monitor all certificates issued for your domain. Set up alerts for unexpected certificate issuance — a certificate you did not request could indicate a DNS hijack or CA compromise.
  • CAA DNS records: Certification Authority Authorization records in DNS restrict which CAs are permitted to issue certificates for your domain. Without a CAA record, any CA can issue a certificate. With one, only listed CAs can issue:
    # CAA record examples (add in DNS provider)
    yourdomain.com. CAA 0 issue "letsencrypt.org"
    yourdomain.com. CAA 0 issue "digicert.com"
    yourdomain.com. CAA 0 issuewild "letsencrypt.org"  # Wildcard permission
    yourdomain.com. CAA 0 iodef "mailto:security@yourdomain.com"  # Violation reports

Common SSL issues after migration

HTTPS migrations (moving from HTTP to HTTPS or migrating hosts) introduce a predictable set of SSL issues. Checking these after every migration prevents post-launch surprises:

  • Certificate not covering all domains: If you use both yourdomain.com and www.yourdomain.com, confirm both are covered by the certificate's Subject Alternative Names (SAN). Let's Encrypt includes both when specified with -d yourdomain.com -d www.yourdomain.com.
  • Hardcoded HTTP URLs in database: WordPress and other CMS platforms often store URLs in the database. After HTTPS migration, run a search-replace on the database to update all http://yourdomain.com references to https://yourdomain.com. Use wp search-replace or a database migration tool.
  • Third-party scripts still HTTP: Analytics, chat widgets, ad scripts, and CDN assets may load via HTTP. Update every third-party script URL to HTTPS or use the upgrade-insecure-requests CSP directive as a temporary measure.
  • Load balancer not forwarding HTTPS: When using a load balancer or CDN that terminates SSL, ensure the backend receives the X-Forwarded-Proto: https header and your application respects it for HTTPS detection and redirect logic.

Check Your SSL/TLS Configuration

Free scan — validates certificate, TLS version, cipher suites, HSTS, and mixed content.

Scan Your SSL Now

Frequently Asked Questions

How do I fix an expired SSL certificate?

Renew through your CA or use Let's Encrypt: sudo certbot renew. Set up a cron job for automatic renewal.

How do I fix mixed content warnings?

Add the Content-Security-Policy: upgrade-insecure-requests header for a quick fix, then update all resource URLs from http:// to https://.

How do I disable TLS 1.0 and 1.1?

Apache: SSLProtocol -all +TLSv1.2 +TLSv1.3. Nginx: ssl_protocols TLSv1.2 TLSv1.3;

Check Your Website Right Now

Run a free automated security scan — 75 checks in 60 seconds. No signup required.

Run Free Security Scan →