Resolving Cloudflare Error 525 (SSL Handshake Failed) on Origin CA Setup

Root Cause Diagnosis

Error 525 means Cloudflare’s edge connected to the origin on TCP 443 but the TLS handshake failed before any HTTP exchange. With an Origin CA certificate, this almost always means the origin is not presenting a certificate for that connection: no SSL vhost on 443, a certificate and key that do not match, no SNI match (or a default server that rejects the handshake), or a protocol/cipher policy Cloudflare cannot negotiate. The Origin CA certificate itself is not the cause. Cloudflare trusts it by design, so certificate validity problems surface as 526, not 525.

Quick Fix

Test the handshake directly against the origin IP, bypassing Cloudflare:

ss -tlnp | grep ':443'
openssl s_client -connect ORIGIN_IP:443 -servername example.com </dev/null 2>&1 | grep -E 'subject=|Protocol|Cipher|alert|errno|wrong version'

If nothing listens on 443, or the output shows alert handshake failure or no peer certificate available, install the Origin CA certificate and key in the origin’s 443 vhost (Step 3 or 4) and reload the web server.

As a temporary diagnostic only, set SSL/TLS > Overview to Flexible. If the site loads, the origin’s HTTPS leg is the problem. Flexible sends plain HTTP to the origin, so revert to Full (strict) once the origin is fixed. Flexible can also cause redirect loops if the origin forces HTTPS.

Step-by-Step Resolution

1. Confirm the error class

CodeMeaning
525TLS handshake with origin failed
526Handshake succeeded, but the certificate is invalid for Full (strict) (expired, wrong hostname, untrusted CA)
521Origin refused the connection or is down
524Origin accepted the connection but timed out

2. Interpret the direct openssl s_client result

OutputCause
Connection refused / timeoutNothing on 443, or firewall (Step 6)
wrong version numberPlain HTTP is served on 443, with no ssl on the listener
no peer certificate available / alert handshake failureNo matching cert for the SNI, or protocol/cipher mismatch
alert internal error (alert 80)SNI rejected by the server (Step 5)
Certificate shown, Verify return code: 20 or 21Expected. Origin CA is not in the system trust store, so this is not an error for Cloudflare

3. Install the Origin CA certificate (Nginx)

See also  cPanel to CyberPanel Manual User Backup Restore Without Corrupted Tarball Issues

Create the certificate at SSL/TLS > Origin Server > Create Certificate. Save the certificate as PEM and the private key separately. The private key is shown only once.

mkdir -p /etc/ssl/cloudflare
# paste contents into these files
nano /etc/ssl/cloudflare/example.com.pem
nano /etc/ssl/cloudflare/example.com.key
chmod 644 /etc/ssl/cloudflare/example.com.pem
chmod 600 /etc/ssl/cloudflare/example.com.key
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;   # nginx >= 1.25.1; on older versions use: listen 443 ssl http2;
    server_name example.com www.example.com;

    ssl_certificate     /etc/ssl/cloudflare/example.com.pem;
    ssl_certificate_key /etc/ssl/cloudflare/example.com.key;
    ssl_protocols       TLSv1.2 TLSv1.3;
}

4. Verify the certificate and key match

# RSA or ECDSA, method-independent
openssl x509 -in /etc/ssl/cloudflare/example.com.pem -noout -pubkey | openssl md5
openssl pkey -in /etc/ssl/cloudflare/example.com.key -pubout | openssl md5

The two hashes must be identical. If they differ, the key was pasted from a different request. Generate a new Origin CA certificate.

Apache equivalent:

SSLEngine on
SSLCertificateFile    /etc/ssl/cloudflare/example.com.pem
SSLCertificateKeyFile /etc/ssl/cloudflare/example.com.key

Panel paths:

  • aaPanel: Website > [site] > SSL > Other certificate. Paste both values. Files land in /www/server/panel/vhost/cert/example.com/.
  • CyberPanel (OpenLiteSpeed): edit the vhssl block in /usr/local/lsws/conf/vhosts/example.com/vhost.conf (keyFile, certFile), then restart with systemctl restart lsws.

5. Fix SNI and default-server handling

Cloudflare sends the requested hostname as SNI. If the matching server_name has no ssl listener, or the default server rejects unknown names, the handshake fails.

nginx -T 2>/dev/null | grep -nE 'listen .*443|server_name|ssl_reject_handshake|default_server'

Remove ssl_reject_handshake on; from any server that may receive Cloudflare traffic, or make sure the correct server_name exists in a 443 server block. Every 443 server block needs its own ssl_certificate and ssl_certificate_key unless inherited from the http level.

If the certificate does not cover the hostname (for example, it lists only example.com and the request is for www.example.com), regenerate it with both names. A wildcard *.example.com covers one label level only and does not cover the apex.

See also  Cloudflare DNS Propagation Delay on Gray-Clouded Subdomains: TTL Flush Fix

6. Allow Cloudflare IP ranges on 443

curl -s https://www.cloudflare.com/ips-v4 -o /tmp/cf-v4.txt
curl -s https://www.cloudflare.com/ips-v6 -o /tmp/cf-v6.txt

Firewalld:

for ip in $(cat /tmp/cf-v4.txt /tmp/cf-v6.txt); do
  firewall-cmd --permanent --add-rich-rule="rule family=$( [[ $ip == *:* ]] && echo ipv6 || echo ipv4 ) source address=$ip port port=443 protocol=tcp accept"
done
firewall-cmd --reload

UFW:

for ip in $(cat /tmp/cf-v4.txt /tmp/cf-v6.txt); do ufw allow proto tcp from $ip to any port 443; done

Also check provider-level firewalls (security groups, Hetzner/OVH/AWS panels), fail2ban bans, and CSF. These commonly block edge IPs after rate limiting.

7. Confirm protocol and cipher policy

Test each version explicitly:

openssl s_client -connect ORIGIN_IP:443 -servername example.com -tls1_2 </dev/null 2>&1 | grep -E 'Protocol|Cipher'
openssl s_client -connect ORIGIN_IP:443 -servername example.com -tls1_3 </dev/null 2>&1 | grep -E 'Protocol|Cipher'

At least one must succeed with an ECDHE cipher. Do not restrict ssl_ciphers to a list that excludes ECDHE with AES-GCM or ChaCha20.

8. Check Authenticated Origin Pulls

If SSL/TLS > Origin Server > Authenticated Origin Pulls is on, the origin must trust Cloudflare’s client certificate CA:

ssl_client_certificate /etc/ssl/cloudflare/origin-pull-ca.pem;
ssl_verify_client on;

Download origin-pull-ca.pem from Cloudflare’s documentation. If the origin requires a client certificate but this is not configured correctly, the connection fails. Disable the feature temporarily to isolate it.

9. Validate, reload, and set the SSL mode

nginx -t && systemctl reload nginx

Set SSL/TLS > Overview to Full (strict). Then test through Cloudflare:

curl -sI https://example.com | head -n 5

Why This Fails for Some Users

  • Nginx reload failed silently. A running process with the old config keeps serving the old state. Always run nginx -t and check systemctl status nginx after editing.
  • Origin cert replaced by a panel job. aaPanel and CyberPanel rewrite vhost certificate paths when Let’s Encrypt renews or when SSL is toggled in the UI, which can swap your Origin CA certificate or remove the ssl listener. Re-apply after panel changes.
  • Non-standard origin port. Cloudflare connects to the origin on the same port as the visitor’s request unless overridden. If HTTPS runs on another port, set a destination port override in Rules > Origin Rules. Cloudflare proxies only these HTTPS ports: 443, 2053, 2083, 2087, 2096, 8443.
  • Upstream load balancer or second proxy. If another TLS-terminating proxy (HAProxy, another Nginx, a hosting provider’s edge) sits between Cloudflare and your server, the cert must be installed on the component that Cloudflare actually reaches.
  • AAAA record points to an IPv6 address that is not serving TLS. Cloudflare may use it. Test with openssl s_client -connect [IPV6]:443, or add listen [::]:443 ssl;.
  • Legacy OpenSSL or ECDSA support. Very old stacks (CentOS 6, Ubuntu 14.04, OpenSSL 1.0.1) may fail TLS 1.2 or ECDSA. Generate an RSA (2048) Origin CA certificate instead of ECDSA and upgrade OpenSSL where possible.
  • Passphrase-protected key. A key that needs a passphrase prevents the service from loading the cert. Nginx fails to start, and other servers may start without SSL on that vhost.
  • Malformed PEM. Windows line endings, missing -----BEGIN CERTIFICATE----- lines, or stray spaces from copy-paste break parsing. Check with openssl x509 -in file.pem -noout -text.
  • Hostname certificate mismatch appears as 526, not 525. If you see 526 after fixing the handshake, regenerate the certificate to include all proxied hostnames.
  • Grey-clouded (DNS-only) records. Browsers do not trust Origin CA certificates. Visitors get NET::ERR_CERT_AUTHORITY_INVALID, not 525. Origin CA is valid only for proxied traffic. For DNS-only records, use a publicly trusted certificate.
  • Enterprise SNI override. If an Origin SNI override is configured under SSL/TLS > Custom Hostnames or via an Origin Rule, Cloudflare sends that value instead of the visitor hostname. The origin must have a matching vhost.
See also  aaPanel Nginx Reverse Proxy 502 Bad Gateway with SSL WebSocket Passthrough

Leave a Comment