How to block IP addresses and whole countries on Cloudflare

powerpurple1 pts0 comments

Block IPs and countries on Cloudflare — Ampliflare Blog

← Blog<br>How IP and region blocking actually works on Cloudflare<br>How to block IP addresses and whole countries on Cloudflare. The Rulesets engine, firewall expressions, IP lists, and the token scopes you need.<br>Jun 21, 2026 · by Nadeem Siddique<br>Cloudflare WAF Firewall rules

code]:rounded [&_:not(pre)>code]:bg-muted [&_:not(pre)>code]:px-1.5 [&_:not(pre)>code]:py-0.5 [&_:not(pre)>code]:font-heading [&_:not(pre)>code]:text-xs [&_:not(pre)>code]:text-foreground [&_h2]:mt-10 [&_h2]:mb-3 [&_h2]:scroll-mt-24 [&_h2]:font-heading [&_h2]:text-base [&_h2]:font-bold [&_h2]:text-foreground [&_h3]:mt-6 [&_h3]:mb-2 [&_h3]:scroll-mt-24 [&_h3]:font-heading [&_h3]:text-sm [&_h3]:font-bold [&_h3]:text-foreground [&_hr]:my-8 [&_hr]:border-border [&_ol]:my-4 [&_ol]:list-decimal [&_ol]:space-y-1.5 [&_ol]:pl-5 [&_p]:my-4 [&_.expressive-code]:my-4 [&_strong]:font-semibold [&_strong]:text-foreground [&_table]:my-4 [&_table]:w-full [&_table]:text-left [&_table]:text-xs [&_td]:border-b [&_td]:border-border [&_td]:py-2 [&_td]:pr-4 [&_th]:border-b [&_th]:border-border [&_th]:py-2 [&_th]:pr-4 [&_th]:font-heading [&_th]:font-bold [&_th]:text-foreground [&_ul]:my-4 [&_ul]:list-disc [&_ul]:space-y-1.5 [&_ul]:pl-5"> Your site is getting hammered by a spread of IP addresses out of one country. You open the Cloudflare dashboard to block them, and an hour later you’re three docs pages deep in firewall expressions, “rulesets,” and account-level IP lists, still not sure you did it right.

Blocking traffic on Cloudflare sounds like it should be a single setting. It isn’t. There are several firewall systems to choose between, an expression syntax to learn, account-level IP lists, and a ruleset “phase” you attach the rule to. Blocking a whole country is a different shape again.

None of it is hard once you’ve done it once. The friction is that you usually learn it mid-incident, while something is hammering your site and you just want it to stop. Here’s how both cases work, including the parts the docs make you stitch together yourself.

There isn’t one firewall, there are layers

Cloudflare has shipped multiple generations of firewall: legacy IP Access Rules, legacy Firewall Rules, and the current Rulesets engine (also called WAF custom rules). New rules should go through the Rulesets engine, but tutorials and Stack Overflow answers mix all three, which is half the confusion.

The Rulesets engine works in phases, which are stages in request processing. Your custom blocking rules live in the phase called http_request_firewall_custom. Before you can add a rule, that phase needs an entrypoint ruleset on your zone, and if you’ve never added a custom rule it doesn’t exist yet. So step one is always: fetch the entrypoint, and create it if it’s missing.

GET /zones/{zone_id}/rulesets/phases/http_request_firewall_custom/entrypoint

Once you have it, a rule is an expression plus an action. The action is block. The expression is where IP and country blocking diverge.

Blocking a country: an expression is enough

Cloudflare already knows the country of every request. It geolocates the connecting IP and exposes it as a field you can reference directly:

ip.src.country in {"US" "CN" "RU"}

That’s the whole rule. ISO 3166 alpha-2 codes, uppercase, quoted, space-separated, inside braces. Attach it to the firewall phase with action: block and you’re done. You don’t need a list or any extra storage; the geolocation is built into the engine.

The only thing that trips people up is the syntax. It’s {"US" "CN"}, not ["US","CN"] or US,CN. Get a brace or a quote wrong and the rule silently matches nothing.

Blocking an IP: a list, not inline rules

You can block a single address with an inline expression like ip.src eq 203.0.113.10 (that’s a documentation example address; use a real one). But the moment you have more than a couple, inline expressions get unwieldy, and each zone has a finite rule budget you don’t want to spend one IP at a time.

The better pattern is an account-level IP List. Create one list, add every IP and CIDR you want to block, and write a single rule that references it by name:

ip.src in $blocked_ips

Now the rule never changes. Blocking another address is just adding an item to the list. And because the list lives at the account level, one blocklist can back rules across every zone you own. Update it once, and every zone honours it.

Lists vs expressions: the asymmetry worth remembering

This is the part the docs won’t put in one place. IP blocks and country blocks feel like the same feature, but they’re built on different primitives, and that changes how you edit them later:

To change which countries are blocked, you rewrite the rule’s expression.

To change which IPs are blocked, you edit the list and leave the rule alone.

If you ever build a UI or a script over this, that asymmetry is the thing to design around.

The token scopes you’ll need

This one bites people mid-task. The two...

rule text cloudflare list block blocking

Related Articles