6 · Cloudflare CDN
Objective — front the app with Cloudflare on the Free plan (TLS termination, DDoS absorption, a WAF, global caching): nameserver cutover, API-driven DNS, Full (Strict) SSL + HSTS, WAF and rate limiting, cache rules, DNSSEC, and a final API verification probe — with Rocket Loader OFF for Laravel.
Background
Section titled “Background”1. Budget against the Free plan
Section titled “1. Budget against the Free plan”Free tier limits are real — plan inside them so nothing silently fails to apply.
| Resource | Free-plan budget | Notes |
|---|---|---|
| WAF custom rules | 5 | Spend on the highest-value blocks |
| Rate-limiting rules | 1 | Reserve for login/API abuse |
| Cache rules | a few | One good static-asset rule goes far |
| Page Rules (legacy) | 3 | Prefer modern Rules where possible |
2. Add the zone and cut over nameservers
Section titled “2. Add the zone and cut over nameservers”-
Add the site as a zone in Cloudflare; it imports existing records — audit the import against what page 2 and page 5 created.
- ✅ The zone exists and its imported records have been audited.
-
Update the registrar’s nameservers to Cloudflare’s pair, then wait for the zone to go Active.
Terminal window dig NS example.com # returns Cloudflare nameservers once Active# Expected: the NS query returns Cloudflare's nameserver pair- ✅
dig NS example.comreturns Cloudflare and the zone shows Active.
- ✅
3. Configure DNS via the API
Section titled “3. Configure DNS via the API”Drive record changes through the API so they’re scriptable and auditable. Use a scoped token (Zone:DNS:Edit), never the global key.
-
Create records through the API — load the token from vault or a mode-600 file; never
export CF_API_TOKEN="<literal>"in a runbook (visible in shell history andps):Terminal window # CF_API_TOKEN and ZONE_ID already exported from vault / ~/.zshrc (see Phase 1 machine setup)curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \-H "Authorization: Bearer $CF_API_TOKEN" -H "Content-Type: application/json" \--data '{"type":"A","name":"app","content":"<origin-ip>","proxied":true}'# Expected: a JSON response with "success":true and the created record- ✅ Records are created via the scoped-token API;
proxied:true(orange cloud) routes traffic through Cloudflare,false(grey cloud) is DNS-only.
- ✅ Records are created via the scoped-token API;
4. Set SSL/TLS and HSTS
Section titled “4. Set SSL/TLS and HSTS”- Set SSL mode to Full (Strict) — encrypts edge↔origin and validates the origin cert.
Flexiblecauses redirect loops and is insecure. - Enable Always Use HTTPS.
- Enable HSTS only once you’re confident HTTPS is permanent (it’s hard to undo):
max-age≥ 6 months, include subdomains, preload optional.
5. Configure security: WAF + rate limiting
Section titled “5. Configure security: WAF + rate limiting”Spend the 5 WAF rules on real threats (block bad bots, restrict /admin by country/ASN, challenge suspicious paths). Use the single rate-limit rule on the login or API endpoint most likely to be brute-forced.
6. Configure caching and speed
Section titled “6. Configure caching and speed”- Cache rule: cache static assets (
/build/*,/images/*) aggressively; bypass cache for authenticated/app routes and anything with a session cookie. - Enable Brotli and Tiered Cache. (Cloudflare removed Auto Minify in Aug 2024 — minify in your build pipeline instead.)
7. Enable DNSSEC and optional Zero Trust
Section titled “7. Enable DNSSEC and optional Zero Trust”- Enable DNSSEC in Cloudflare, then add the DS record it generates at your registrar — DNSSEC isn’t active until the registrar side is done.
- Optionally protect staging with Zero Trust Access (email-OTP gate) so the unfinished site isn’t public.
8. Run the final verification probe
Section titled “8. Run the final verification probe”Confirm the edge is live, encrypted end-to-end, and DNSSEC-validated.
-
Probe the zone over HTTP and the API.
Terminal window # Zone is active and proxied (expect cf-ray + cf-cache-status headers)curl -sI https://app.example.com | grep -iE 'cf-ray|cf-cache-status|strict-transport'# SSL mode end-to-end (expect HTTP/2 200, valid cert)curl -sI https://app.example.com | head -1# DNSSEC validated via a validating resolver (AD bit)dig +dnssec @1.1.1.1 example.com A | grep -q 'flags:.* ad' && echo "DNSSEC validated"dig DNSKEY example.com +short | grep -q . && echo "DNSKEY published"# Zone status via APIcurl -s "https://api.cloudflare.com/client/v4/zones/$ZONE_ID" \-H "Authorization: Bearer $CF_API_TOKEN" | grep -o '"status":"[^"]*"'# Expected: cf-ray present (proxied), a strict-transport-security header, zone "status":"active", and DNSSEC validated- ✅ The probe shows
cf-ray(proxied), thestrict-transport-securityheader (HSTS), zone"status":"active", and DNSSEC validated.
- ✅ The probe shows
Checklist
Section titled “Checklist”Do not mark this step done until every box below is checked.
- 👤 Zone Active — nameservers are Cloudflare’s; imported records audited (esp. email DNS).
- 👤 SSL hardened — SSL = Full (Strict), Always Use HTTPS on, HSTS set.
- 👤 WAF within budget — WAF rules + 1 rate-limit rule within Free-plan budget.
- 🔀 Cache rule live — static-asset cache rule live; app/auth routes bypass cache.
- 🔀 Rocket Loader OFF; DNSSEC active — DS added at registrar.
- 🤖 Probe green — verification probe shows
cf-ray, HSTS header, and"status":"active".