Country block (temporary geo gate)
Block visitors by Cloudflare’s CF-IPCountry header for a limited time (TTL). Intended for event windows — not as a permanent security control (use WAF for that).
Requirements
Section titled “Requirements”- Zone IP Geolocation on (Admin → Cloudflare access → Check/Fix setup).
- Traffic proxied (orange cloud) so Cloudflare attaches geo headers.
Behaviour
Section titled “Behaviour”| Request | Result |
|---|---|
| Country on active block list | 403 branded “Not available in your region” |
| IP allowlisted | Not geo-blocked (office override) |
| Admin Pass queue | Not geo-blocked |
| Valid admission cookie | Allowed through |
| List expired (TTL) | Block inactive — everyone queues normally |
Unknown XX / T1 |
Not blocked unless those codes are listed |
Checked on protected origin paths, /wait, /demo, and POST /join — before the waiting room / Durable Object.
Admin setup
Section titled “Admin setup”/admin→ Country block- Enter ISO codes (one per line), e.g.
CN,RU - Set TTL (hours) (required when enabling; max 30 days)
- Enable + Save country block (resets the hit counter window)
- Status shows your
CF-IPCountryand whether you would be blocked - Live queue shows Geo blocks total + per-country hits (refreshes every 5s)
- Disable now clears the active gate (keeps the code list in the form)
Hit stats live in KV (admin:geo-block-stats) separately from the block list so saves keep history until you enable a new window. Totals appear in the admin Live metrics strip and Access tab (see analytics.md).
Clients (full page, widget, API)
Section titled “Clients (full page, widget, API)”| Surface | Behaviour when blocked |
|---|---|
Full page /wait |
403 HTML “Not available in your region” |
Widget /wait?embed=1 |
Same HTML, embed-sized layout |
Waiting-room JS (if /join 403) |
Stops polling; shows region error in-page |
Custom API POST /join |
403 JSON { error: { code: "forbidden", details: { country } } } |
Marketing demos at tideguard.dev include a Simulate geo block control on full / widget / API pages.
PUT /api/admin/geo-block
{ "enabled": true, "countriesText": "CN\nRU", "ttlHours": 24}Stored in KV (admin:geo-block) as { enabled, countries, expiresAt, updatedAt }.
