← News
/PLAYBOOK · 2026-09-02

GeoIP Geo-Restriction in Practice: Blocking Overseas Malicious Traffic with Nginx

Nginx GeoIP geo-restriction in practice: country-level blocking of overseas malicious traffic with GeoLite2. Covers module install, real-IP restoration behind CDN, automatic DB updates, and search-engine crawler false positives.

GeoIP geo-restriction uses IP geolocation data for access control at the edge. For services that only serve domestic users, most overseas traffic is scanners and automated attack tools. Country-level blocking with the Nginx GeoIP module drops large volumes of malicious traffic before it reaches the application. This article gives a complete configuration based on the MaxMind GeoLite2 database.

Applicable Scenarios

Prerequisites

Check whether the module is compiled in or loaded:

nginx -V 2>&1 | tr ' ' '\n' | grep -i geoip

How It Works

On request parse, the GeoIP module matches the client IP against a local IP geolocation database (mmdb), obtains a country code, then uses a `map` directive to produce an allow/deny variable. An `if` or `location` returns 403 or proxies normally. The entire process stays inside Nginx—no outbound lookups, negligible overhead.

Two critical points: the database must be updated regularly; IP-block assignments change over time and stale data causes misclassification. Behind a CDN you must restore the real client IP first, otherwise you geolocate the CDN node. A domestic CDN makes the rule completely ineffective.

Procedure

1. Install the GeoIP2 Module and Database

# Debian/Ubuntu (when using distro nginx)
apt install -y libnginx-mod-http-geoip2

# Download the free IP geolocation database
mkdir -p /etc/nginx/geoip
cd /etc/nginx/geoip
wget https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-Country.mmdb

2. Configure Country Lookup and Allow Rules

In the `http` block of `/etc/nginx/nginx.conf`, add:

geoip2 /etc/nginx/geoip/GeoLite2-Country.mmdb {
    $geoip2_country_code country/iso_code;
}

map $geoip2_country_code $allowed_country {
    default 0;    # deny by default
    CN 1;         # allow mainland China IPs only
}

To allow Hong Kong users, add a line `HK 1;`.

3. Apply Blocking on the Site

Site-wide block (add in the `server` block):

if ($allowed_country = 0) {
    return 403;
}

Safer approach: restrict only sensitive paths such as admin, leaving public pages open to overseas search engines:

location /admin {
    if ($allowed_country = 0) {
        return 403;
    }
    proxy_pass http://backend;
}

4. Restore Real IP Behind CDN/Reverse Proxy

If a CDN sits in front of the site, configure `real_ip` in the `http` block so the CDN origin X-Forwarded-For is restored to the real client IP (CDN CIDRs per vendor docs):

set_real_ip_from 0.0.0.0/0;        # in production, replace with the CDN vendor's official CIDR list
real_ip_header X-Forwarded-For;
real_ip_recursive on;

5. Automatic Database Updates

Create `/etc/cron.weekly/update-geoip` to update the database weekly and reload Nginx:

#!/bin/bash
cd /etc/nginx/geoip
wget -q https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-Country.mmdb -O GeoLite2-Country.mmdb.new \
  && mv GeoLite2-Country.mmdb.new GeoLite2-Country.mmdb \
  && nginx -s reload

Permissions: `chmod +x /etc/cron.weekly/update-geoip`

Verification

Temporarily emit the country code from a test location to confirm lookup:

location /geo_test {
    return 200 "$geoip2_country_code\n";
}

After reload, visit `https://helixcyber.ai/geo_test`. A domestic IP should return `CN`. Delete the location after verification.

Then verify blocking: access a restricted path from an overseas VPS (or have an overseas contact do it). Expect 403 Forbidden; domestic access should return the page normally. Check access logs to confirm the country code is recorded:

log_format main '$remote_addr - $geoip2_country_code $request $status';
tail -f /var/log/nginx/access.log

FAQ

FAQ 1: Blocking does not take effect behind a CDN?

This is the most common issue: Nginx sees the CDN node IP. A domestic CDN is classified as CN and allowed. You must configure `set_real_ip_from` per step 4, and the CIDR list must strictly match the CDN vendor's origin ranges. Otherwise an attacker can spoof the X-Forwarded-For header and bypass geo-restriction.

FAQ 2: False-positive blocks of legitimate overseas users or search-engine crawlers?

Google and Bing crawlers mostly come from overseas IPs. Site-wide blocking hurts indexing. Pick one: ① enable geo-restriction only on admin, API, and other sensitive paths, leave public pages open; ② allow major search-engine crawler UAs before the deny rule (UA is spoofable—SEO fallback only, never allow login endpoints). Also, the free GeoLite2 database is imprecise on some IP blocks; when false positives occur, first check the database update time.

Summary

GeoIP geo-restriction is a low-cost way to shrink attack surface. Three configuration keys: real-IP restoration determines whether the rule actually works; automatic database updates determine the false-positive rate; path-level granularity determines impact on the business and SEO. It is coarse-grained protection. Combine it with UA blacklists and rate limiting for layered edge defense.