|
| 1 | +# Cloudflare dormant setup (free tier) |
| 2 | + |
| 3 | +Pre-configured Cloudflare account for codecrispi.es. **Proxy stays OFF** (gray cloud, DNS-only). Traffic goes direct to netcup. When HN/reddit spike forces it, flip one toggle per record to **orange cloud** → traffic now absorbed by CF edge. |
| 4 | + |
| 5 | +## Why dormant? |
| 6 | + |
| 7 | +- Zero behavior change vs current state — traffic still direct |
| 8 | +- CF account configured, nameservers transferred, rules ready |
| 9 | +- Activation = single toggle in CF dashboard. No code change, no DNS propagation wait. ~5 min from spike → mitigation. |
| 10 | +- Revertible — flip back to gray cloud → back to direct origin |
| 11 | + |
| 12 | +## One-time setup (user-only, ~30 min) |
| 13 | + |
| 14 | +### 1. Create Cloudflare account |
| 15 | + |
| 16 | +- https://dash.cloudflare.com/sign-up |
| 17 | +- Use a real email (LE renewals + abuse alerts route here) |
| 18 | +- Enable 2FA at account level |
| 19 | + |
| 20 | +### 2. Add site |
| 21 | + |
| 22 | +- "Add a Site" → enter `codecrispi.es` |
| 23 | +- Plan: **Free** |
| 24 | +- CF scans current DNS at netcup; verify it imports: |
| 25 | + - A `codecrispi.es` → `37.120.174.54` |
| 26 | + - AAAA `codecrispi.es` → `2a03:4000:6:776d:34d0:3dff:feb9:d51a` |
| 27 | + - A `www.codecrispi.es` → `37.120.174.54` |
| 28 | + - AAAA `www.codecrispi.es` → `2a03:4000:6:776d:34d0:3dff:feb9:d51a` |
| 29 | + - (No MX — no email at apex) |
| 30 | + - (Any TXT records for DKIM/SPF/verification — preserve) |
| 31 | + |
| 32 | +### 3. Set ALL records to DNS-only (gray cloud) |
| 33 | + |
| 34 | +Critical step. Per record in the DNS list: |
| 35 | +- Toggle the orange cloud icon → **gray cloud** |
| 36 | +- This means: CF answers DNS queries but does NOT proxy the traffic |
| 37 | +- Traffic flows: client → CF DNS resolution → direct connect to netcup |
| 38 | +- CF sees the DNS query but never the HTTP request |
| 39 | + |
| 40 | +### 4. Change nameservers at netcup |
| 41 | + |
| 42 | +- CF dashboard shows the two NS records to set (e.g. `nina.ns.cloudflare.com` + `walt.ns.cloudflare.com`) |
| 43 | +- Log into netcup customer portal → DNS → change nameservers for `codecrispi.es` |
| 44 | +- Wait for propagation (~5min–24h depending on TTL of current netcup NS records) |
| 45 | +- CF dashboard turns "Active" once it detects the NS change |
| 46 | + |
| 47 | +### 5. Pre-configure cache rules (dormant) |
| 48 | + |
| 49 | +These rules ONLY take effect when proxy is ON (orange). Configuring now = ready to flip: |
| 50 | + |
| 51 | +**Cache Rule 1: Cache everything static** |
| 52 | +- Hostname: `codecrispi.es` OR `www.codecrispi.es` |
| 53 | +- AND URI Path matches `\.(js|css|png|jpg|svg|ico|webmanifest|woff2?|ttf|map)$` |
| 54 | +- THEN: Cache eligibility → Eligible for cache, Edge TTL → 1 year |
| 55 | + |
| 56 | +**Cache Rule 2: Cache HTML for 5 minutes** |
| 57 | +- Hostname matches |
| 58 | +- AND URI Path matches `\.html$` OR ends with `/` |
| 59 | +- THEN: Edge TTL → 5 min |
| 60 | + |
| 61 | +**Bypass: API + auth** |
| 62 | +- URI Path starts with `/api/` OR `/auth/` OR `/health` |
| 63 | +- THEN: Cache eligibility → Bypass |
| 64 | + |
| 65 | +### 6. Verify direct origin still works |
| 66 | + |
| 67 | +```bash |
| 68 | +# DNS now from CF (gray cloud = same IP) |
| 69 | +dig +short codecrispi.es @1.1.1.1 |
| 70 | +# expect: 37.120.174.54 |
| 71 | + |
| 72 | +# HTTPS still hits netcup (Caddy cert) |
| 73 | +curl -sI https://codecrispi.es/ | grep -i server |
| 74 | +# expect: Server: Caddy (NOT Cloudflare) |
| 75 | +``` |
| 76 | + |
| 77 | +## Activation (when ready, ~5 min) |
| 78 | + |
| 79 | +For each of the 4 records (apex A+AAAA, www A+AAAA): |
| 80 | + |
| 81 | +1. CF dashboard → DNS → Records |
| 82 | +2. Click the gray cloud icon next to the record |
| 83 | +3. It turns **orange** → CF is now proxying |
| 84 | + |
| 85 | +Verify: |
| 86 | + |
| 87 | +```bash |
| 88 | +# DNS now returns CF anycast IPs |
| 89 | +dig +short codecrispi.es @1.1.1.1 |
| 90 | +# expect: 104.x.x.x or 172.x.x.x (CF IPs) |
| 91 | + |
| 92 | +curl -sI https://codecrispi.es/ | grep -i server |
| 93 | +# expect: Server: cloudflare |
| 94 | +``` |
| 95 | + |
| 96 | +CF requests new edge TLS cert automatically (~30s). HTTPS keeps working through the swap because CF Universal SSL provisions in parallel. |
| 97 | + |
| 98 | +## Rollback (~30 sec) |
| 99 | + |
| 100 | +Click orange cloud → gray cloud per record. Traffic immediately falls back to direct origin. CF cache continues serving stale content for ~30 seconds while routing transitions. |
| 101 | + |
| 102 | +## What you give up |
| 103 | + |
| 104 | +- **Origin TLS termination** → CF re-terminates at edge with their cert. Your Caddy LE cert still works in parallel; CF's just takes precedence at the edge |
| 105 | +- **Real client IPs** → arrive in `CF-Connecting-IP` header; nginx logs show CF IPs in `$remote_addr` unless you configure `real_ip_header` (see below) |
| 106 | +- **No JS injection** — CF doesn't inject scripts on free tier (Pro+ has the option for analytics; off by default) |
| 107 | +- **Privacy** — CF sees full URL + user IP for every cached miss |
| 108 | + |
| 109 | +## Optional: real client IP at origin |
| 110 | + |
| 111 | +If you want real IPs in nginx logs after CF activation, add to `nginx.conf` http block: |
| 112 | + |
| 113 | +```nginx |
| 114 | +set_real_ip_from 173.245.48.0/20; |
| 115 | +set_real_ip_from 103.21.244.0/22; |
| 116 | +set_real_ip_from 103.22.200.0/22; |
| 117 | +set_real_ip_from 103.31.4.0/22; |
| 118 | +set_real_ip_from 141.101.64.0/18; |
| 119 | +set_real_ip_from 108.162.192.0/18; |
| 120 | +set_real_ip_from 190.93.240.0/20; |
| 121 | +set_real_ip_from 188.114.96.0/20; |
| 122 | +set_real_ip_from 197.234.240.0/22; |
| 123 | +set_real_ip_from 198.41.128.0/17; |
| 124 | +set_real_ip_from 162.158.0.0/15; |
| 125 | +set_real_ip_from 104.16.0.0/13; |
| 126 | +set_real_ip_from 104.24.0.0/14; |
| 127 | +set_real_ip_from 172.64.0.0/13; |
| 128 | +set_real_ip_from 131.0.72.0/22; |
| 129 | +real_ip_header CF-Connecting-IP; |
| 130 | +``` |
| 131 | + |
| 132 | +(CF IP list: https://www.cloudflare.com/ips/ — update on schedule) |
| 133 | + |
| 134 | +Defer this until activation; works fine without for free-tier needs. |
| 135 | + |
| 136 | +## Cost |
| 137 | + |
| 138 | +**EUR 0/mo for free tier.** Unlimited bandwidth + requests. Pro ($20/mo) only adds WAF + image polish — not needed for this app. |
| 139 | + |
| 140 | +## Activation triggers (when to flip) |
| 141 | + |
| 142 | +- Show HN / reddit /r/programming / dev.to frontpage submission planned in <2 days |
| 143 | +- Sustained > 50 rps measured against current ceiling |
| 144 | +- DDoS attempt observed in nginx logs |
| 145 | +- Star count crosses 500 (likely future popularity) |
| 146 | + |
| 147 | +## What this PR adds |
| 148 | + |
| 149 | +`docs/CLOUDFLARE-PREP.md` — this file. No code change, no infra change. |
| 150 | +The user-side setup steps stay user-only (CF account, registrar nameserver change). Activation runbook documented for when needed. |
0 commit comments