Introduction

Geo-blocking is a Web Application Firewall (WAF) feature that restricts access based on the geographic location of IP addresses. It's used to comply with regulations, reduce attack surface, or block traffic from high-risk regions. When geo-blocking fails, traffic from blocked countries reaches the application, potentially violating compliance requirements or exposing services to attacks. Geo-blocking issues typically stem from outdated GeoIP databases, incorrect country code specifications, rule ordering problems, IP header spoofing, or the GeoIP module not being enabled. Understanding how to configure and debug geo-blocking rules is essential for effective geographic access control.

Symptoms

When WAF geo-blocking is not filtering correctly, you will observe:

  • Traffic from blocked countries still reaching the application
  • Access logs showing requests from blocked country codes
  • No block entries in WAF logs for specified countries
  • Geo-blocking rules show as active but have no matches
  • False positives - legitimate traffic being blocked incorrectly
  • Inconsistent behavior - some IPs blocked, others from same country not

Testing from blocked country shows: ``bash # From a blocked country (e.g., via VPN) curl -v https://yourdomain.com/ # Expected: 403 Forbidden # Actual: 200 OK (site loads normally)

WAF dashboard shows: `` Geo-blocking Rule: Block Country X Status: Enabled Hits: 0

Access logs show requests from blocked countries: `` 192.0.2.1 (Country: CN) - GET /admin - 200 198.51.100.1 (Country: RU) - POST /api - 200

Common Causes

  1. 1.GeoIP database outdated - IP-to-country mapping stale or missing
  2. 2.Incorrect country codes - Using wrong ISO codes (CN vs CHN)
  3. 3.Rule not in correct position - Other rules allow before geo-block
  4. 4.GeoIP module disabled - MaxMind or GeoIP module not loaded
  5. 5.Missing database license - MaxMind requires license key for updates
  6. 6.IP header spoofing - X-Forwarded-For overriding real IP
  7. 7.Proxy/CDN hiding origin - CloudFlare, CloudFront hiding real IP
  8. 8.Rule exceptions misconfigured - Exception paths bypass geo-block
  9. 9.IPv6 not configured - Only IPv4 addresses blocked
  10. 10.Cache bypassing WAF - Cached responses served before WAF evaluation

Step-by-Step Fix

Step 1: Verify GeoIP Database Status

Check if GeoIP database is installed and current:

For ModSecurity with GeoIP: ```bash # Check GeoIP database location ls -la /usr/share/GeoIP/ ls -la /var/lib/GeoIP/

# Check database age stat /usr/share/GeoIP/GeoIP.dat stat /usr/share/GeoIP/GeoIPv6.dat

# Check MaxMind database ls -la /usr/share/GeoIP/GeoLite2-Country.mmdb

# Check ModSecurity GeoIP configuration grep -r "SecGeoLookupDb" /etc/modsecurity/ ```

For Nginx with GeoIP: ```bash # Check Nginx GeoIP module nginx -V 2>&1 | grep -i geoip

# Check GeoIP database in Nginx config grep -r "geoip_country|geoip_city" /etc/nginx/

# Test GeoIP lookup nginx -t 2>&1 ```

For AWS WAF: ```bash # Check AWS WAF geo-match rules aws wafv2 list-rules --scope REGIONAL --region us-east-1

# Get rule details aws wafv2 get-rule --scope REGIONAL \ --id <rule-id> \ --name <rule-name> ```

Step 2: Update GeoIP Database

Ensure GeoIP database is current:

MaxMind GeoLite2 (free, requires account): ```bash # Install GeoIP update tool sudo apt install geoipupdate

# Configure with license key sudo vim /etc/GeoIP.conf ```

Add configuration: ``ini AccountID YOUR_ACCOUNT_ID LicenseKey YOUR_LICENSE_KEY EditionIDs GeoLite2-Country GeoLite2-City DatabaseDirectory /usr/share/GeoIP

Run update: ```bash # Update databases sudo geoipupdate

# Verify update ls -la /usr/share/GeoIP/GeoLite2-Country.mmdb

# Set up automatic updates sudo systemctl enable geoipupdate.timer ```

Manual database update: ```bash # Download latest GeoLite2 wget https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=YOUR_KEY -O GeoLite2-Country.tar.gz

# Extract and install tar -xzf GeoLite2-Country.tar.gz sudo mv GeoLite2-Country_*/GeoLite2-Country.mmdb /usr/share/GeoIP/ ```

Step 3: Test GeoIP Lookup

Verify GeoIP lookups work correctly:

```bash # Test IP-to-country lookup # Using mmdblookup (MaxMind) mmdblookup --file /usr/share/GeoIP/GeoLite2-Country.mmdb --ip 8.8.8.8

# Using geoiplookup (legacy) geoiplookup 8.8.8.8

# Test specific country IPs # China IP geoiplookup 202.96.128.86

# Russia IP geoiplookup 77.88.55.55

# US IP geoiplookup 8.8.8.8 ```

Expected output for US IP: `` GeoIP Country Edition: US, United States

Step 4: Configure Geo-Blocking Rules Correctly

Set up proper geo-blocking rules:

ModSecurity Configuration: ``bash sudo vim /etc/modsecurity/modsecurity.conf

Add GeoIP configuration: ```apache # Load GeoIP database SecGeoLookupDb /usr/share/GeoIP/GeoLite2-Country.mmdb

# Geo-blocking rule SecRule REMOTE_ADDR "@geoLookup" \ "phase:1,chain,deny,status:403,id:100001,msg:'Blocked by GeoIP'" SecRule GEO:COUNTRY_CODE "@pm CN RU KP IR" \ "msg:'Blocked country: %{GEO:COUNTRY_CODE}'" ```

Nginx Configuration: ```nginx # In http block geoip_country /usr/share/GeoIP/GeoLite2-Country.mmdb;

# Map for blocked countries map $geoip_country_code $blocked_country { default 0; CN 1; RU 1; KP 1; IR 1; }

# In server block server { if ($blocked_country) { return 403 "Access denied from your country"; } } ```

AWS WAF Configuration: ``bash # Create geo-match rule aws wafv2 create-rule-group \ --name GeoBlockRuleGroup \ --scope REGIONAL \ --capacity 10 \ --rules '[{ "Name": "BlockCountries", "Priority": 0, "Statement": { "GeoMatchStatement": { "CountryCodes": ["CN", "RU", "KP", "IR"] } }, "Action": { "Block": {} }, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "GeoBlockMetric" } }]'

Step 5: Use Correct Country Codes

Ensure correct ISO 3166-1 alpha-2 codes:

```bash # Common country codes reference cat << 'EOF' # Use these ISO 3166-1 alpha-2 codes: CN - China RU - Russia KP - North Korea IR - Iran NG - Nigeria BR - Brazil IN - India US - United States GB - United Kingdom DE - Germany JP - Japan KR - South Korea (NOT KP!) AU - Australia CA - Canada

# WRONG codes that won't work: CHN - China (use CN, not CHN) RUS - Russia (use RU, not RUS) KOR - South Korea (use KR, not KOR) EOF ```

Verify in configuration: ``bash # Check your geo-block configuration grep -E "Country|COUNTRY|geo" /etc/modsecurity/*.conf grep -E "pm\(|@pm" /etc/modsecurity/*.conf

Step 6: Handle Proxy/CDN IP Addresses

When behind CDN or proxy, get real client IP:

CloudFlare Configuration: ```nginx # In Nginx set_real_ip_from 103.21.244.0/22; set_real_ip_from 103.22.200.0/22; set_real_ip_from 103.31.4.0/22; set_real_ip_from 104.16.0.0/13; set_real_ip_from 104.24.0.0/14; set_real_ip_from 108.162.192.0/18; set_real_ip_from 131.0.72.0/22; set_real_ip_from 141.101.64.0/18; set_real_ip_from 162.158.0.0/15; set_real_ip_from 172.64.0.0/13; set_real_ip_from 173.245.48.0/20; set_real_ip_from 188.114.96.0/15; set_real_ip_from 190.93.240.0/20; set_real_ip_from 197.234.240.0/22; set_real_ip_from 198.41.128.0/17;

real_ip_header CF-Connecting-IP; real_ip_recursive on; ```

AWS CloudFront Configuration: ```nginx # Get CloudFront IP ranges curl -s https://ip-ranges.amazonaws.com/ip-ranges.json | jq -r '.prefixes[] | select(.service=="CLOUDFRONT") | .ip_prefix'

# Configure in Nginx set_real_ip_from 13.32.0.0/15; # ... add all CloudFront ranges real_ip_header X-Forwarded-For; real_ip_recursive on; ```

ModSecurity with proxy: ``apache # Use correct IP header SecRule REQUEST_HEADERS:X-Forwarded-For ".*" \ "phase:1,pass,nolog,chain,id:100000" SecRule REMOTE_ADDR "@geoLookup"

Step 7: Verify Rule Order and Priority

Ensure geo-block rule executes before allow rules:

```bash # Check rule order in ModSecurity grep -n "SecRule" /etc/modsecurity/*.conf | head -20

# Rules execute in phase and ID order # Geo-block should be in phase:1 or phase:2 ```

Correct rule ordering: ```apache # GOOD: Geo-block first, then other checks SecRule REMOTE_ADDR "@geoLookup" "phase:1,chain,deny,id:100001" SecRule GEO:COUNTRY_CODE "@pm CN RU" "msg:'Geo-blocked'"

# Then other rules SecRule REQUEST_URI "/admin" "phase:2,allow,id:100002" # This won't execute for blocked countries

# BAD: Allow rule before geo-block SecRule REQUEST_URI "/public" "phase:1,allow,id:100001" # Allows all, geo-block never runs SecRule REMOTE_ADDR "@geoLookup" "phase:2,chain,deny,id:100002" # Too late! ```

Step 8: Test Geo-Blocking

Verify geo-blocking is working:

```bash # Test with IPs from different countries # Use VPN or proxy to test from blocked countries

# Test from China IP curl -H "X-Forwarded-For: 202.96.128.86" https://yourdomain.com/test # Expected: 403 Forbidden

# Test from US IP curl -H "X-Forwarded-For: 8.8.8.8" https://yourdomain.com/test # Expected: 200 OK

# Check WAF logs tail -f /var/log/modsecurity/audit.log | grep -i "geo|country" ```

Using online testing tools: ```bash # Use services like: # - https://geo.ipify.org/ # - https://iplocation.com/ # - VPN services to test from different countries

# Test via curl with known IPs declare -A country_ips=( ["CN"]="202.96.128.86" ["RU"]="77.88.55.55" ["US"]="8.8.8.8" ["GB"]="8.8.4.4" )

for country in "${!country_ips[@]}"; do echo "Testing $country (${country_ips[$country]}):" curl -s -o /dev/null -w "%{http_code}" \ -H "X-Forwarded-For: ${country_ips[$country]}" \ https://yourdomain.com/ echo "" done ```

Verification

After configuration, verify geo-blocking works:

```bash # Check WAF rule is loaded # ModSecurity: curl -s http://localhost/modsec-status | grep geo

# Check blocked requests in logs grep -r "Blocked country|GeoIP" /var/log/modsecurity/audit.log

# Verify GeoIP module is loaded nginx -V 2>&1 | grep geoip apachectl -M | grep geoip

# Test from blocked country (via VPN) curl -v https://yourdomain.com/ 2>&1 | grep -E "HTTP|403" # Expected: HTTP/1.1 403 Forbidden ```

Monitor geo-blocking effectiveness: ```bash # Count blocked requests by country grep "Blocked country" /var/log/modsecurity/audit.log | \ awk -F'country: ' '{print $2}' | tr -d "'" | sort | uniq -c | sort -rn

# Check recent blocks grep "Blocked country" /var/log/modsecurity/audit.log | tail -20 ```

Prevention

To prevent geo-blocking issues:

  1. 1.Set up automatic database updates:
  2. 2.```bash
  3. 3.# Cron job for GeoIP updates
  4. 4.0 3 * * 0 /usr/bin/geoipupdate > /var/log/geoip-update.log 2>&1
  5. 5.`
  6. 6.Monitor database age:
  7. 7.```bash
  8. 8.# Alert if database older than 30 days
  9. 9.DB_AGE=$(($(date +%s) - $(stat -c %Y /usr/share/GeoIP/GeoLite2-Country.mmdb)))
  10. 10.if [ $DB_AGE -gt 2592000 ]; then
  11. 11.echo "GeoIP database is older than 30 days"
  12. 12.fi
  13. 13.`
  14. 14.Log geo-blocking decisions:
  15. 15.```apache
  16. 16.SecRule GEO:COUNTRY_CODE "@pm CN RU" \
  17. 17."phase:1,deny,log,auditlog,msg:'Geo-block: %{GEO:COUNTRY_CODE}'"
  18. 18.`
  19. 19.Use both IPv4 and IPv6 databases:
  20. 20.```apache
  21. 21.SecGeoLookupDb /usr/share/GeoIP/GeoLite2-Country.mmdb
  22. 22.# This single database handles both IPv4 and IPv6
  23. 23.`
  24. 24.Test rules before production:
  25. 25.```bash
  26. 26.# Test configuration
  27. 27.mlogc /etc/modsecurity/modsecurity.conf
  28. 28.# Or use ModSecurity audit mode first
  29. 29.SecRuleEngine DetectionOnly
  30. 30.`
  31. 31.Document blocked countries:
  32. 32.```bash
  33. 33.# Create documentation
  34. 34.cat > /etc/modsecurity/GEO-BLOCK-README << 'EOF'
  35. 35.Blocked Countries: CN, RU, KP, IR
  36. 36.Reason: Compliance and security policy
  37. 37.Last Updated: 2024-12-12
  38. 38.Next Review: 2025-03-12
  39. 39.EOF
  40. 40.`
  41. 41.Handle exceptions properly:
  42. 42.```apache
  43. 43.# Exception for specific paths or IPs
  44. 44.SecRule REQUEST_URI "^/api/webhook" "phase:1,allow,id:99999"
  45. 45.`
  46. 46.Regular testing schedule:
  47. 47.```bash
  48. 48.# Weekly geo-block test script
  49. 49.#!/bin/bash
  50. 50.BLOCKED_IPS="202.96.128.86 77.88.55.55"
  51. 51.for ip in $BLOCKED_IPS; do
  52. 52.status=$(curl -s -o /dev/null -w "%{http_code}" -H "X-Forwarded-For: $ip" https://yourdomain.com/)
  53. 53.if [ "$status" != "403" ]; then
  54. 54.echo "ALERT: IP $ip not blocked (status: $status)"
  55. 55.fi
  56. 56.done
  57. 57.`
  • [Technical troubleshooting: Fix Certificate Chain Incomplete SSL Validation Is](certificate-chain-incomplete-ssl-validation)
  • [Fix Ddos Attack Mitigation Waf Rate Limiting Issue in Network Security](ddos-attack-mitigation-waf-rate-limiting)
  • [Fix DNS Hijacking Spoofing Attack Issue in Network Security](dns-hijacking-spoofing-attack)
  • [Fix firewall iptables rules not persisting across reboot Issue in Network-Security](firewall-iptables-rules-not-persisting-across-reboot)
  • [Fix firewall rule blocking legitimate traffic Issue in Network-Security](firewall-rule-blocking-legitimate-traffic)

<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "TechArticle", "headline": "WAF Geoblock Not Filtering", "description": "Fix WAF geo-blocking not working. Configure GeoIP rules, update databases, and verify country-based access control.", "url": "https://www.fixwikihub.com/fix-security-waf-geoblock-not-filtering", "publisher": { "@type": "Organization", "name": "FixWikiHub", "url": "https://www.fixwikihub.com" }, "author": { "@type": "Person", "name": "FixWikiHub Editorial Team" }, "datePublished": "2025-12-12T17:36:23.752Z", "dateModified": "2025-12-12T17:36:23.752Z" } </script>