Files
mcpedia/content/writeups/infra/cloudflare-525.md
T
asepharyana 53d636af0e
CI / typecheck + build (turbo) (push) Canceled after 0s
feat(phase7): grow corpus, MCP write-tools+auth, /metrics observability
- content/: +5 real docs (caddy, bullmq, mcp-streamable-http, postgres-fts,
  cloudflare-525 writeup) across docs/writeups/notes. Reindexed: 9 docs, 17
  chunks, 5 revisions (was 4 docs).
- apps/mcp: add write-tools index_document/reindex_all/restore_revision (require
  x-webhook-secret) + queue_status (public). createMcpServer(authSecret?) threads
  the HTTP header; stdio keeps writes open (trusted local).
- apps/api: GET /metrics (Prometheus text: uptime + queue job gauges).
- Caddy: expose /metrics on wiki. domain -> :4020.
Verified live: /metrics 200; MCP tools/list -> 10; index_document unauth -> error,
auth -> enqueues + worker drains; typecheck green.
2026-08-20 10:04:16 +07:00

2.0 KiB

id, title, type, tags, status, author, created_at, updated_at
id title type tags status author created_at updated_at
cloudflare-525-writeup Diagnosing Cloudflare 525 (Origin TLS Handshake Failed) writeup
cloudflare
tls
525
caddy
debugging
published asep 2026-08-20 2026-08-20

Diagnosing Cloudflare 525 (Origin TLS Handshake Failed)

A 525 appears between the user and the origin when Cloudflare (Strict TLS mode) cannot complete the TLS handshake to the origin server. This writeup captures the debugging loop that recurred while wiring new subdomains.

Symptom

curl https://<sub>.asepharyana.my.id → HTTP/2 525. Browser shows Cloudflare's "SSL handshake failed" page.

Root causes (in order of likelihood)

  1. No Caddy site block for the SNI. Cloudflare proxies every *.asepharyana.my.id record. A host without a matching Caddy site block has no certificate, so the handshake dies. This is the #1 cause and the one that bit wiki and mcp.
  2. Certificate still provisioning. The first request after adding a block triggers ACME http-01 issuance. Until the cert lands (~10s), the origin 525s. Self-heals.
  3. Wrong cert presented. Rare here — Caddy serves the SNI-matched cert; a mismatch means the block points at the wrong backend or the cert store is stale.

The debugging loop

curl -sI https://<sub>/            # 525?
grep -n "<sub>" /etc/caddy/Caddyfile   # block present?
sudo journalctl -u caddy | grep -i "tls\|acme\|<sub>"   # cert issued?
openssl s_client -connect 127.0.0.1:443 -servername <sub>   # origin cert valid?

If the block is missing: add import proxy <port>, caddy validate, systemctl reload caddy. If the cert is mid-issuance: wait and re-test. Do not point Cloudflare at a non-existent origin or set the SSL mode to Flexible — Flexible mode breaks already- working Strict setups.

Lesson

Every new subdomain needs (a) a Caddy site block and (b) a Cloudflare DNS record that proxies to the origin. Omit either and you get a 525. The wildcard DNS means you only add the Caddy side.