When a website configured behind an edge proxy or content delivery network (such as Cloudflare) displays “Error 525: SSL handshake failed”, it indicates that the proxy attempted to establish a secure, encrypted TLS connection with your origin server (Nginx, Apache, or LiteSpeed), but the cryptographic handshake failed.
A TLS handshake involves multiple steps: certificate verification, cipher suite negotiation, protocol agreement (TLS 1.2 / 1.3), and Server Name Indication (SNI) checks. If any step fails, the connection is instantly aborted.
Quick Answer
- Test the TLS handshake directly against your origin server IP using
openssl s_client:openssl s_client -connect ORIGIN_IP:443 -servername yourdomain.com - Check if your origin certificate has expired:
echo | openssl s_client -connect ORIGIN_IP:443 -servername yourdomain.com 2>/dev/null | openssl x509 -noout -dates - If using Cloudflare Full (Strict) mode, your origin server must have an active, trusted SSL certificate. If the origin certificate is expired, renew it with Certbot (
certbot renew) or deploy a free 15-year Cloudflare Origin CA certificate. - Ensure Nginx or Apache explicitly supports TLS 1.2 and TLS 1.3:
ssl_protocols TLSv1.2 TLSv1.3;
Symptoms
- Cloudflare displays a branded landing page: “Error 525: SSL handshake failed”, indicating the failure is between Cloudflare and the origin web server.
- Running
curl -Iv https://yourdomain.comoutputs:OpenSSL SSL_connect: SSL_ERROR_SYSCALLorSSL alert number 40 / handshake_failure. - Browser displays
NET::ERR_SSL_VERSION_OR_CIPHER_MISMATCHwhen connecting directly to the server. - Web server error logs show:
SSL_do_handshake() failed (SSL: error:1408F10B:SSL routines:ssl3_get_record:wrong version number).
Common Causes
- Expired Origin SSL Certificate: The Let’s Encrypt or custom SSL certificate installed on the origin Nginx/Apache host has passed its expiration date.
- Cloudflare SSL Mode Mismatch: Cloudflare encryption is set to Full (Strict), but the origin server has no SSL certificate installed on port 443, or uses an untrusted self-signed certificate.
- Port 443 Blocked by Host Firewall: The origin server is listening on port 80, but port 443 is blocked by a host firewall (UFW, firewalld, or AWS Security Group).
- Unsupported TLS Protocols or Ciphers: The origin web server is configured with legacy, deprecated cipher suites that modern proxies reject, or disabled TLS 1.2/1.3.
- Missing SNI (Server Name Indication) Configuration: Multiple domains share one IP address, and Nginx/Apache is not configured with a default SSL virtual host for the requested server name.
Before You Start
- Obtain your origin server’s actual public IP address (bypassing any CDN). You cannot debug origin SSL by sending queries to Cloudflare’s proxy IP.
- For automated zero-downtime certificate renewals, explore our server security services.
Step 1 — Test Origin SSL Handshake Directly Using OpenSSL
Run this diagnostic command from your local computer or another server to query the origin IP directly:
openssl s_client -connect 203.0.113.10:443 -servername yourdomain.com
- Replace
203.0.113.10with your origin server’s public IP address. - The
-servername yourdomain.comflag tests SNI support.
Evaluating the Output
- If it connects and outputs certificates: Look at
Verify return code: 0 (ok). The origin SSL is valid. - If it returns
handshake failure: The web server does not support the client’s cipher suites or TLS version. Proceed to Step 4. - If it returns
Connection refusedor hangs: Port 443 is closed or blocked. Proceed to Step 3. - If it returns
certificate has expired: Proceed to Step 2.
Step 2 — Check and Renew Expired Certificates
Let’s Encrypt certificates expire every 90 days. If an automated cron renewal failed, your site will trigger Error 525.
Log into your origin server and check certificate status:
sudo certbot certificates
Expected Output
Found the following certs:
Certificate Name: yourdomain.com
Expiry Date: 2026-09-10 12:00:00+00:00 (INVALID: EXPIRED)
Force Certificate Renewal
Renew the certificates immediately:
sudo certbot renew --force-renewal
Reload your web server to load the new certificate files into memory:
sudo systemctl reload nginx || sudo systemctl reload apache2
Step 3 — Align Cloudflare SSL Encryption Modes
In your Cloudflare dashboard, navigate to SSL/TLS -> Overview.
Cloudflare provides four encryption modes:
+─────────────────────────────────────────────────────────────────────────+
| Cloudflare SSL/TLS Encryption Modes |
+─────────────────────────────────────────────────────────────────────────+
Off ──► No encryption at all (HTTP only)
Flexible ──► Encrypts browser to Cloudflare; plaintext to origin
Full ──► Encrypted, but accepts self-signed certs on origin
Full (Strict) ──► Requires trusted, non-expired SSL cert on origin
- If your origin has an active, valid Let’s Encrypt or CA certificate: Use Full (Strict).
- If your origin certificate expired and you need an immediate fix: Temporarily switch Cloudflare to Full while you repair the origin certificate.
- Best Long-Term Practice: Install a free Cloudflare Origin CA Certificate (valid for 15 years) directly on your origin server. It never expires unexpectedly and works seamlessly with Full (Strict) mode.
Step 4 — Configure Modern TLS Protocols and Ciphers in Nginx
If OpenSSL reported a cipher or protocol mismatch, ensure Nginx supports modern cryptographic standards.
Open your Nginx configuration:
sudo nano /etc/nginx/sites-available/yourdomain.com.conf
Verify your SSL directives inside the server { ... } block:
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# Enforce modern TLS protocols
ssl_protocols TLSv1.2 TLSv1.3;
# Secure cipher suites
ssl_prefer_server_ciphers off;
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;
# Enable SSL session resumption
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
}
Test syntax and reload:
sudo nginx -t && sudo systemctl reload nginx
Step 5 — Verify Port 443 Listening and Firewall Rules
Verify that your web server is actively listening on TCP port 443 across all network interfaces:
sudo ss -tulpn | grep 443
Expected Output
tcp LISTEN 0 511 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=14201,fd=8))
If nothing is returned, Nginx is not configured to listen on port 443 for SSL.
Check Host Firewall Status
Ensure port 443 is open to the public internet:
# On Ubuntu/Debian UFW:
sudo ufw status | grep 443
sudo ufw allow 443/tcp
# On AlmaLinux / RHEL firewalld:
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
Step 6 — Verify Resolution
Test the live website through cURL, instructing it to display SSL handshake details:
curl -Iv https://yourdomain.com
Look for Successful Handshake Confirmation:
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=yourdomain.com
* start date: Sep 18 12:00:00 2026 GMT
* expire date: Dec 17 12:00:00 2026 GMT
* issuer: C=US, O=Let's Encrypt, CN=R3
* SSL certificate verify ok.
The handshake completes cleanly and the Error 525 screen is resolved.
Common Mistakes
- Using “Flexible” SSL on an origin that forces HTTPS redirects: If Cloudflare connects to your server on HTTP (port 80), and your origin Nginx config forces a 301 redirect to HTTPS, you will create an infinite redirect loop (
ERR_TOO_MANY_REDIRECTS). - Missing Intermediate Certificates in
fullchain.pem: In Nginx, usingcert.peminstead offullchain.peminssl_certificatefails the certificate trust chain verification on mobile browsers and edge proxies. - Leaving TLS 1.0 or 1.1 enabled: Modern browsers and cloud proxies reject insecure legacy TLS versions, causing handshake aborts.
Prevention Checklist
- Set up automated Certbot renewal timers:
systemctl status certbot.timer. - Use Cloudflare 15-year Origin CA certificates for origin-to-edge encryption.
- Ensure UFW and cloud security groups keep port 443 open.
- Schedule automated certificate expiration monitoring in Grafana or Zabbix.
Quick Reference Commands
| Operation | Command |
|---|---|
| Test origin SSL handshake | openssl s_client -connect IP:443 -servername domain |
| View certificate expiration | certbot certificates |
| Force renew Certbot certs | sudo certbot renew --force-renewal |
| Check port 443 listener | ss -tulpn | grep 443 |
| Allow HTTPS in UFW | sudo ufw allow 443/tcp |
Frequently Asked Questions
Why does Error 525 happen only on mobile devices or certain networks?
Mobile networks and newer operating systems strictly enforce modern elliptic curve ciphers and require complete intermediate certificate chains. If your server is missing the intermediate CA cert (fullchain.pem), desktop browsers may work from cached root stores while mobile devices fail with Error 525.
What is the Cloudflare Origin CA certificate?
The Cloudflare Origin CA is a free SSL certificate generated inside the Cloudflare dashboard specifically to secure the connection between Cloudflare and your origin server. It can be issued for up to 15 years, eliminating the risk of 90-day renewal lapses.
Can a wrong server time cause SSL handshake failure?
Yes. If your server’s hardware clock or system time drifts significantly into the past or future (due to a disabled NTP daemon), SSL certificates will be evaluated as not yet valid or already expired. Ensure systemd-timesyncd or chrony is running.
How does ServerCare360 assist with SSL and web security?
Our server security and Linux server support specialists deploy automated Let’s Encrypt renewal pipelines, configure hardened TLS 1.3 ciphers, manage Cloudflare edge routing, and provide 24/7 incident response for SSL outages.