Cloudflare in front of your origin
Article.
Verified 2026-10Verified 2026-10-15 against Cloudflare’s developer docs; the header and address runs are against this site, which is served by Cloudflare Pages.
Cloudflare sits between users and your servers as a reverse proxy: DNS, caching, TLS, a web application firewall and DDoS absorption, from one anycast network.
Turning it on takes a click; the interview question is what changes for the origin once traffic arrives through someone else’s proxy, because most Cloudflare incidents are the origin misunderstanding that: redirect loops, lost client IPs, an origin still reachable directly, and ports that are silently not proxied.
The mechanism: an anycast reverse proxy chosen in DNS
Each DNS record is either proxied (the “orange cloud”) or DNS-only (grey). A proxied name resolves to Cloudflare’s addresses, not yours; the nearest Cloudflare location terminates the connection and opens its own to your origin.
user ── TLS ──► Cloudflare edge (anycast, nearest city)
│ cache · WAF · rate limits · DDoS
└── TLS (mode-dependent) ──► your originSeeing it from outside
Cloudflare publishes the ranges it serves from, and a proxied name resolves inside them:
v4 = curl("https://www.cloudflare.com/ips-v4").split()
v6 = curl("https://www.cloudflare.com/ips-v6").split()
nets = [ipaddress.ip_network(n) for n in v4 + v6]
addrs = {ai[4][0] for ai in socket.getaddrinfo(host, 443)}
inside = sum(any(ipaddress.ip_address(a) in n for n in nets) for a in addrs)Cloudflare publishes 15 IPv4 and 7 IPv6 ranges, e.g. ['173.245.48.0/20', ...]
stackbook.pages.dev: 2 addresses, 2 inside Cloudflare's ranges
www.cloudflare.com: 2 addresses, 2 inside Cloudflare's ranges
pypi.org: 4 addresses, 0 inside Cloudflare's rangesResponses carry the proxy’s fingerprints:
Server: cloudflare
CF-Ray: a4aff5965ff3babc-VIE # request ID plus the edge location (Vienna)
CF-Cache-Status: HIT # served from the edge cache
alt-svc: h3=":443"; ma=86400 # HTTP/3 offered by the edgeCF-Ray is the first thing to ask for in a support case or to log at the
origin: it ties a user’s error page to one request at one edge.
TLS: the mode is a choice about the second hop
| Mode | Edge to origin | Verdict |
|---|---|---|
| Flexible | plain HTTP | a trap: looks secure to users, is not |
| Full | HTTPS, certificate not checked | encrypted, not authenticated |
| Full (strict) | HTTPS, certificate validated | the one to use |
Flexible causes the classic redirect loop: the origin redirects HTTP to HTTPS, Cloudflare fetches it over HTTP again, forever. Full (strict) with a real certificate, or a free Origin CA certificate that only Cloudflare trusts, encrypts and authenticates both hops.
Caching: what the edge keeps
By default Cloudflare caches by file extension (images, CSS, JavaScript,
fonts) and does not cache HTML or JSON. It also skips anything sent with
Cache-Control: private, no-store, no-cache or max-age=0, anything with
a Set-Cookie header, and every non-GET request.
Caching dynamic pages needs
a cache rule plus correct Cache-Control from the origin, and the origin’s
headers still decide how long
(HTTP semantics and caching).
This site shows a trade worth knowing. Even its content-hashed stylesheet
(Base.a-o2CiLe.css) is served with Cache-Control: public, max-age=0, must-revalidate, on purpose. Cloudflare Pages appends every matching
_headers rule instead of letting the most specific win, so a /* policy
plus a /_astro/* override produced one malformed header:
Cache-Control: public, max-age=0, must-revalidate, public, max-age=31536000, immutableBrowsers honour the first max-age, so the override bought nothing. The
site keeps one rule: nine small hashed assets revalidate with cheap 304s, and
in exchange a deploy is visible at once and a deleted page stops answering
instead of being served from the edge for an hour.
Getting the real client IP at the origin
Behind the proxy, every request comes from a Cloudflare address. The client’s
address is in CF-Connecting-IP (and appended to X-Forwarded-For). Trust
it only from Cloudflare’s ranges, or anyone who reaches the origin directly
can claim any IP:
# /etc/nginx/conf.d/cloudflare-realip.conf, generated from ips-v4 and ips-v6
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
# ... the other published ranges
real_ip_header CF-Connecting-IP;Rate limits, audit logs and geo rules at the origin all depend on this; without it, every client looks like a handful of Cloudflare addresses.
Locking the origin
The proxy protects nothing if the origin answers on its own IP. Origins leak through old DNS records, mail records on the same server, certificate transparency logs and internet-wide scans. Three ways to close the door, strongest last:
- Firewall to Cloudflare’s ranges on 80 and 443, refreshed when the list changes.
- Authenticated Origin Pulls: Cloudflare presents a client certificate, and the origin requires it (mTLS).
- Cloudflare Tunnel:
cloudflaredon the origin dials out to Cloudflare, so the origin needs no inbound ports at all.
WAF, rate limits, DDoS
- DDoS protection at the network and HTTP layers is on for every plan; the anycast network absorbs volume your origin never sees.
- WAF rules: managed rule sets for common attacks (paid plans), plus custom rules on any request field.
- Rate-limiting rules at the edge stop abuse before it costs origin capacity; keep application limits too, for per-user and per-API-key logic the edge cannot see.
A Matrix homeserver behind Cloudflare
Two facts decide whether it works:
- Only certain ports are proxied. For HTTPS: 443, 2053, 2083, 2087, 2096
and 8443. Matrix federation’s default 8448 is not among them, so a
proxied name breaks federation unless discovery points elsewhere: serve
/.well-known/matrix/serverreturning{"m.server": "matrix.example.org:443"}and let federation share 443 (Matrix and Synapse). - Requests time out after 125 seconds (error 524), adjustable only on
Enterprise. A 30-second
/synclong poll fits; long media uploads and admin exports may not, and belong on a DNS-only name.
WebSockets pass through the proxy on all plans; TURN does not (it is UDP and not HTTP), so a coturn server must be DNS-only (STUN, TURN and coturn).
Where it breaks in production
- Redirect loops from Flexible mode plus an origin HTTPS redirect, or “Always Use HTTPS” plus an origin redirect to HTTP.
- Every user has the same IP in logs and rate limiters: the real-IP module is missing or trusts the header from everywhere.
- The origin is attacked directly because its IP was never hidden or the firewall was never closed.
- The 52x family: 521 the origin refused the connection, 522 it timed out connecting, 524 it accepted but did not answer in 125 s, 525 and 526 TLS to the origin failed or its certificate is invalid under Full (strict).
- Stale content after a deploy when HTML was cached by a rule without
purging, or personal pages cached when a rule ignored
Set-Cookie. - Federation silently broken because 8448 is not proxied.
The trade not taken: a cloud provider’s CDN and WAF
The alternative on AWS is CloudFront plus AWS WAF plus Shield, with Route 53 for DNS. It keeps everything in one account and IAM, integrates with S3 and ALB origins natively, and bills per request and per rule. Cloudflare bundles DNS, CDN, TLS, WAF and DDoS protection in one product, with unmetered DDoS mitigation even on the free plan and a far simpler setup, at the cost of a second vendor and an origin that must be locked to it.
For a small team with a public web product, Cloudflare is usually the shorter path; for a stack deep in AWS with private origins, CloudFront is.
Related
Interview angle 5
- “What does Cloudflare do when you proxy a domain?” - the name resolves
to Cloudflare’s anycast addresses; the nearest edge terminates TLS, applies
cache, WAF, rate limits and DDoS filtering, then connects to your origin.
- Follow-up: which SSL mode? Full (strict), with a real or Origin CA certificate. Flexible sends plain HTTP to the origin and causes redirect loops.
- “Your app’s logs show all requests from a few IPs.” - they are
Cloudflare’s. Restore the client IP from
CF-Connecting-IPwithset_real_ip_fromlimited to Cloudflare’s published ranges.- Follow-up: why limited? Otherwise a request straight to the origin can claim any client IP.
- “How do you protect the origin?” - firewall it to Cloudflare’s ranges, require Authenticated Origin Pulls, or use a Tunnel so it has no inbound ports.
- “Can a Matrix homeserver sit behind Cloudflare?” - yes, with
.well-knowndelegation so federation uses 443: port 8448 is not proxied. TURN stays DNS-only, and requests over 125 seconds get a 524. - “What does Cloudflare cache by default?” - static files by extension,
not HTML or JSON, and nothing with
Set-Cookieorprivate,no-store,no-cacheormax-age=0.