FREE THOUGHT · FREE SOFTWARE · FREE WORLD

Block (or allow only) whole countries, or turn a messy list of IPs, CIDRs and ranges into the smallest set of rules. Output for Apache 2.4 Require, Apache 2.2, nginx, or ipset + iptables. Country ranges come from the five regional internet registries and refresh weekly.

Registry data says where address blocks were assigned, not where every user sits: VPNs, mobile carriers and clouds cross borders. "Allow only" also locks out search engines crawling from other countries. Behind Cloudflare or a load balancer, Apache must see the real visitor IP (mod_remoteip) or these rules match the proxy instead.

Sometimes the cleanest firewall rule is geography. If you sell to one country and the brute-force attempts on wp-login.php come from fifty others, you can make your login page invisible to most of the planet with a few dozen lines. This tool builds those lines from the source: the regional internet registries themselves.

Where the data comes from

Every IP block on earth is handed out by one of five RIRs: ARIN, RIPE NCC, APNIC, LACNIC and AFRINIC. Each publishes a daily delegated file listing every block, the country it was assigned to, and when. My server pulls all five, merges adjacent ranges and collapses them into the fewest possible CIDRs, IPv4 and IPv6, and refreshes weekly. No third-party GeoIP database, no license, no API key.

How to use it

  1. Pick countries, either to block or to allow only (allow-lists are far shorter and far stronger).
  2. Choose the scope: the whole site, or just a path like /wp-login.php or /wp-admin/.
  3. Pick the output: Apache 2.4 Require, nginx, iptables/ipset, or a plain CIDR list.
  4. Copy or download. The range counts and data date are shown so you know how big the list is before you paste it.

What the output looks like

Lock the login to one country, keep your own IP as a back door:

<Files "wp-login.php">
  <RequireAny>
    Require ip 203.0.113.7
    Require ip 24.0.0.0/12 47.0.0.0/8 2600::/12
    # ... generated ranges ...
  </RequireAny>
</Files>

Block a list of countries site-wide instead:

<RequireAll>
  Require all granted
  Require not ip 198.51.100.0/22 2001:db8::/32
</RequireAll>

Do it at the right layer

.htaccess with thousands of ranges works, but Apache rereads it on every request. For big lists move it into the server config, or better, push it down to the kernel with ipset where a hash lookup costs nothing:

ipset create blk hash:net family inet
while read -r c; do ipset add blk "$c"; done < blocked-v4.txt
iptables -I INPUT -m set --match-set blk src -p tcp -m multiport --dports 80,443 -j DROP

Behind Cloudflare or a load balancer, Apache sees the proxy's address, not the visitor's. Configure mod_remoteip first or you'll block your own CDN.

FAQ

How accurate is registry data?

It tells you which country a block was assigned to, which is right for the vast majority of addresses. It's wrong for VPNs, cloud regions and big multinationals that route space across borders. Treat it as a wall, not a lie detector.

Won't this lock out Google?

Blocking whole sites by country can. Googlebot crawls mostly from US ranges. That's why scoping to wp-login.php or an admin path is the move I'd make first.

Is a country block enough security?

No. Attackers rent servers in whatever country you allow. It cuts noise; it doesn't replace strong passwords, 2FA and patching. Pair it with the .htaccess generator's security block.