Globalization has made cyberattacks much easier 🙁 unfortunately. As a result, you may not want certain countries to visit your site if you mainly get malicious traffic from specific countries that overload your server and slow it down. In this tutorial we will be configuring nginx to use the latest GeoIP database and blocking a custom list of countries, continents or both from accessing your site using MaxMind GeoIP databases.
nginx GeoIP Database Installation Ubuntu 18.04
This tutorial assumes you already have nginx-extras
installed on your system and have root access.
Install the necessary GeoIP database, GeoIP library and nginx GeoIP module
sudo apt-get install geoip-database-extra libgeoip1 libnginx-mod-http-geoip -y
After installing these packages we can update the MaxMind GeoIP databases to be the latest GeoIP2 data packaged in the GeoIP database format – thanks to Miyuru who keeps them updated. This is especially convenient because currently if you want to use the official GeoIP2 databases you would need to recompile nginx which can be quite the hassle.
cd /usr/share/GeoIP
mv GeoIP.dat GeoIP.dat.bak
wget https://dl.miyuru.lk/geoip/maxmind/country/maxmind.dat.gz
gunzip maxmind.dat.gz
mv maxmind.dat GeoIP.dat
mv GeoIPCity.dat GeoIPCity.dat.bak
wget https://dl.miyuru.lk/geoip/maxmind/city/maxmind.dat.gz
gunzip maxmind.dat.gz
mv maxmind.dat GeoIPCity.dat
To tell nginx where the GeoIP databases are located you need to add these lines into /etc/nginx/nginx.conf
in your http {
block
geoip_country /usr/share/GeoIP/GeoIP.dat;
geoip_city /usr/share/GeoIP/GeoIPCity.dat;
I put it at the top here
#WP-Bullet.com nginx configuration
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
multi_accept on;
}
http {
# GeoIP databases
geoip_country /usr/share/GeoIP/GeoIP.dat;
geoip_city /usr/share/GeoIP/GeoIPCity.dat;
...
Now we can block some countries and continents 😀
Blocking Countries by GeoIP Detection in nginx
The first thing we are going to do is make a list of the countries to block, you can put this in your http {
block.
The full list of MaxMind GeoIP country codes in 2 letter format can be found here
# map the list of denied countries
map $geoip_country_code $allowed_country {
default yes;
# Pakistan
PK no;
# Ukraine
UA no;
# Russia
RU no;
# China
CN no;
}
Now we can block the country with this if statement
# block the country
if ($allowed_country = no) {
return 444;
}
If you want to add a custom HTTP header to show the country you can do so with this snippet in the nginx server block.
add_header X-Country $geoip_country_code;
Now let’s block some continents!
Blocking Continents by GeoIP Detection in nginx
The logic for blocking continents is very similar, for this however we need to use the GeoIP city database.
You can find a list of the countries and the continents to which they belong here.
Full list of MaxMind GeoIP Continents in 2 letter code:
AF
AN
AS
EU
NA
OC
SA
Here is the MaxMind GeoIP continent list with 2 letter country code mapped to the full continent name
AF - Africa
AN - Antarctica
AS - Asia
EU - Europe
NA - North America
OC - Oceania
SA - South America
We can use the same nginx map command logic for blocking continents!
# map the continents to block
map $geoip_city_continent_code $allowed_continent {
default yes;
# Antarctica
AN no;
# Asia
AS no;
}
In your server block you can add this if statement to block the continents via GeoIP for your custom continent block list.
# block the continents
if ($allowed_continent = no) {
return 444;
}
If you want to add a custom nginx header showing the continent you can add this snippet in your server block
add_header X-Continent $geoip_city_continent_code;
As usual after you finish making any of these modifications you should test your nginx configuration
nginx -t
If the syntax is OK then reload nginx
service nginx reload
This is only the beginning of the possibilities with GeoIP detection with nginx using the GeoIP databases from MaxMind!
You can try playing with redirecting based on GeoIP as well and caching based on Geolocation.
Sources
Blocking Visitors from a Country nginx
nginx GeoIP module Documentation
Hello
Is it recommended to regularly update the database by downloading ?https://dl.miyuru.lk/geoip/maxmind/country/maxmind.dat.gz ?
Thank you
Good idea! You can set a cronjob to do this quite easily every month or so. I’m not sure how often this database does get updated though. You will probably need to make sure nginx reloads after you update the database as well.
thank you very much, I’ll make myself a little script ^^
When i block US or RU, then how to exclude google and yandex bot from accessing my site?
Good question! You would have to map the user agent to a variable and then allow based on that. You may need to use some conditional logic for this as well like https://gist.github.com/jrom/1760790
Hello
I wanted to block certain cities, since it passes the country block.
so I put that in the nginx.conf file:
map $geoip_city_code $allowed_city {
default yes;
# Singapore
SG no;
}
when I type nginx -t
I got this message:
nginx: [emerg] unknown “geoip_city_code” variable
nginx: configuration file /etc/nginx/nginx.conf test failed
Do you have any ideas? 🙂
Currently, I have this in the nginx.conf file
# GeoIP databases
geoip_country /usr/share/GeoIP/GeoIP.dat;
geoip_city /usr/share/GeoIP/GeoIPCity.dat;
# map the list of denied countries
map $geoip_country_code $allowed_country {
default yes;
# Pakistan
PK no;
# Ukraine
UA no;
# Russia
RU no;
# China
CN no;
}
map $geoip_city_code $allowed_city {
default yes;
# Singapore
SG no;
}
Hello again! Wrong variable, allowed variables can be found here http://nginx.org/en/docs/http/ngx_http_geoip_module.html looks like $geoip_city would do it!
I’ve had this working on my previous server, now trying to set it up on a new server which should be more or less alike the old server. However, I’m getting:
nginx: [emerg] unknown directive “geoip_country” in /etc/nginx/nginx.conf:37
nginx: configuration file /etc/nginx/nginx.conf test failed
any idea what’s causing this?
Any help or pointers are much appreciated 🙂
Sounds like nginx is not compiled with the geoip module. If you are on Ubuntu then be sure to install the nginx-extras package
I can see I have –with-http_geoip_module=dynamic installed. Is there another one I need?
I installed the nginx extras package, that added –add-dynamic-module=/build/nginx-4jYSyN/nginx-1.16.1/debian/modules/http-geoip2 but didn’t change anything unfortunately
I solved it by added load_module “modules/ngx_http_geoip_module.so”; in the main part of nginx.conf