Skip to content
prod e051e98
Browse

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.

Free tier limits are real — plan inside them so nothing silently fails to apply.

ResourceFree-plan budgetNotes
WAF custom rules5Spend on the highest-value blocks
Rate-limiting rules1Reserve for login/API abuse
Cache rulesa fewOne good static-asset rule goes far
Page Rules (legacy)3Prefer modern Rules where possible
  1. 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.
  2. 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.com returns Cloudflare and the zone shows Active.

Drive record changes through the API so they’re scriptable and auditable. Use a scoped token (Zone:DNS:Edit), never the global key.

  1. 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 and ps):

    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.
  • Set SSL mode to Full (Strict) — encrypts edge↔origin and validates the origin cert. Flexible causes 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.

  • 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.)
  • 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.

Confirm the edge is live, encrypted end-to-end, and DNSSEC-validated.

  1. 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 API
    curl -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), the strict-transport-security header (HSTS), zone "status":"active", and DNSSEC validated.

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".