A short guide on how to geo block your webpage with nginx.

Installation

If you are using the letsencrypt container the nginx module is already installed. If not you can take a look at the howtoforge guide.

That said the container doesn’t come with the GeoIP database.

1. Download the database and place it in your letsencrypt appdata location e.g /appdata/letsencrypt/geoip/GeoIPv6.dat I added a folder called geoip and placed the file there.

Note: The IPv6 database will also block IPv4!

Note2: If you use Cloudflare you have to use the IPv6 database, or you will get random 520 errors!

NGINX

2. In your nginx.conf file add the following after http {

http {

geoip_country /config/geoip/GeoIPv6.dat;

# LOCAL IP ALLOW GEO BLOCK
    geo $lan-ip {
    default no;
    192.168.1.0/24 yes;
    }
# GEO IP BLOCK SITE 1
    map $geoip_country_code $allowed_country {
    default no;
    YOUR-COUNTRY-CODE yes; # e.g <US> for United States 
    }

Instead of "YOUR-COUNTRY-CODE" add your own country code from this list. This will block all other countries than the one you choose.

The geo $lan-ipis for allowing you to access the domain on your LAN. Check out http://jodies.de/ipcalc if you are wondering what your netmask is.   – Thanks dropbearninja

Note: The geo $lan-ip part is only needed if you set default to no

For it to actually block you need to add this in your server block:

 # LOCAL IP ALLOW GEO BLOCK
    if ($lan-ip = yes) {
    set $allowed_country yes;
    }
    
# COUNTRY GEO BLOCK 
    if ($allowed_country = no) {
    return 444;
    }

3. If you host several websites and want a different country block just add another with a different variable ($allowed_country2):

As defaultis set to yes it will allow every country except the country codes set to no

 # GEO IP BLOCK DOMAIN 2
  map $geoip_country_code $allowed_country2 {
   default yes;
    CN no; #China
    RU no; #Russia
    HK no; #Hong Kong
    IN no; #India
    IR no; #Iran
    VN no; #Vietnam
    TR no; #Turkey
    EG no; #Egypt
    MX no; #Mexico
    JP no; #Japan
    KR no; #South Korea
    KP no; #North Korea 🙂
    PE no; #Peru
    BR no; #Brazil
    UA no; #Ukraine
    ID no; #Indonesia
    TH no; #Thailand
 }

I made this list based on the Spamhaus statistics and Aakamai’s state of the internet report.

Then add this in your other server block

#COUNTRY GEO BLOCK
    if ($allowed_country2 = no) {
    return 444;
}

Blocked

You can test if it worked with a VPN or do a performance test from a location that is blocked here https://www.webpagetest.org/

TIP! This database does get updated!

By using the User Scripts plugin you can easily set up a cronjob every week.
Click on Add New Script → Enter the name → Click on the name of the script and then Edit Script

Copy the script and set your download path. (Thank you Tronyx for the script!)

#!/usr/bin/env bash

wget -O /tmp/GeoIPv6.dat.gz http://geolite.maxmind.com/download/geoip/database/GeoIPv6.dat.gz

gunzip /tmp/GeoIPv6.dat.gz

mv /tmp/GeoIPv6.dat /mnt/cache/appdata/letsencrypt/geoip/GeoIPv6.dat

chown 911:911 /mnt/cache/appdata/letsencrypt/geoip/GeoIPv6.dat

Set the schedule to custom and add 00 00 * * 1 for it to run every monday at 00:00

Click Run In Background and then Apply

Souce:

https://dev.maxmind.com/geoip/legacy/install/country/
http://dev.maxmind.com/geoip/legacy/codes/iso3166/
https://www.howtoforge.com/nginx-how-to-block-visitors-by-country-with-the-geoip-module-debian-ubuntu
https://www.spamhaus.org/statistics/botnet-cc/
https://www.akamai.com/us/en/multimedia/documents/state-of-the-internet/q3-2017-state-of-the-internet-security-report.pdf