Skip to content
Back to skills

Cloudflare Block Countries

ASecurity

Block specific countries via Cloudflare WAF Custom Rules using the Cloudflare API. Use when user wants to geo-block traffic, block countries in Cloudflare, set up WAF country rules, or mentions blocking regions. Handles both creating new rulesets and updating existing ones.

  • 3 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 14, 2026
ai-agentsgobashexpressgitapisecurity

Works with

  • claude code
  • cursor
  • cli
  • api

Security analysis

A100/100

Scanned October 14, 2026

npx -y skills add oleg-koval/agent-skills --skill cloudflare-block-countries --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Cloudflare Block Countries?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Cloudflare Block Countries
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/oleg-koval-cloudflare-block-countries-agent-skills/badge)](https://www.skillsdirectory.com/skills/oleg-koval-cloudflare-block-countries-agent-skills)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: cloudflare-block-countries
description: 'Block specific countries via Cloudflare WAF Custom Rules using the Cloudflare API. Use when user wants to geo-block traffic, block countries in Cloudflare, set up WAF country rules, or mentions blocking regions. Handles both creating new rulesets and updating existing ones.'
license: MIT
allowed-tools: Bash
compatibility: Codex, Claude Code, Cursor, GitHub Copilot, Windsurf, Kiro, and other Agent Skills compatible tools. Requires curl and jq.
metadata:
  targets: [_source-only]
  author: Oleg Koval
  tags:
    - cloudflare
    - waf
    - security
    - geo-blocking
    - firewall
---

# Cloudflare Country Block via WAF Custom Rules

Block traffic from specific countries using Cloudflare WAF Custom Rules and the Cloudflare API.

## Prerequisites

- Cloudflare API Token with `Zone:Rulesets:Edit` permission
- Zone ID for the target domain
- `curl` and `jq` installed

## Workflow

### 1. Get Zone IDs

```bash
curl -s -X GET \
  "https://api.cloudflare.com/client/v4/zones?account.id=YOUR_ACCOUNT_ID&status=active" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" | jq '.result[] | {name: .name, id: .id}'
```

### 2. Check Existing Custom Firewall Rulesets

```bash
curl -s -X GET \
  "https://api.cloudflare.com/client/v4/zones/YOUR_ZONE_ID/rulesets" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" | \
  jq '.result[] | select(.phase == "http_request_firewall_custom")'
```

If the output is empty: no existing ruleset. Go to **3a**. If a ruleset exists, note its `id` and go to **3b**.

### 3a. Create NEW Ruleset with Block Rule

```bash
curl -s -X POST \
  "https://api.cloudflare.com/client/v4/zones/YOUR_ZONE_ID/rulesets" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "name": "default",
    "description": "WAF Custom Rules",
    "kind": "zone",
    "phase": "http_request_firewall_custom",
    "rules": [
      {
        "action": "block",
        "description": "Block traffic from sanctioned countries",
        "enabled": true,
        "expression": "(ip.src.country in {\"RU\" \"BY\" \"IR\" \"KP\"})"
      }
    ]
  }' | jq '.success'
```

### 3b. Update EXISTING Ruleset

```bash
curl -s -X PUT \
  "https://api.cloudflare.com/client/v4/zones/YOUR_ZONE_ID/rulesets/RULESET_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "description": "WAF Custom Rules",
    "rules": [
      {
        "action": "block",
        "description": "Block traffic from sanctioned countries",
        "enabled": true,
        "expression": "(ip.src.country in {\"RU\" \"BY\" \"IR\" \"KP\"})"
      }
    ]
  }' | jq '.success'
```

### 4. Verify the Rule is Active

```bash
curl -s -X GET \
  "https://api.cloudflare.com/client/v4/zones/YOUR_ZONE_ID/rulesets/RULESET_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" | jq '.result.rules'
```

## Country Codes Reference

| Code | Country |
|------|---------|
| `RU` | Russia |
| `BY` | Belarus |
| `IR` | Iran |
| `KP` | North Korea |
| `CN` | China |
| `CU` | Cuba |
| `SY` | Syria |
| `VE` | Venezuela |

## WAF Expression Examples

```
# Block multiple countries
(ip.src.country in {"RU" "BY" "IR" "KP"})

# Block country + specific ASN
(ip.src.country eq "RU") or (ip.geoip.asnum eq 12345)

# Block all except allowlisted IPs
(ip.src.country in {"RU" "BY"}) and not (ip.src in {1.2.3.4/32})
```

## Multi-Zone Script

To apply the same block rule across multiple zones:

```bash
#!/usr/bin/env bash
API_TOKEN="YOUR_API_TOKEN"
ZONES=("ZONE_ID_1" "ZONE_ID_2" "ZONE_ID_3")
EXPRESSION='(ip.src.country in {"RU" "BY" "IR" "KP"})'

for ZONE_ID in "${ZONES[@]}"; do
  EXISTING=$(curl -s -X GET \
    "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets" \
    -H "Authorization: Bearer $API_TOKEN" \
    -H "Content-Type: application/json" | \
    jq -r '.result[] | select(.phase == "http_request_firewall_custom") | .id')

  if [ -z "$EXISTING" ]; then
    METHOD="POST"
    URL="https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets"
    DATA=$(jq -n --arg expr "$EXPRESSION" '{
      name: "default", description: "WAF Custom Rules",
      kind: "zone", phase: "http_request_firewall_custom",
      rules: [{action: "block", description: "Block sanctioned countries", enabled: true, expression: $expr}]
    }')
  else
    METHOD="PUT"
    URL="https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets/$EXISTING"
    DATA=$(jq -n --arg expr "$EXPRESSION" '{
      description: "WAF Custom Rules",
      rules: [{action: "block", description: "Block sanctioned countries", enabled: true, expression: $expr}]
    }')
  fi

  RESULT=$(curl -s -X "$METHOD" "$URL" \
    -H "Authorization: Bearer $API_TOKEN" \
    -H "Content-Type: application/json" \
    --data "$DATA" | jq '.success')

  echo "Zone $ZONE_ID: $RESULT"
done
```

## Notes

- `PUT` on an existing ruleset **replaces all rules** in it. Include all rules in the payload if the ruleset already has other rules.
- WAF Custom Rules require a Cloudflare plan that supports rulesets (Free includes basic WAF; Pro/Business/Enterprise for full custom rules).
- Changes are applied globally within seconds; no cache purge needed.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.