Question
How to fix Cloudflare 525 with Caddy
If Cloudflare shows Error 525, it means the SSL handshake to your origin failed. In practice, this is usually a certificate, port, or SNI mismatch.
Fast recovery checklist
- Cloudflare SSL mode: keep
Full (strict)only when origin cert is valid for your hostname. - Verify origin HTTPS on port 443 is open in firewall and listening on server.
- Confirm Caddy site block includes the exact domain name and TLS configuration.
- Run one SNI test and one curl test from the server before changing more settings.
Commands that usually surface the root cause
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl status caddy --no-pager -n 20
sudo journalctl -u caddy --since '30 minutes ago' --no-pager | tail -n 80
curl -Iv --resolve yourdomain.com:443:ORIGIN_IP https://yourdomain.com/
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com -showcerts </dev/null | head -n 60
sudo ss -lntp | grep :443
Error signal to Caddy fix
| Signal | Likely Caddy issue | First fix |
|---|---|---|
curl --resolve returns a certificate for the wrong hostname | The Caddy site label does not include the hostname Cloudflare sends with SNI. | Use explicit labels such as example.com, www.example.com instead of only :443 or only the apex. |
openssl shows no peer certificate or handshake failure | Caddy is not completing TLS, or another service/firewall is interrupting before Caddy answers. | Check sudo ss -lntp | grep :443, Caddy logs, UFW, cloud firewall, and any load balancer in front of Caddy. |
Apex works, www fails | The certificate or site label covers only one hostname. | Add both hostnames to the Caddy site block and issue a cert that covers both names. |
| IPv4 works, IPv6 fails | The AAAA origin points to a host without the same Caddy/TLS config. | Mirror the Caddy config on IPv6 or remove the proxied AAAA record until it is ready. |
| Origin test works, Cloudflare still shows 525 | Cloudflare is reaching a different origin IP or edge-to-origin traffic is blocked. | Compare proxied DNS records, Cloudflare origin rules, security groups, and the exact origin IP used in the forced test. |
Example: Cloudflare 525 after switching to Full (strict)
This usually means Cloudflare can reach port 443, but Caddy does not present a certificate Cloudflare accepts for the requested hostname.
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName
# Check for three things:
# 1. The certificate has example.com or *.example.com in Subject Alternative Name.
# 2. The certificate is not expired.
# 3. Caddy is serving this certificate on the same hostname Cloudflare requests.
If the certificate is for a different host, fix the Caddy site label first. If the certificate is expired, renew or replace it before changing Cloudflare mode.
Example: origin IP test works, but hostname test fails
Testing https://ORIGIN_IP is not enough for Caddy because Caddy uses SNI to choose the site block. Test the hostname while forcing it to the origin IP.
curl -Iv --resolve example.com:443:203.0.113.10 https://example.com/
# Good result:
# SSL connection using TLSv1.3
# server certificate verification OK
# HTTP/2 200 or HTTP/1.1 200
# Bad result:
# SSL certificate problem, handshake failure, or default Caddy certificate.
This isolates the origin from Cloudflare. If this forced-origin request fails, the problem is on Caddy or the origin firewall. If it succeeds, check Cloudflare SSL mode, DNS target, and any origin rules.
Caddyfile patterns that cause 525
The most common Caddy-specific failure is a site label that does not match the hostname Cloudflare sends with SNI. A direct IP test can look fine while the real hostname still fails.
# Risky: catches requests but may not serve the cert Cloudflare expects
:443 {
reverse_proxy 127.0.0.1:3000
}
# Better: match the exact hostname Cloudflare proxies
example.com, www.example.com {
reverse_proxy 127.0.0.1:3000
}
If you use a Cloudflare Origin Certificate, make sure the certificate covers both the apex and www hostname when both DNS records are proxied. A certificate for example.com alone can still fail for www.example.com under Full (strict).
Caddyfile examples for common deployments
For a normal public site where Caddy obtains a public certificate, keep the site label explicit and let Caddy manage TLS.
example.com, www.example.com {
encode zstd gzip
reverse_proxy 127.0.0.1:3000
}
For an origin that should only be validated by Cloudflare, a Cloudflare Origin Certificate can be used, but the certificate must include every proxied hostname.
example.com, www.example.com {
tls /etc/ssl/cloudflare/example-origin.pem /etc/ssl/cloudflare/example-origin.key
reverse_proxy 127.0.0.1:3000
}
Do not combine a catch-all :443 site with hostname-specific sites unless you have tested which block answers each SNI name. The simplest recovery path is usually to remove the catch-all, make hostnames explicit, validate, and reload.
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
curl -Iv --resolve example.com:443:203.0.113.10 https://example.com/
curl -Iv --resolve www.example.com:443:203.0.113.10 https://www.example.com/
Example: apex works but www returns 525
When example.com works but www.example.com fails, the origin often has a certificate or Caddy site block for only one hostname. Test both names with the same origin IP before changing Cloudflare SSL mode.
curl -Iv --resolve example.com:443:203.0.113.10 https://example.com/
curl -Iv --resolve www.example.com:443:203.0.113.10 https://www.example.com/
openssl s_client -connect 203.0.113.10:443 -servername www.example.com </dev/null \
| openssl x509 -noout -subject -issuer -ext subjectAltName
If the apex succeeds and www fails, add both hostnames to the Caddy site label and issue a certificate that covers both. Then retest the two forced-origin requests and only after that retest through Cloudflare.
Common operator mistake
People often switch many settings at once. Fix one failed check first, then retest through Cloudflare. This avoids long trial-and-error loops.
Post-fix checks for AI crawler pages
When 525 affects a site that depends on search and AI crawler access, verify more than the homepage. Test a crawl path and a representative content page through Cloudflare after the certificate fix.
curl -I https://example.com/robots.txt
curl -I https://example.com/sitemap.xml
curl -I https://example.com/questions/important-page/
# Expected: 200, 301, or 304.
# Not fixed: 525, 526, handshake failure, or intermittent timeouts.
If only one hostname fails, compare the apex and www Caddy site blocks and certificate names. Cloudflare can request either hostname depending on DNS and redirect rules.
For multi-site Caddy servers, also confirm no default catch-all site is answering before the intended hostname block. A catch-all can make direct IP tests look healthy while SNI-specific requests still fail.
When to use a Cloudflare Origin Certificate
A Cloudflare Origin Certificate is a reasonable fix when Cloudflare is the only client that must validate origin TLS. Do not use it for direct browser access to the origin hostname, because public browsers will not trust that certificate chain.
When not to edit Cloudflare SSL mode
Changing from Full (strict) to Flexible can make the error page disappear while leaving the origin misconfigured. Treat it as a temporary diagnostic only if you have no other way to restore service. The durable fix is to make the forced-origin hostname test succeed with the same hostname, IP, and TLS certificate Cloudflare will use.
If this page is part of a search or AI visibility workflow, retest /robots.txt, /sitemap.xml, and one deep article URL after the TLS fix. A homepage-only test can miss crawler-impacting failures.
Running Nginx instead? Follow the Nginx-specific workflow: How to fix Cloudflare 525 with Nginx.
If Cloudflare shows 526 instead of 525, use this checklist: How to fix Cloudflare 526 invalid certificate.