SSL Certificate Checker Complete Guide: Verify, Monitor & Fix Certificate Errors (2025)
Your e-commerce site was processing thousands of orders yesterday. This morning, customers see “Your connection is not private” and abandon their carts. Your SSL certificate expired overnight.
You just deployed your new website. Chrome shows “Not Secure” with a crossed-out padlock. Google Search Console sends warnings about security issues. Your rankings start dropping.
You migrated to a new hosting provider. Half your users get SSL certificate mismatch errors. Your support tickets triple overnight. Revenue tanks by 60%.
The reality is brutal: SSL certificate problems cost businesses an average of $5,600 per minute in lost revenue according to Gartner research. Worse, Google demotes sites with SSL errors, expired certificates trigger instant browser warnings that 84% of users refuse to bypass, and your competitors are one security mistake away from stealing your traffic.
But here’s what most developers don’t realize: SSL certificate problems are 100% preventable and fixable—if you know what to check, when to check it, and how to interpret the results.
This guide teaches you exactly that. You’ll learn how SSL/TLS certificates actually work under the hood, how to verify certificate validity and security configurations with command-line tools and automated checkers, how to troubleshoot every common SSL error with step-by-step fixes backed by RFC standards, how to implement automated monitoring that prevents expiration disasters before they happen, and how to optimize your HTTPS setup for maximum security, performance, and PCI DSS compliance.
By the end of this guide, you’ll diagnose SSL issues faster than most developers can Google the error message. Let’s begin.
Quick Answer: SSL Certificate Essentials
Don’t have time for 10,000 words? Here’s what you need to know right now:
- What SSL certificates do: Enable HTTPS encryption protecting data during transmission between browsers and servers using TLS 1.2/1.3 protocols
- Most critical check: Certificate expiration date—expired certificates cause complete site blockage with zero grace period
- How often to check: Implement automated daily monitoring with alerts at 30, 14, and 7 days before expiration
- Best checking tool: Use our SSL Certificate Checker for instant validation combined with SSL Labs for comprehensive A+ grading
- Common certificate lifetimes: Let’s Encrypt (90 days), Commercial DV/OV (1 year maximum), industry limit (398 days per CA/Browser Forum Ballot SC22)
- Quick SSL error fix: Check expiration date → Verify domain name match → Test certificate chain completeness → Clear browser/DNS caches → Restart web server
- Free vs Paid certificates: Let’s Encrypt provides identical 256-bit encryption strength to $1000/year EV certificates—difference is validation level only
Still here? Perfect. Let’s master SSL certificate checking from fundamentals to advanced troubleshooting.
What is an SSL Certificate? (The Fundamentals)
SSL/TLS Certificate Definition
An SSL certificate is a digital credential that enables HTTPS encryption between web browsers and servers. Despite the name, modern “SSL certificates” actually use the TLS (Transport Layer Security) protocol—SSL itself was deprecated in 2015 due to security vulnerabilities like the POODLE attack.
SSL certificates follow the X.509 standard defined in RFC 5280, which specifies exactly what information certificates must contain:
Certificate Contents:
- Subject: Domain name(s) the certificate covers (e.g.,
example.com,www.example.com) - Issuer: Certificate Authority (CA) that verified and signed the certificate
- Public Key: Cryptographic key used for encryption (typically 2048-4096 bit RSA or 256-bit ECDSA)
- Validity Period:
notBeforeandnotAfterdates (maximum 398 days since September 2020) - Signature Algorithm: How the CA cryptographically signed the certificate (e.g., SHA-256 with RSA)
- Subject Alternative Names (SAN): Additional domains covered by the certificate
- Key Usage: What the certificate can be used for (digital signature, key encipherment)
The term “SSL certificate” persists in industry terminology due to branding and historical recognition, but technically all modern certificates use TLS 1.2 or TLS 1.3 protocols, not the deprecated SSL protocols.
How SSL Certificates Work (The TLS Handshake)
When you visit https://orbit2x.com, your browser and our server perform a complex cryptographic dance called the TLS handshake. This happens in milliseconds, invisible to users, but critical for security:
TLS 1.3 Handshake Process (Simplified):
1. Client Hello (Browser → Server)
- Supported TLS versions (1.2, 1.3)
- Supported cipher suites (encryption algorithms)
- Random number for key generation
- Supported elliptic curves (for ECDHE key exchange)
2. Server Hello + Certificate (Server → Browser)
- Selected TLS version (1.3)
- Selected cipher suite (e.g., TLS_AES_256_GCM_SHA384)
- Server's SSL certificate chain
- Server random number
- Key exchange parameters
3. Certificate Validation (Browser)
- Verify certificate not expired (notBefore < now < notAfter)
- Verify domain matches (orbit2x.com in SAN field)
- Verify signature from trusted CA
- Verify complete certificate chain to root CA
- Check for revocation via OCSP or CRL
4. Key Exchange (Browser ↔ Server)
- Browser generates pre-master secret
- Encrypted using server's public key (from certificate)
- Both sides derive session keys using ECDHE
- Forward secrecy guaranteed (keys can't be recovered later)
5. Encrypted Session Begins
- All subsequent data encrypted with AES-256-GCM
- Perfect Forward Secrecy protects past communications
- HTTP/2 multiplexing enabled over secure channel
Typical handshake time: 50-100ms for initial connection, <5ms for resumed sessions with session tickets.
TLS 1.3 improved this process by reducing round trips from 2-RTT to 1-RTT, and supporting 0-RTT (zero round-trip time) for resumed sessions—making HTTPS faster than ever.
Why SSL Certificates Are Critical in 2025
SSL certificates aren’t optional anymore. They’re mandatory for professional web presence, regulatory compliance, and competitive advantage. Here’s why:
1. Data Encryption and Protection
SSL/TLS establishes encrypted tunnels using AES-GCM cipher suites with 128-256 bit keys and ECDHE key exchange providing perfect forward secrecy. This protects:
- Login credentials: Passwords, API keys, session tokens
- Payment information: Credit card numbers, billing addresses
- Personal data: Names, emails, phone numbers, addresses
- Healthcare information: Protected Health Information (PHI) under HIPAA
- Financial data: Account numbers, transactions (PCI DSS requirement)
Without encryption, attackers on public WiFi, compromised routers, or ISP equipment can perform man-in-the-middle (MITM) attacks intercepting plaintext traffic. According to Verizon’s Data Breach Investigations Report, 82% of breaches involve human elements—expired certificates are preventable vulnerabilities.
2. Search Engine Rankings (Google’s HTTPS Ranking Signal)
Google announced HTTPS as a ranking factor in August 2014, giving HTTPS sites preference over HTTP equivalents in search results. By July 2018, Chrome began marking all HTTP sites as “Not Secure” in the address bar.
The SEO impact is measurable:
- HTTPS sites typically rank 5-10% higher than HTTP equivalents
- Expired SSL certificates cause immediate de-indexing of secure URLs
- Certificate warnings increase bounce rates by 70-90%
- Core Web Vitals scores improve with HTTP/2 (HTTPS-only)
After implementing SSL, verify proper redirects with our HTTP Status Checker to ensure all HTTP URLs redirect to HTTPS with 301 permanent redirects.
3. User Trust and Conversion Optimization
The padlock icon and “Secure” label are critical trust signals for e-commerce. Research shows:
- 84% of users abandon purchases when encountering SSL certificate warnings (GlobalSign research)
- Conversion rates increase 15-30% after implementing HTTPS on checkout pages
- Brand trust improves measurably with valid certificates vs “Not Secure” warnings
- Mobile users are particularly sensitive to security indicators
During peak sales periods (Black Friday, holiday shopping, product launches), certificate expiration can cost businesses hundreds of thousands in lost revenue within hours.
4. Regulatory Compliance Requirements
SSL/TLS encryption is mandatory for multiple compliance frameworks:
- PCI DSS 4.0: Requires TLS 1.2 minimum, deprecates TLS 1.1 and all SSL versions (mandatory since June 2018)
- GDPR Article 32: Requires “appropriate technical measures” including encryption of personal data in transit
- HIPAA Security Rule: Transmission Security (§164.312(e)) requires encryption of ePHI during transmission
- SOC 2 Trust Principles: Encryption in transit (CC6.6) is essential for security certification
- CCPA: California Consumer Privacy Act requires reasonable security measures including encryption
Non-compliance results in fines ranging from $5,000 per violation (PCI DSS) to 4% of annual revenue (GDPR).
Internal Tool Links for Complete Security Audit:
- SSL Certificate Checker - Verify certificate validity and expiration
- HTTP Headers Analyzer - Check security headers (HSTS, CSP, X-Frame-Options)
- DNS Lookup Tool - Verify CAA records authorizing certificate issuance
- HTTP Status Checker - Test HTTP to HTTPS redirect chains
SSL Certificate Types and Validation Levels
Not all SSL certificates are created equal. Understanding validation levels, scope types, and CA selection criteria ensures you choose the right certificate for your use case.
Validation Level Classification
Certificate Authorities verify different levels of identity before issuing certificates. The three validation tiers defined by the CA/Browser Forum Baseline Requirements are:
Domain Validation (DV) Certificates
What DV Validates: Domain control only—proves you control the domain name, nothing about your organization.
Validation Methods:
- DNS-01 Challenge: Add TXT record to DNS (e.g.,
_acme-challenge.example.com) - HTTP-01 Challenge: Place file at
http://example.com/.well-known/acme-challenge/ - TLS-ALPN-01 Challenge: Certificate presented during TLS handshake
- Email Validation: Click link sent to admin@example.com
Issuance Time: 2-10 minutes (fully automated with ACME protocol)
Cost: Free (Let’s Encrypt, ZeroSSL, Buypass) to $50/year
Encryption Strength: 2048-4096 bit RSA or 256-bit ECDSA with TLS 1.2/1.3 (identical to OV/EV)
Use Cases:
- Personal blogs and portfolios
- Development and staging environments
- Most business websites and SaaS platforms
- APIs and microservices
- Internal applications
Browser Display: Standard padlock icon, no organization name shown
Market Share: Approximately 95% of all SSL certificates are DV (Let’s Encrypt alone issues over 300 million active certificates)
Recommendation: DV certificates from Let’s Encrypt are perfect for 99% of websites. The encryption is identical to paid certificates—only the validation level differs.
Organization Validation (OV) Certificates
What OV Validates: Domain control + legal entity existence and operational status.
Validation Process:
- Domain control verification (same as DV)
- Business registry database check (Dun & Bradstreet, Secretary of State records)
- Phone verification with organization representative
- Confirmation of organization name, address, and jurisdiction
- Verification that organization is active and operational
Issuance Time: 1-3 business days (manual human review required)
Cost: $50-300/year depending on CA and features
Certificate Details Display: Organization name, city, state/province, country visible when viewing certificate
Use Cases:
- Corporate websites requiring organization identification
- B2B SaaS platforms and enterprise software
- Government and educational institutions
- Mid-size to large company public websites
- Any site where proving organizational identity matters
Browser Display: Standard padlock icon + organization name visible in certificate details (not in address bar)
Advantage Over DV: Provides additional assurance of legitimate organization behind website (helps differentiate from phishing sites)
Extended Validation (EV) Certificates
What EV Validates: Extensive verification of legal, physical, and operational existence per CA/Browser Forum EV Guidelines.
Rigorous Validation Process:
- Legal existence verification through government business registries
- Physical address verification via government databases or site visits
- Operational existence confirmation (active business for 3+ years)
- Exclusive right to use domain name
- Final cross-reference and approval by CA legal/compliance team
- Callback to organization’s verified phone number
- Review of articles of incorporation, business licenses, or equivalent
Issuance Time: 3-7 business days (extensive manual vetting)
Cost: $150-1000+/year depending on CA and certificate scope
Certificate Details: Full organization name, jurisdiction, registration number visible
Use Cases:
- Financial institutions and banks
- E-commerce platforms processing high transaction volumes
- Healthcare organizations handling PHI
- Government agencies requiring maximum assurance
- Any organization where trust is critical to business
Browser Display History:
- Pre-2019: Green address bar with organization name (Chrome, Firefox, Safari)
- 2019-Present: Standard padlock icon (EV indicators removed by all major browsers)
Important Note: Major browsers (Chrome, Firefox, Safari, Edge) removed the green address bar in 2019 after research showed users didn’t understand or notice it. Modern browsers show EV certificates identically to DV/OV certificates in the address bar—organization name only visible by clicking padlock and viewing certificate details.
Current Recommendation: Given the browser UI changes and high cost, EV certificates now offer minimal user-facing benefits. Only purchase EV if required by:
- Regulatory compliance (specific industry regulations)
- Contractual obligations (partner/vendor requirements)
- Internal security policies (enterprise mandates)
For most organizations, DV or OV certificates provide identical encryption and adequate validation.
Certificate Scope Types (Domain Coverage)
Beyond validation level, certificates differ in how many domains they cover:
Single-Domain Certificates
Covers: One fully qualified domain name (FQDN) exactly
Examples:
- Certificate for
example.comonly - Does NOT cover
www.example.com(different subdomain) - Does NOT cover
mail.example.comorshop.example.com
Cost: Lowest ($0-50/year)
Use Case: Single-site deployments where you control DNS and can consolidate on one domain
Common Issue: Users accessing www.example.com get certificate errors if certificate only lists example.com
Solution: Either:
- Add both to SAN field when requesting certificate
- Configure 301 redirect from www to non-www (or vice versa)
- Use wildcard certificate instead
Wildcard Certificates
Covers: Unlimited same-level subdomains using asterisk notation
Format: *.example.com
Includes:
blog.example.comshop.example.comapi.example.comadmin.example.com- Any other first-level subdomain
Does NOT Cover:
example.com(root domain—must add separately to SAN)www.example.com(technically yes, but root domain not included automatically)admin.shop.example.com(multi-level subdomain—would need*.shop.example.com)
Cost: 2-5x single-domain cost ($50-300/year)
Use Cases:
- Multi-tenant SaaS platforms (user1.app.com, user2.app.com)
- Multiple subdomains for services (api.example.com, cdn.example.com)
- Development environments with dynamic subdomain creation
- Microservices architectures
Let’s Encrypt Wildcard:
# Requires DNS-01 validation (not HTTP-01)
sudo certbot certonly --manual --preferred-challenges dns \
-d example.com \
-d *.example.com
Security Consideration: Wildcard certificates mean compromising the private key exposes all subdomains. For security-critical deployments, separate certificates per service provide better isolation.
Multi-Domain (SAN/UCC) Certificates
Covers: Multiple distinct domain names in Subject Alternative Names (SAN) field
Format: List of specific domains
Example SAN List:
- example.com
- www.example.com
- shop.example.com
- example.org
- example.net
- shop.example.org
Capacity: Typically 5-100 domains per certificate (CA-dependent)
Cost: $50-500/year depending on number of domains and validation level
Use Cases:
- Multiple brand domains under one organization
- International domains (.com, .co.uk, .de, etc.)
- Consolidating multiple sites on one certificate (easier management)
- Exchange/Office 365 servers requiring multiple service names
Let’s Encrypt Multi-Domain:
sudo certbot certonly --nginx \
-d example.com \
-d www.example.com \
-d shop.example.com \
-d api.example.com \
-d mail.example.com
Management Advantage: Update one certificate to add/remove domains instead of managing separate certificates
Management Disadvantage: All domains must renew simultaneously—can’t stagger renewals for risk management
Choosing a Certificate Authority (CA)
Certificate Authorities must be included in the Common CA Database (CCADB) maintained by Mozilla to achieve universal browser trust. Evaluate CAs based on these factors:
Free Certificate Authorities
- Validation: DV only
- Lifetime: 90 days (encourages automation)
- Automation: Full ACME protocol support
- Rate Limits: 50 certificates per domain per week
- Active Certificates: 300+ million
- Trust: Included in all major browsers and OS trust stores
- Cost: Free forever (nonprofit backed by sponsors)
- Best For: 99% of websites—blogs, businesses, e-commerce, SaaS
- Support: Community forums and documentation
- Validation: DV
- Lifetime: 90 days
- Automation: ACME support + manual dashboard
- Features: Free and paid tiers, commercial support available
- API Access: RESTful API for automation
- Best For: Organizations wanting dashboard + ACME flexibility
- Validation: DV
- Lifetime: 180 days (longer than Let’s Encrypt)
- Automation: ACME support
- Region: European CA (Norway)
- Best For: European organizations, longer validity preference
Commercial Certificate Authorities
- Validation: DV, OV, EV available
- Features: Premium CA, highest warranty ($1.75M), 24/7 phone support
- Trust: Highest reputation, merged with Symantec CA business
- API: Full automation via DigiCert CertCentral API
- Best For: Enterprise organizations, financial services, large e-commerce
- Cost: $$$ (premium pricing)
Sectigo (formerly Comodo)
- Validation: DV, OV, EV
- Position: Largest commercial CA by volume
- Pricing: Mid-tier (competitive)
- Features: Wide range of products, reseller program
- Best For: Mid-size organizations wanting paid support at reasonable cost
- Validation: DV, OV, EV
- Specialization: Enterprise PKI, IoT certificates, managed services
- Features: Certificate lifecycle management platforms
- Best For: Large enterprises, IoT deployments, managed PKI needs
- Validation: DV, OV, EV
- Integration: Bundled with hosting, easy cPanel integration
- Best For: Small businesses using GoDaddy hosting wanting simplicity
- Note: Higher pricing, basic features vs specialized CAs
CA Selection Criteria Checklist
When choosing a Certificate Authority, evaluate:
✅ Root Certificate Trust
- Included in Mozilla’s trusted CA list
- Included in Apple’s root certificates
- Included in Microsoft’s trusted root program
- Included in Chrome Root Store
✅ Automation Support
- ACME protocol compatibility (RFC 8555)
- RESTful API for bulk operations
- Webhook notifications for expiration
- CI/CD pipeline integration
✅ Security and Compliance
- Certificate Transparency automatic logging (RFC 6962)
- OCSP stapling support (RFC 6960)
- CRL distribution points
- Audit logs and compliance reports
✅ Operational Factors
- Issuance speed (minutes for DV vs days for OV/EV)
- Revocation process and timeline
- Support availability (community vs 24/7 phone)
- Warranty/liability coverage (varies from $0 to $1.75M)
- Multi-year pricing discounts
✅ Management Features
- Bulk certificate management dashboard
- Expiration monitoring and alerts
- Team collaboration features
- Historical certificate tracking
Recommendation for 2025: Start with Let’s Encrypt for DV certificates. Their ACME automation, 90-day lifetimes encouraging automation, and zero cost make them ideal for modern DevOps workflows. Only consider commercial CAs if you specifically need OV/EV validation levels, premium support, or high-value warranties.
Verify your certificate choice with our SSL Certificate Checker, and ensure your DNS CAA records explicitly authorize your chosen CA to prevent unauthorized certificate issuance.
How to Check SSL Certificates (Methods and Tools)
Checking SSL certificates requires different approaches depending on your goals: quick manual verification, comprehensive security audits, automated monitoring, or troubleshooting specific errors. Here’s every method from simplest to most advanced.
Browser-Based SSL Checking (Manual Verification)
Every modern browser includes built-in SSL certificate inspection—perfect for quick manual checks.
Chrome/Edge (Chromium-Based)
- Click the padlock icon in address bar (left of URL)
- Select “Connection is secure” → “Certificate is valid”
- View certificate details:
- General tab: Issued to (domain), Issued by (CA), Valid from/to dates
- Details tab: Full certificate chain, signature algorithm, public key, extensions
- Certification Path: Visualize chain from end-entity → intermediate → root CA
Quick Checks:
- Validity dates: Ensure current date between “Valid from” and “Expires on”
- Issued to: Matches domain you’re visiting
- Issued by: Recognized CA (Let’s Encrypt, DigiCert, etc.)
- Subject Alternative Names: Lists all covered domains
Firefox
- Click padlock icon → Connection secure → More information
- Security tab → View Certificate button
- Examine certificate details in dedicated viewer
Firefox Advantage: Better certificate chain visualization and detailed security information
Safari (macOS)
- Click padlock → Show Certificate
- Trust chain displayed with expandable certificate details
- Trust Settings show system trust status
Browser Method Limitations
- Only checks certificate served to your specific connection
- Doesn’t test from multiple locations (important for CDNs)
- Doesn’t verify full OCSP/CRL revocation status
- Can’t test historical certificate changes
- No cipher suite or protocol analysis
- Single point-in-time check (no monitoring)
Use browser checking for: Quick verification during development, confirming certificate installation after renewal, initial troubleshooting of “Not Secure” warnings.
Using SSL Certificate Checker Tools
Online SSL checkers provide comprehensive analysis beyond browser capabilities.
Our SSL Certificate Checker (orbit2x.com/ssl)
Our tool provides instant SSL certificate analysis including:
Certificate Validation:
- Expiration date with countdown (days remaining)
- Domain name matching verification
- Certificate Authority identification
- Full certificate chain analysis
- Subject Alternative Names (SAN) list
Security Analysis:
- TLS protocol version detection (1.2, 1.3)
- Cipher suite evaluation
- Weak algorithm detection
- Forward secrecy verification
Practical Monitoring:
- Expiration alerts (configure 30/14/7 day warnings)
- Email/webhook notifications
- Historical certificate tracking
- Multi-domain batch checking
Why Use Our Tool:
- No installation required—instant browser-based checking
- Fast results (<5 seconds average)
- Mobile-friendly interface
- Free unlimited checks
- Integrates with our DNS Lookup and Security Headers tools
Perfect for: Daily operations, expiration monitoring, quick security audits, client website verification
SSL Labs Server Test (ssllabs.com/ssltest)
The industry standard for comprehensive SSL/TLS security grading.
Comprehensive Analysis:
- Overall Grade: A+ to F rating (target: A+)
- Protocol Support: Tests SSL 2.0/3.0, TLS 1.0/1.1/1.2/1.3
- Cipher Suites: Ranks all supported ciphers by strength
- Handshake Simulation: Tests compatibility with 40+ clients (browsers, mobile, API clients)
- Vulnerability Detection: POODLE, BEAST, CRIME, BREACH, Heartbleed, etc.
- Certificate Chain: Validates complete chain including OCSP stapling
- Forward Secrecy: Confirms ECDHE/DHE support
- HSTS: Checks HTTP Strict Transport Security header
Grading Criteria:
- A+: Perfect score + HSTS with long max-age
- A: Strong security, no known vulnerabilities, modern protocols
- B: Minor issues (e.g., TLS 1.0 still enabled)
- C: Moderate issues (weak cipher suites)
- F: Critical failures (expired certificate, SSL 3.0 enabled)
Scan Time: 60-90 seconds for complete analysis
Limitations:
- Slower than quick checkers (full handshake simulation)
- Public results (cached for 24 hours by default)
- No monitoring/alerting features
Best For: Quarterly security audits, achieving PCI DSS compliance, benchmarking against industry standards, troubleshooting complex SSL/TLS configuration issues
Certificate Transparency Logs (crt.sh)
Certificate Transparency (RFC 6962) requires all publicly trusted certificates to be logged to independent CT logs. crt.sh aggregates these logs for monitoring.
Use Cases:
- Monitor all certificates issued for your domain: Detect unauthorized issuance
- Track competitor SSL strategies: See their CA choices and certificate lifetimes
- Audit certificate history: Review all past certificates for forensics
- Detect typosquatting: Monitor similar domain certificates (e.g., examp1e.com)
- Verify CT compliance: Confirm your certificates appear in logs
Search Syntax:
crt.sh/?q=example.com # Exact domain
crt.sh/?q=%.example.com # All subdomains
crt.sh/?q=example.com&output=json # JSON API for automation
Monitoring Strategy:
# Daily cron job to alert on new certificates
curl -s "https://crt.sh/?q=example.com&output=json" | \
jq '.[] | select(.not_after > now | strftime("%Y-%m-%d"))' | \
# Send to monitoring system if new certs found
Integration: Set up automated monitoring to receive alerts when new certificates are issued for your domains—essential for detecting:
- Compromised CA accounts
- Social engineering attacks requesting certificates
- Subdomain takeover attempts
- Employee mistakes (duplicate/wrong certificates)
Command-Line SSL Checking (Advanced Users)
Command-line tools provide scriptable, automated SSL verification perfect for CI/CD pipelines, monitoring systems, and troubleshooting.
Using OpenSSL (Universal)
OpenSSL is the standard SSL/TLS toolkit available on Linux, macOS, and Windows (via Git Bash, WSL, or native install).
Check Certificate Details:
# Full connection test with certificate details
openssl s_client -connect example.com:443 -servername example.com
# Extract and view certificate
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
openssl x509 -noout -text
# Check expiration dates only
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
openssl x509 -noout -dates
# Output:
# notBefore=Jan 15 00:00:00 2025 GMT
# notAfter=Apr 15 23:59:59 2025 GMT
# Calculate days until expiration
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -noout -enddate | cut -d= -f2 | \
xargs -I {} date -d "{}" +%s | \
awk "{print int(((\$1 - $(date +%s)) / 86400))}"
Test Specific TLS Versions:
# Test TLS 1.3 support
openssl s_client -connect example.com:443 -tls1_3
# Test TLS 1.2
openssl s_client -connect example.com:443 -tls1_2
# Test deprecated TLS 1.1 (should fail on modern servers)
openssl s_client -connect example.com:443 -tls1_1
# Expected: "no protocols available" or connection refused
Verify Certificate Chain Completeness:
# Display full certificate chain
openssl s_client -connect example.com:443 -showcerts
# Expected output shows multiple certificates:
# Certificate chain
# 0 s:CN = example.com (end-entity/server certificate)
# 1 s:CN = R3, O = Let's Encrypt (intermediate CA)
# 2 s:CN = ISRG Root X1 (root CA - may be omitted)
# Verify chain against system CA bundle
openssl s_client -connect example.com:443 \
-CAfile /etc/ssl/certs/ca-certificates.crt
# Should return: "Verify return code: 0 (ok)"
Check Subject Alternative Names (SANs):
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
openssl x509 -noout -text | grep -A1 "Subject Alternative Name"
# Output:
# Subject Alternative Name:
# DNS:example.com, DNS:www.example.com, DNS:mail.example.com
Test OCSP Stapling:
echo | openssl s_client -connect example.com:443 -status 2>/dev/null | \
grep "OCSP Response Status"
# Expected: OCSP Response Status: successful (0x0)
Using curl (Quick Checks)
# Basic certificate information
curl -vI https://example.com 2>&1 | grep -i "SSL\|TLS\|certificate"
# Show certificate expiration with verbose output
curl --insecure -vvI https://example.com 2>&1 | grep "expire date"
# Test with specific TLS version
curl --tlsv1.3 https://example.com
curl --tlsv1.2 https://example.com
# Follow redirects and test final destination
curl -L -vI https://example.com 2>&1 | grep "SSL"
# Time TLS handshake (performance testing)
curl -w "time_connect: %{time_connect}\ntime_appconnect: %{time_appconnect}\ntime_total: %{time_total}\n" \
-o /dev/null -s https://example.com
# time_appconnect - time_connect = TLS handshake time
Using nmap (Security Scanning)
# Enumerate all SSL/TLS cipher suites supported by server
nmap --script ssl-enum-ciphers -p 443 example.com
# Output shows:
# - TLS versions supported
# - Cipher suites per version ranked by strength
# - Overall grade (A, B, C, etc.)
# - Warnings about weak/insecure ciphers
# Check certificate details and validation
nmap --script ssl-cert -p 443 example.com
# Output includes:
# - Certificate subject and issuer
# - Validity dates
# - Subject Alternative Names
# - SHA-256 fingerprint
# Check for known SSL/TLS vulnerabilities
nmap --script ssl-* -p 443 example.com
# Tests for: Heartbleed, POODLE, DROWN, etc.
Using testssl.sh (Comprehensive CLI Auditing)
testssl.sh is a powerful shell script providing SSL Labs-quality testing from command line:
# Install
git clone https://github.com/drwetter/testssl.sh.git
cd testssl.sh
# Full test (equivalent to SSL Labs)
./testssl.sh example.com
# Quick check (certificates and protocols only)
./testssl.sh --fast example.com
# Check specific TLS version
./testssl.sh --tls1_3 example.com
# JSON output for automation
./testssl.sh --jsonfile report.json example.com
# Check for specific vulnerabilities
./testssl.sh --heartbleed --poodle --drown example.com
Best For: Automated security testing in CI/CD pipelines, detailed vulnerability assessments, batch testing multiple servers
Programmatic SSL Checking (API Integration)
Integrate certificate checking into applications, monitoring systems, and automation workflows with code.
Python Example (Production-Ready)
import ssl
import socket
from datetime import datetime
from cryptography import x509
from cryptography.hazmat.backends import default_backend
def check_ssl_certificate(hostname, port=443):
"""
Check SSL certificate and return comprehensive details.
Returns:
dict: Certificate details including expiration, issuer, SANs, etc.
"""
context = ssl.create_default_context()
try:
# Establish connection and get certificate
with socket.create_connection((hostname, port), timeout=10) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
# Get DER-encoded certificate
der_cert = ssock.getpeercert(binary_form=True)
# Parse certificate with cryptography library
cert = x509.load_der_x509_certificate(der_cert, default_backend())
# Extract expiration dates
not_before = cert.not_valid_before
not_after = cert.not_valid_after
days_remaining = (not_after - datetime.now()).days
# Extract Subject Alternative Names
try:
san_extension = cert.extensions.get_extension_for_oid(
x509.ExtensionOID.SUBJECT_ALTERNATIVE_NAME
)
san_list = [name.value for name in san_extension.value]
except x509.ExtensionNotFound:
san_list = []
# Extract subject and issuer
subject = cert.subject.rfc4514_string()
issuer = cert.issuer.rfc4514_string()
return {
'valid': True,
'hostname': hostname,
'subject': subject,
'issuer': issuer,
'not_before': not_before,
'not_after': not_after,
'days_remaining': days_remaining,
'expired': days_remaining < 0,
'expiring_soon': days_remaining < 30,
'san_list': san_list,
'serial_number': cert.serial_number,
'signature_algorithm': cert.signature_algorithm_oid._name,
'version': cert.version.name
}
except socket.timeout:
return {'valid': False, 'error': 'Connection timeout'}
except socket.gaierror:
return {'valid': False, 'error': 'DNS resolution failed'}
except ssl.SSLError as e:
return {'valid': False, 'error': f'SSL Error: {str(e)}'}
except Exception as e:
return {'valid': False, 'error': f'Unexpected error: {str(e)}'}
# Usage
result = check_ssl_certificate('orbit2x.com')
if result['valid']:
print(f"Certificate for {result['hostname']}")
print(f"Issuer: {result['issuer']}")
print(f"Expires: {result['not_after']}")
print(f"Days remaining: {result['days_remaining']}")
print(f"SANs: {', '.join(result['san_list'])}")
if result['expiring_soon']:
print(f"⚠️ WARNING: Certificate expires in {result['days_remaining']} days!")
else:
print(f"❌ Error: {result['error']}")
Node.js Example (Async/Await)
const https = require('https');
const tls = require('tls');
/**
* Check SSL certificate for a hostname
* @param {string} hostname - Domain to check
* @param {number} port - Port number (default 443)
* @returns {Promise<Object>} Certificate details
*/
function checkSSLCertificate(hostname, port = 443) {
return new Promise((resolve, reject) => {
const options = {
host: hostname,
port: port,
method: 'HEAD',
rejectUnauthorized: false // Allow self-signed for inspection
};
const req = https.request(options, (res) => {
const cert = res.socket.getPeerCertificate();
if (!cert || Object.keys(cert).length === 0) {
reject(new Error('No certificate found'));
return;
}
const validTo = new Date(cert.valid_to);
const validFrom = new Date(cert.valid_from);
const now = new Date();
const daysRemaining = Math.floor((validTo - now) / (1000 * 60 * 60 * 24));
// Extract Subject Alternative Names
const subjectaltname = cert.subjectaltname
? cert.subjectaltname.split(', ').map(san => san.replace('DNS:', ''))
: [];
resolve({
valid: true,
hostname: hostname,
subject: cert.subject,
issuer: cert.issuer,
valid_from: validFrom,
valid_to: validTo,
days_remaining: daysRemaining,
expired: daysRemaining < 0,
expiring_soon: daysRemaining < 30,
fingerprint: cert.fingerprint,
fingerprint256: cert.fingerprint256,
serial_number: cert.serialNumber,
san_list: subjectaltname
});
});
req.on('error', (error) => {
reject(error);
});
req.end();
});
}
// Usage with async/await
(async () => {
try {
const result = await checkSSLCertificate('orbit2x.com');
console.log(`Certificate for ${result.hostname}`);
console.log(`Issuer: ${result.issuer.O}`);
console.log(`Valid from: ${result.valid_from.toISOString()}`);
console.log(`Valid to: ${result.valid_to.toISOString()}`);
console.log(`Days remaining: ${result.days_remaining}`);
console.log(`SANs: ${result.san_list.join(', ')}`);
if (result.expiring_soon) {
console.log(`⚠️ WARNING: Certificate expires in ${result.days_remaining} days!`);
}
} catch (error) {
console.error(`❌ Error checking certificate: ${error.message}`);
}
})();
Bash Monitoring Script (Cron-Ready)
#!/bin/bash
# ssl_monitor.sh - Alert on certificates expiring within 30 days
# Usage: ./ssl_monitor.sh example.com [alert_days]
set -euo pipefail
DOMAIN="${1:-}"
ALERT_DAYS="${2:-30}"
SLACK_WEBHOOK="${SLACK_WEBHOOK_URL:-}"
if [ -z "$DOMAIN" ]; then
echo "Usage: $0 <domain> [alert_days]"
exit 1
fi
# Get certificate expiration date
EXPIRY=$(echo | openssl s_client -connect "${DOMAIN}:443" -servername "${DOMAIN}" 2>/dev/null | \
openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
if [ -z "$EXPIRY" ]; then
echo "❌ Failed to retrieve certificate for ${DOMAIN}"
exit 1
fi
# Calculate days remaining (works on Linux and macOS)
if date --version >/dev/null 2>&1; then
# GNU date (Linux)
EXPIRY_EPOCH=$(date -d "${EXPIRY}" +%s)
else
# BSD date (macOS)
EXPIRY_EPOCH=$(date -j -f "%b %d %H:%M:%S %Y %Z" "${EXPIRY}" +%s)
fi
NOW_EPOCH=$(date +%s)
DAYS_REMAINING=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
echo "Domain: ${DOMAIN}"
echo "Expires: ${EXPIRY}"
echo "Days remaining: ${DAYS_REMAINING}"
# Alert if expiring soon
if [ "$DAYS_REMAINING" -lt "$ALERT_DAYS" ]; then
MESSAGE="⚠️ SSL ALERT: ${DOMAIN} expires in ${DAYS_REMAINING} days (${EXPIRY})"
echo "$MESSAGE"
# Send to Slack if webhook configured
if [ -n "$SLACK_WEBHOOK" ]; then
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"${MESSAGE}\"}" \
"$SLACK_WEBHOOK"
fi
# Send email (requires mail command)
if command -v mail &> /dev/null; then
echo "$MESSAGE" | mail -s "SSL Certificate Expiring: ${DOMAIN}" admin@example.com
fi
exit 1
else
echo "✅ Certificate valid for ${DAYS_REMAINING} more days"
exit 0
fi
Cron Schedule (Daily at 9 AM):
0 9 * * * /opt/scripts/ssl_monitor.sh example.com 30 >> /var/log/ssl_monitor.log 2>&1
0 9 * * * /opt/scripts/ssl_monitor.sh www.example.com 30 >> /var/log/ssl_monitor.log 2>&1
0 9 * * * /opt/scripts/ssl_monitor.sh api.example.com 30 >> /var/log/ssl_monitor.log 2>&1
Tool Integration Workflow:
After checking certificates with any method:
- Verify DNS CAA records authorize your CA to issue certificates
- Check security headers include HSTS with proper max-age
- Test HTTP to HTTPS redirects return 301 status codes
- Confirm server IP geolocation matches expected CDN/hosting location
Common SSL Certificate Errors and Solutions
SSL errors range from simple expiration issues to complex chain validation failures. This section provides systematic diagnosis and fixes for every common error you’ll encounter.
Certificate Expired (ERR_CERT_DATE_INVALID)
Browser Error Messages:
- Chrome: “Your connection is not private” +
NET::ERR_CERT_DATE_INVALID - Firefox:
SEC_ERROR_EXPIRED_CERTIFICATE- “The certificate expired on [date]” - Safari: “This Connection Is Not Private” - Certificate is not valid
- Edge: “Your connection isn’t private” +
DLG_FLAGS_SEC_CERT_DATE_INVALID
What Happens:
- 100% traffic blockage - users cannot access website without clicking through warnings
- Most users (95%+) abandon - security warnings are effective deterrents
- Google de-indexes HTTPS URLs within hours of expiration
- SEO rankings plummet - site disappears from search results
- APIs fail immediately - automated clients refuse expired certificates
- Email delivery disrupted if mail server uses same expired certificate
- Revenue loss immediate - e-commerce loses 100% of orders during outage
Root Causes:
-
Certificate reached notAfter date: CA/Browser Forum limits certificates to 398 days maximum since September 2020. Let’s Encrypt certificates expire after 90 days.
-
Automated renewal failed: Certbot cron job failed, DNS validation timeout, CA outage during renewal window, insufficient permissions to reload web server.
-
Calendar reminder missed: Manual renewal tracking failed, team miscommunication, forgotten about certificate.
-
System clock incorrect: Server time wrong by weeks/months confuses certificate validation.
Diagnosis Commands:
# Check expiration date
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
openssl x509 -noout -dates
# Output:
# notBefore=Oct 15 00:00:00 2024 GMT
# notAfter=Jan 13 23:59:59 2025 GMT ← If this date is past, certificate expired
# Check days until expiration (or days since expiration if negative)
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
openssl x509 -noout -enddate | cut -d= -f2 | \
{ read date; echo $(( ($(date -d "$date" +%s) - $(date +%s)) / 86400 )); }
# Output: -15 ← Negative number means expired 15 days ago
# Verify system time is correct
date
timedatectl # On systemd systems
Step-by-Step Fix:
1. Generate New Certificate (Let’s Encrypt):
# Renew all certificates
sudo certbot renew
# Force renew specific certificate even if not near expiration
sudo certbot renew --force-renewal --cert-name example.com
# Renew and deploy (automatically reloads web server)
sudo certbot renew --deploy-hook "systemctl reload nginx"
2. Generate New Certificate (Manual/Commercial CA):
# Generate CSR (Certificate Signing Request)
openssl req -new -newkey rsa:4096 -nodes \
-keyout example.com.key \
-out example.com.csr \
-subj "/C=US/ST=California/L=San Francisco/O=Example Inc/CN=example.com"
# Submit CSR to CA dashboard, download new certificate bundle
# Usually get: certificate.crt + intermediate.crt + root.crt
3. Install Certificate on Web Server:
Nginx:
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# Update these paths with new certificate
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# ... rest of config
}
Apache:
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
# ... rest of config
</VirtualHost>
4. Test Configuration Syntax:
# Nginx - test before restart to avoid downtime
sudo nginx -t
# Expected: "syntax is okay" and "test is successful"
# Apache
sudo apachectl configtest
# Expected: "Syntax OK"
5. Reload/Restart Web Server:
# Nginx (reload is graceful - no dropped connections)
sudo systemctl reload nginx
# or
sudo nginx -s reload
# Apache
sudo systemctl reload apache2 # Debian/Ubuntu
sudo systemctl reload httpd # RHEL/CentOS
# If reload doesn't work, restart (brief downtime)
sudo systemctl restart nginx
6. Verify Certificate Installation:
# Check certificate dates
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
openssl x509 -noout -dates
# Verify via SSL checker
# Use our tool: https://orbit2x.com/ssl
7. Clear CDN Cache (if applicable):
# Cloudflare - purge entire cache via API
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" \
-H "Authorization: Bearer {api_token}" \
-H "Content-Type: application/json" \
--data '{"purge_everything":true}'
# AWS CloudFront - create invalidation
aws cloudfront create-invalidation \
--distribution-id DISTRIBUTION_ID \
--paths "/*"
8. Test from Multiple Browsers/Devices:
- Chrome (Windows, macOS, Linux)
- Firefox (different from Chrome’s certificate validation)
- Safari (uses macOS keychain)
- Mobile browsers (iOS Safari, Chrome Android)
- Incognito/private mode (ensures fresh certificate check)
Prevention (Critical - Don’t Skip This):
A. Implement Automated Renewal:
# Let's Encrypt automatic renewal (runs twice daily by default)
sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer
# Verify timer is active
sudo systemctl status certbot.timer
# Test renewal process (dry run - doesn't actually renew)
sudo certbot renew --dry-run
# Add post-renewal hook to reload web server
sudo certbot renew --deploy-hook "systemctl reload nginx"
B. Set Up Monitoring Alerts:
# Add to crontab (run daily at 9 AM)
0 9 * * * /opt/scripts/ssl_monitor.sh example.com 30
# Monitor multiple domains
0 9 * * * /opt/scripts/ssl_monitor.sh example.com 30
0 9 * * * /opt/scripts/ssl_monitor.sh www.example.com 30
0 9 * * * /opt/scripts/ssl_monitor.sh api.example.com 30
Use our SSL Certificate Checker with email alerts configured for 30, 14, and 7 days before expiration.
C. Calendar Reminders as Backup:
- Set recurring calendar events 30 days before expiration
- Assign to multiple team members (redundancy)
- Include renewal procedure link in event description
D. Document Renewal Procedures:
Create a runbook in your wiki/documentation:
## SSL Certificate Renewal Procedure
### Automatic Renewal (Let's Encrypt)
- Primary: Certbot timer runs twice daily
- Verify: `sudo systemctl status certbot.timer`
- Test: `sudo certbot renew --dry-run`
- Logs: `/var/log/letsencrypt/letsencrypt.log`
### Manual Renewal (if automatic fails)
1. `sudo certbot renew --force-renewal`
2. `sudo nginx -t`
3. `sudo systemctl reload nginx`
4. Verify: https://orbit2x.com/ssl
### Emergency Contact
- Primary: DevOps Team (devops@example.com)
- Secondary: CTO (cto@example.com)
- CA Support: support@letsencrypt.org
Certificate Name Mismatch (ERR_CERT_COMMON_NAME_INVALID)
Browser Error Messages:
- Chrome:
NET::ERR_CERT_COMMON_NAME_INVALID- “The certificate is valid for X but you’re trying to access Y” - Firefox:
SSL_ERROR_BAD_CERT_DOMAIN- “Certificate is only valid for example.com” - Safari: “This certificate is not valid for this website”
User Experience:
- Security warning page blocks access
- “Your connection is not private” with technical details
- Users can bypass (Advanced → Proceed) but almost nobody does
Root Causes:
-
Accessing domain not in certificate SAN field:
- Certificate for
example.comonly - User accesses
www.example.com(not included) - Mismatch triggers warning
- Certificate for
-
Wrong certificate installed on server:
- Server configured with wrong certificate file
- Copy-paste error in configuration
- Multiple certificates, wrong one activated
-
SNI (Server Name Indication) misconfiguration:
- Multiple virtual hosts on same IP
- SNI not configured correctly
- Server serving default certificate instead of domain-specific one
-
Load balancer serving wrong certificate:
- Backend servers have different certificates
- Load balancer not configured for SNI
- Certificate not uploaded to load balancer
Diagnosis:
# Check what domains are in certificate
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
openssl x509 -noout -text | grep -A1 "Subject Alternative Name"
# Output:
# Subject Alternative Name:
# DNS:example.com ← Only lists example.com, not www.example.com
# Test different subdomains
echo | openssl s_client -connect www.example.com:443 -servername www.example.com 2>/dev/null | \
openssl x509 -noout -subject -ext subjectAltName
# Check certificate Subject (older Common Name field)
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
openssl x509 -noout -subject
Solutions:
Option 1: Reissue Certificate with All Domain Variants
# Let's Encrypt - include all domains in one certificate
sudo certbot certonly --nginx \
-d example.com \
-d www.example.com \
-d mail.example.com \
-d shop.example.com
# Verify SAN field includes all domains
sudo openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -text | \
grep -A5 "Subject Alternative Name"
# Should list: DNS:example.com, DNS:www.example.com, etc.
Option 2: Implement 301 Redirect to Canonical Domain
If you want all traffic on one domain (e.g., www.example.com → example.com):
Nginx:
# Redirect www to non-www
server {
listen 443 ssl http2;
server_name www.example.com;
# Use valid certificate (even if for different domain)
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# 301 permanent redirect
return 301 https://example.com$request_uri;
}
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;
# Main site configuration
root /var/www/html;
# ... rest of config
}
Apache:
<VirtualHost *:443>
ServerName www.example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
Redirect permanent / https://example.com/
</VirtualHost>
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
DocumentRoot /var/www/html
# ... rest of config
</VirtualHost>
Note: This still shows a certificate warning on www.example.com before redirect. Better to include both domains in certificate (Option 1).
Option 3: Use Wildcard Certificate
For unlimited subdomains:
# Let's Encrypt wildcard (requires DNS-01 validation)
sudo certbot certonly --manual --preferred-challenges dns \
-d example.com \
-d *.example.com
# Certbot will display DNS TXT record to add:
# _acme-challenge.example.com. IN TXT "random-string-here"
# Add to DNS, wait for propagation, press Enter
# Verify wildcard coverage
sudo openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -text | \
grep "Subject Alternative Name" -A1
# Output: DNS:example.com, DNS:*.example.com
Wildcard Coverage:
- ✅
www.example.com - ✅
blog.example.com - ✅
shop.example.com - ✅ Any first-level subdomain
- ❌
example.com(root domain must be added separately) - ❌
admin.shop.example.com(multi-level subdomain)
Option 4: Verify DNS Records Match Certificate
Use our DNS Lookup Tool to verify:
- A records point to correct server IP for all domains
- CNAME records properly configured
- CAA records authorize your CA
# Check DNS resolution
dig A example.com
dig A www.example.com
# Verify both resolve to same IP (or CDN CNAME)
Fix Nginx SNI Configuration (Multiple Virtual Hosts):
# Ensure server_name directives are correct
server {
listen 443 ssl http2;
server_name example.com; # ← Exact match required
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# ... config for example.com
}
server {
listen 443 ssl http2;
server_name shop.example.com; # ← Different subdomain
ssl_certificate /etc/letsencrypt/live/shop.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/shop.example.com/privkey.pem;
# ... config for shop.example.com
}
# Test SNI with OpenSSL
openssl s_client -connect example.com:443 -servername example.com | grep "subject="
openssl s_client -connect shop.example.com:443 -servername shop.example.com | grep "subject="
# Each should return correct certificate for that domain
Incomplete Certificate Chain (ERR_CERT_AUTHORITY_INVALID)
Browser Error Messages:
- Chrome:
NET::ERR_CERT_AUTHORITY_INVALID- “This server could not prove that it is example.com” - Firefox:
SEC_ERROR_UNKNOWN_ISSUER- “The certificate is not trusted” - Safari: “This certificate is invalid”
Symptoms:
- Works in Chrome, fails in Firefox/Safari (or vice versa)
- Inconsistent behavior across browsers/devices
- Mobile browsers (iOS Safari, Android Chrome) fail more often
- SSL Labs reports “Chain issues” or “Extra download”
Why This Happens:
SSL/TLS relies on chain of trust from end-entity certificate → intermediate CA(s) → root CA. Browsers and operating systems ship with trusted root CA certificates, but servers must provide intermediate certificates.
Proper Certificate Chain:
1. End-Entity Certificate (your domain: example.com)
↓ signed by
2. Intermediate CA Certificate (e.g., "R3" for Let's Encrypt)
↓ signed by
3. Root CA Certificate (e.g., "ISRG Root X1" - in browser trust store)
What Goes Wrong:
- Server only sends end-entity certificate (missing intermediate)
- Certificates installed in wrong order
- Incomplete bundle downloaded from CA
- Server configuration points to wrong file
Some browsers still work because:
- AIA (Authority Information Access) fetching: Chrome downloads missing intermediates automatically
- Certificate caching: Browser already has intermediate from visiting other sites
- Operating system trust store: Windows/macOS may have intermediates cached
But relies on client behavior—can’t depend on it. Must serve complete chain.
Diagnosis:
# Check certificate chain sent by server
openssl s_client -connect example.com:443 -showcerts
# Expected output shows multiple certificates:
# Certificate chain
# 0 s:CN = example.com ← Your certificate
# i:C = US, O = Let's Encrypt, CN = R3
# -----BEGIN CERTIFICATE-----
# [certificate data]
# -----END CERTIFICATE-----
# 1 s:C = US, O = Let's Encrypt, CN = R3 ← Intermediate CA
# i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
# -----BEGIN CERTIFICATE-----
# [certificate data]
# -----END CERTIFICATE-----
# If you only see one certificate (0), chain is incomplete
# Test chain validation
openssl s_client -connect example.com:443 -CApath /etc/ssl/certs
# Should return: "Verify return code: 0 (ok)"
# If error: "Verify return code: 21 (unable to verify the first certificate)"
# → Chain incomplete
# SSL Labs test
# Visit: https://www.ssllabs.com/ssltest/analyze.html?d=example.com
# Look for: "Chain issues" warning
Fix Procedure:
1. Download Complete Certificate Bundle from CA:
Let’s Encrypt (Certbot automatically provides):
# Certbot creates these files:
ls -l /etc/letsencrypt/live/example.com/
# cert.pem ← End-entity certificate only (DON'T USE THIS ALONE)
# chain.pem ← Intermediate certificate(s) only
# fullchain.pem ← cert.pem + chain.pem (USE THIS!)
# privkey.pem ← Private key
Commercial CA (download from dashboard):
- Usually get:
example_com.crt(your cert) +intermediate.crt+root.crt - Some CAs provide pre-bundled
example_com_bundle.crt
2. Create Proper Certificate Bundle (if needed):
# Concatenate in correct order: end-entity → intermediate → root
cat example_com.crt intermediate.crt root.crt > fullchain.pem
# Verify file contains multiple certificates
grep -c "BEGIN CERTIFICATE" fullchain.pem
# Should return: 2 or 3 (end-entity + intermediates)
# Alternative: Let's Encrypt already provides fullchain.pem
# Just use it directly
3. Configure Web Server with Full Chain:
Nginx (CORRECT):
server {
listen 443 ssl http2;
server_name example.com;
# USE FULLCHAIN (includes intermediates)
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ← FULL CHAIN
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# ... rest of config
}
Nginx (WRONG - Missing Chain):
# DON'T DO THIS - Missing intermediates
ssl_certificate /etc/letsencrypt/live/example.com/cert.pem; ← ONLY END-ENTITY
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
Apache (CORRECT):
<VirtualHost *:443>
ServerName example.com
SSLEngine on
# Method 1: Separate files
SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem ← INTERMEDIATES
# Method 2: Bundled file (Apache 2.4.8+)
# SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
# SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
</VirtualHost>
4. Verify Configuration:
# Test config syntax
sudo nginx -t
sudo apachectl configtest
# Reload web server
sudo systemctl reload nginx
sudo systemctl reload apache2
5. Test Certificate Chain:
# Verify full chain sent
echo | openssl s_client -connect example.com:443 -showcerts 2>/dev/null | \
grep -c "BEGIN CERTIFICATE"
# Should return: 2 or 3 (not just 1)
# Verify chain validation
echo | openssl s_client -connect example.com:443 -CApath /etc/ssl/certs 2>/dev/null | \
grep "Verify return code"
# Expected: "Verify return code: 0 (ok)"
# Test with SSL Labs
# Should show: "Certificate 1: [your domain]"
# "Certificate 2: [intermediate CA]"
# "No chain issues"
6. Test on Multiple Platforms:
- Firefox (strictest chain validation)
- Safari (uses macOS keychain)
- Mobile browsers (iOS Safari, Chrome Android)
- OpenSSL command line
- Our SSL Certificate Checker
Common Pitfall - Order Matters:
# WRONG ORDER (intermediates before end-entity)
cat intermediate.crt example_com.crt > bundle.pem # ❌
# CORRECT ORDER (end-entity first)
cat example_com.crt intermediate.crt > bundle.pem # ✅
The server must send the chain in order: end-entity → intermediate(s) → (optionally) root.
Testing from Multiple Locations:
Some issues only appear from specific networks/regions:
# Test from different networks
# Use VPN, mobile hotspot, different ISP
# Or use online tools testing from multiple locations
# Combine with DNS checks
# Use our DNS Lookup: https://orbit2x.com/lookup
Mixed Content Warnings (HTTP Resources on HTTPS Pages)
Browser Behavior:
- Padlock icon degraded - shows “Not secure” or warning triangle
- Browser console warnings - “Mixed Content” messages
- Active content blocked - JavaScript, iframes, stylesheets from HTTP URLs don’t load
- Passive content warning - Images, video, audio from HTTP show warnings but may load
What Is Mixed Content:
HTTPS page loading resources via insecure HTTP protocol. Browsers block this because:
- Defeats HTTPS purpose - Attackers can modify HTTP resources in transit
- Man-in-the-middle vulnerability - HTTP content isn’t encrypted/authenticated
- User expects full security - Padlock implies everything is secure
Two Types:
Active Mixed Content (BLOCKED by default):
- JavaScript (
<script src="http://example.com/script.js">) - Stylesheets (
<link href="http://example.com/style.css">) - Iframes (
<iframe src="http://example.com/frame.html">) - XMLHttpRequest/Fetch API calls to HTTP URLs
- Web fonts (
@font-facewith HTTP URL)
Passive Mixed Content (WARNED but may load):
- Images (
<img src="http://example.com/image.jpg">) - Video/Audio (
<video src="http://example.com/video.mp4">) - Object embeds (
<object data="http://example.com/file.pdf">)
Modern browsers increasingly block passive mixed content too.
Detection:
Browser Developer Tools:
Chrome DevTools → Console tab → Filter: "Mixed Content"
Firefox Developer Tools → Console → Security warnings
Safari Web Inspector → Console → Filter by "mixed content"
Command Line Scan:
# Download page and search for HTTP resources
curl -s https://example.com | grep -i 'http://'
# More specific - find in src/href attributes
curl -s https://example.com | grep -E 'src=|href=' | grep -i 'http://' | head -20
# Check for HTTP in inline styles
curl -s https://example.com | grep -i 'style=' | grep -i 'http://'
# Check external stylesheets for HTTP URLs
curl -s https://example.com | grep '<link.*stylesheet' | \
xargs -I {} curl -s {} | grep -i 'url(http://'
Automated Scanning:
- Chrome Lighthouse (built into DevTools) - Security audit
- Our SSL Certificate Checker - Checks for common mixed content
- Why No Padlock? - Specialized mixed content detector
Solutions:
1. Update All URLs to HTTPS:
HTML:
<!-- BEFORE (insecure) -->
<script src="http://example.com/script.js"></script>
<img src="http://example.com/image.jpg">
<link href="http://example.com/style.css">
<!-- AFTER (secure) -->
<script src="https://example.com/script.js"></script>
<img src="https://example.com/image.jpg">
<link href="https://example.com/style.css">
CSS:
/* BEFORE */
.background {
background-image: url(http://example.com/bg.jpg);
}
/* AFTER */
.background {
background-image: url(https://example.com/bg.jpg);
}
JavaScript:
// BEFORE
fetch('http://api.example.com/data')
// AFTER
fetch('https://api.example.com/data')
Database Content (WordPress, CMS):
-- Update all HTTP URLs to HTTPS in WordPress
UPDATE wp_posts
SET post_content = REPLACE(post_content, 'http://example.com', 'https://example.com');
UPDATE wp_posts
SET guid = REPLACE(guid, 'http://example.com', 'https://example.com');
UPDATE wp_options
SET option_value = REPLACE(option_value, 'http://example.com', 'https://example.com');
2. Use Protocol-Relative URLs (Legacy Approach):
<!-- Works on both HTTP and HTTPS pages -->
<script src="//cdn.example.com/script.js"></script>
<img src="//cdn.example.com/image.jpg">
<!-- Browser automatically uses current page's protocol -->
<!-- HTTPS page → loads https://cdn.example.com/script.js -->
<!-- HTTP page → loads http://cdn.example.com/script.js -->
Note: Protocol-relative URLs are legacy. Better to use explicit HTTPS now that HTTPS is universal.
3. Implement Content Security Policy (CSP):
Automatic HTTPS Upgrade:
<!-- In HTML <head> -->
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
Or as HTTP header:
# Nginx
add_header Content-Security-Policy "upgrade-insecure-requests" always;
# Apache
Header always set Content-Security-Policy "upgrade-insecure-requests"
What This Does:
- Automatically upgrades all HTTP requests to HTTPS
- No code changes needed in HTML/CSS/JS
- Browser handles rewriting URLs
- Falls back to blocking if HTTPS unavailable
Comprehensive CSP (Blocks Mixed Content):
Content-Security-Policy: default-src https: 'unsafe-inline' 'unsafe-eval'; img-src https: data:; font-src https: data:;
Verify CSP Implementation:
Use our HTTP Headers Analyzer to check CSP header presence and syntax.
4. Fix Third-Party Resources:
CDNs and External Libraries:
<!-- BAD - HTTP CDN -->
<script src="http://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- GOOD - HTTPS CDN -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- BEST - SRI (Subresource Integrity) for security -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
crossorigin="anonymous"></script>
Social Media Embeds:
<!-- Twitter - use HTTPS embed -->
<blockquote class="twitter-tweet">
<a href="https://twitter.com/user/status/123"></a>
</blockquote>
<script async src="https://platform.twitter.com/widgets.js"></script>
<!-- YouTube - HTTPS embed URL -->
<iframe src="https://www.youtube.com/embed/VIDEO_ID"></iframe>
<!-- Google Maps - HTTPS API -->
<iframe src="https://www.google.com/maps/embed?pb=..."></iframe>
Widgets and Advertising:
Contact providers for HTTPS versions. Most modern ad networks support HTTPS.
5. Test Thoroughly:
# Check all pages for mixed content
for page in about contact products; do
echo "Checking /$page"
curl -s https://example.com/$page | grep -i 'http://' | wc -l
done
# Crawl entire site with wget
wget --spider --recursive --no-check-certificate \
-e robots=off -o scan.log https://example.com/
grep -i "http://" scan.log
Browser Testing:
- Open browser DevTools → Console
- Navigate through entire site
- Check for any “Mixed Content” warnings
- Test forms, AJAX requests, media players
Mobile Testing:
- iOS Safari (strict mixed content handling)
- Chrome Android
- Test on cellular networks (different behavior vs WiFi sometimes)
Verification:
- Our SSL Certificate Checker - Validates HTTPS setup
- Our HTTP Headers Analyzer - Checks CSP headers
- SSL Labs - Comprehensive security test
Self-Signed Certificate Errors
Browser Errors:
NET::ERR_CERT_AUTHORITY_INVALIDSEC_ERROR_UNKNOWN_ISSUER- “Certificate is not trusted”
- “Your connection is not private”
What Are Self-Signed Certificates:
Certificates signed by your own private key instead of trusted Certificate Authority. Browser trust stores don’t include your key, so browsers reject as untrusted.
When Self-Signed Is Appropriate:
✅ Acceptable Use Cases:
- Local development environments (
localhost,127.0.0.1,.local,.test) - Internal corporate networks (intranets) with enterprise CA
- Testing and staging environments (not public-facing)
- Educational/learning purposes
- IoT devices on closed networks
❌ NEVER Use Self-Signed For:
- Production public websites
- E-commerce or any real user traffic
- Any site requiring SEO/trust
- Sites subject to compliance (PCI DSS, HIPAA, etc.)
Why Not Production:
- Browser warnings scare away 95%+ of users
- No legal liability/warranty
- Can’t prove certificate authenticity
- Trains users to click through warnings (security risk)
- Google penalizes in search rankings
- No certificate transparency logging
Creating Self-Signed Certificate (Development):
Basic Self-Signed:
# Generate 4096-bit RSA key + self-signed cert valid 365 days
openssl req -x509 -newkey rsa:4096 -sha256 \
-days 365 \
-nodes \
-keyout localhost.key \
-out localhost.crt \
-subj "/C=US/ST=California/L=San Francisco/O=Development/CN=localhost"
# Files created:
# localhost.key - Private key (keep secret!)
# localhost.crt - Self-signed certificate
Self-Signed with Subject Alternative Names (multiple domains):
# Create config file for SANs
cat > localhost.cnf <<EOF
[req]
default_bits = 4096
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = req_ext
[dn]
C = US
ST = California
L = San Francisco
O = Development
CN = localhost
[req_ext]
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
DNS.2 = *.localhost
DNS.3 = 127.0.0.1
IP.1 = 127.0.0.1
IP.2 = ::1
EOF
# Generate certificate with SANs
openssl req -x509 -newkey rsa:4096 -sha256 \
-days 365 \
-nodes \
-keyout localhost.key \
-out localhost.crt \
-config localhost.cnf \
-extensions req_ext
# Verify SANs
openssl x509 -in localhost.crt -noout -text | grep -A5 "Subject Alternative Name"
Install Self-Signed in Development Server:
Nginx:
server {
listen 443 ssl http2;
server_name localhost;
ssl_certificate /path/to/localhost.crt;
ssl_certificate_key /path/to/localhost.key;
# Disable OCSP/stapling for self-signed
ssl_stapling off;
root /var/www/html;
index index.html;
}
Python Development Server:
# Flask example
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "Hello HTTPS World!"
if __name__ == '__main__':
app.run(
ssl_context=('localhost.crt', 'localhost.key'),
host='0.0.0.0',
port=5000
)
Node.js Development Server:
const https = require('https');
const fs = require('fs');
const express = require('express');
const app = express();
const options = {
key: fs.readFileSync('localhost.key'),
cert: fs.readFileSync('localhost.crt')
};
app.get('/', (req, res) => {
res.send('Hello HTTPS World!');
});
https.createServer(options, app).listen(5000, () => {
console.log('HTTPS server running on https://localhost:5000');
});
Trusting Self-Signed Certificate (Development Only):
macOS:
# Add to system keychain
sudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain localhost.crt
# Or double-click localhost.crt → Keychain Access → Always Trust
Windows:
# Import to Trusted Root Certification Authorities
certutil -addstore -f "ROOT" localhost.crt
# Or: Double-click .crt → Install Certificate → Local Machine →
# Place in "Trusted Root Certification Authorities"
Linux (Debian/Ubuntu):
# Copy to ca-certificates directory
sudo cp localhost.crt /usr/local/share/ca-certificates/localhost.crt
# Update CA certificates
sudo update-ca-certificates
# Verify
openssl s_client -connect localhost:443 -CApath /etc/ssl/certs
Firefox (Separate Trust Store):
Settings → Privacy & Security → Certificates → View Certificates
→ Authorities tab → Import → Select localhost.crt
→ Check "Trust this CA to identify websites"
Production Solution: Replace with Let’s Encrypt
# Install Certbot
sudo apt-get update
sudo apt-get install certbot python3-certbot-nginx
# Get trusted certificate (automatic)
sudo certbot --nginx -d example.com -d www.example.com
# Certificate issued in 2-5 minutes
# Fully trusted by all browsers
# Free forever
# Auto-renewal configured
# Verify installation
sudo certbot certificates
# Test renewal
sudo certbot renew --dry-run
Verification:
- Browser shows padlock without warnings
- Our SSL Certificate Checker shows no errors
- SSL Labs gives A or A+ rating
Summary:
- ✅ Self-signed for development/internal use only
- ❌ Never self-signed for production
- ✅ Let’s Encrypt for production (free, trusted, automated)
- ✅ Test with our SSL Certificate Checker
Continue to Part 2 of this guide for: SSL/TLS Best Practices, Certificate Monitoring, Advanced Topics (OCSP, mTLS, Post-Quantum), Compliance Requirements, Troubleshooting Workflows, Future of SSL/TLS, and Comprehensive FAQ…
Related Tools:
- SSL Certificate Checker - Verify certificate validity and expiration
- DNS Lookup Tool - Check CAA records and DNS configuration
- HTTP Headers Analyzer - Verify HSTS, CSP, and security headers
- HTTP Status Checker - Test redirect chains
- IP Address Checker - Verify server geolocation
External Resources:
- Let’s Encrypt Documentation
- Mozilla SSL Configuration Generator
- SSL Labs Server Test
- Certificate Transparency Logs
- RFC 8446: TLS 1.3
- RFC 5280: X.509 Certificates
- CA/Browser Forum Requirements
Your website’s security begins with a valid SSL certificate. Check yours now: SSL Certificate Checker