Diagnosing and Fixing SSL/TLS Errors
Your guide to resolving web server and client SSL/TLS issues.

SSL/TLS powers secure connections across the internet. But when things break—handshakes fail, certificates misbehave, or browsers throw cryptic errors—it can be frustrating. This post helps you quickly identify and fix common SSL/TLS issues using real examples and tools.

Common SSL/TLS Errors

1. Cipher Mismatch (SSL_ERROR_NO_CYPHER_OVERLAP)

Client and server don’t agree on encryption algorithms.

2. Port Misuse (SSL_ERROR_RX_RECORD_TOO_LONG)

HTTPS connection attempted on a port not configured for SSL/TLS (often HTTP port 80).

3. Invalid Certificate (SSL_ERROR_BAD_CERT_DOMAIN)

The certificate presented by the server does not match the domain name the client is trying to access.

4. Incomplete Chain (unable to get local issuer certificate)

The server is not presenting the necessary intermediate certificates that allow the client to trace the server's certificate back to a trusted root CA.

Useful Commands & Tools

Check with OpenSSL:

openssl s_client -connect yourdomain.com:443 -servername yourdomain.com

Provides detailed SSL handshake information and certificate details.

Debug with Curl:

curl -v https://yourdomain.com

Shows verbose output of the connection attempt, including SSL handshake steps.

Browser Developer Tools:

  • Chrome: DevTools → Security tab (shows certificate details, connection status, and errors).
  • Firefox: Click the 🔒 icon in the address bar → "Connection secure" → "More information" → "View Certificate".

Server Logs:

  • Apache: Typically /var/log/apache2/error.log or similar.
  • Nginx: Typically /var/log/nginx/error.log or similar.

Check these for specific error messages related to SSL/TLS failures.

Basic SSL Configurations

Nginx Example

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name ssldoctor.in www.ssldoctor.in;

    ssl_certificate /etc/nginx/ssl/ssldoctor.in/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/ssldoctor.in/privkey.pem;

    # Modern SSL Settings
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    # Add HSTS header
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

    # ... other Nginx configurations (root, location blocks, etc.)
}

Apache Example

<IfModule mod_ssl.c>
  <VirtualHost *:443>
      ServerAdmin webmaster@ssldoctor.in
      ServerName ssldoctor.in
      ServerAlias www.ssldoctor.in

      DocumentRoot /var/www/ssldoctor.in/html

      SSLEngine on
      SSLCertificateFile /etc/apache2/ssl/ssldoctor.in/certificate.crt
      SSLCertificateKeyFile /etc/apache2/ssl/ssldoctor.in/private.key
      SSLCertificateChainFile /etc/apache2/ssl/ssldoctor.in/ca_bundle.crt

      # Modern SSL Settings
      SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1
      SSLCipherSuite          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
      SSLHonorCipherOrder     off
      SSLSessionTickets       off

      # HSTS Header
      Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"

      # ... other Apache configurations
  </VirtualHost>
</IfModule>