Nginx

Upgrade to GeoIP2 with nginx on CentOS / RHEL 7

by ,


We have by far the largest RPM repository with dynamic stable NGINX modules and VMODs for Varnish 4.1 and 6.0 LTS. If you want to install nginx, Varnish and lots of useful modules for them, this is your one stop repository to get all performance related software.
You have to maintain an active subscription in order to be able to use the repository!

GeoLite Legacy databases are discontinued as of January 2, 2019. They are not updated nor any longer available for download. Every user should move to GeoLite2 databases, a more contemporary version of the GeoLite Legacy geolocation databases which are still available in a free version updated every month.

I’ve recently added the GeoIP2 module to nginx extras repository for CentOS 6 and 7 to easily migrate from GeoIP to GeoIP2. By using nginx-module-geoip2 package, only a couple of lines in NGINX configuration file are needed to configure the module.

GeoIP2 module installation

If you haven’t used our repository in the past, add up the release package for it first.

For CentOS / RHEL 6, run: yum -y install https://extras.getpagespeed.com/release-el6-latest.rpm
For CentOS / RHEL 7, run: yum -y install https://extras.getpagespeed.com/release-el7-latest.rpm

Now, to install NGINX and the GeoIP2 module, you would run:

yum install nginx nginx-module-geoip2

Then add the following at the top of your /etc/nginx/nginx.conf:

load_module modules/ngx_http_geoip2_module.so;

If your NGINX was running, reload it to pick up on the newly added module via service nginx reload.
Otherwise, run NGINX service via service nginx start.

GeoIP2 configuration

First, you need to get a hold of the latest MaxMind GeoLite2 country/city free databases.
Life is so easy when you use our repository, eh? We provide the geoipupdate program that is capable of fetching those databases.

Run:

yum install geoipupdate geoipupdate-cron

Then, make sure that /etc/GeoIP.conf specifies these in order to use free databases:

AccountID 0
LicenseKey 000000000000

If you’re using commercial databases, you will adjust those settings appropriately.

Now you can fetch the databases by running geoipupdate without arguments, once. The geoipupdate will download GeoLite2-City.mmdb and GeoLite2-Country.mmdb over to /usr/share/GeoIP/ directory.

The weekly cron that was installed will take care of continuous updates of database files.

Tip: you can query IP geolocation using command line by installing libmaxminddb-devel package then running geolookups like this:

mmdblookup --file /usr/share/GeoIP/GeoLite2-Country.mmdb --ip 8.8.8.8 country names en

Now it’s time to tell NGINX about our GeoIP databases. In nginx.conf, preferably in the http { ... } section:

http {
    ...
    geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
        auto_reload 5m;
        $geoip2_metadata_country_build metadata build_epoch;
        # $geoip2_data_country_code default=US source=$variable_with_ip country iso_code;
        $geoip2_data_country_code default=US country iso_code;
        $geoip2_data_country_name country names en;
    }

    geoip2 /usr/share/GeoIP/GeoLite2-City.mmdb {
        $geoip2_data_city_name default=London city names en;
    }
    ....

    fastcgi_param COUNTRY_CODE $geoip2_data_country_code;
    fastcgi_param COUNTRY_NAME $geoip2_data_country_name;
    fastcgi_param CITY_NAME    $geoip2_data_city_name;
    ....
}

Testing GeoIP2 country and city fetching

The easiest way to confirm that nginx is fetching all GeoIP information is using a temporary header on any server { }. Using Headers-More module to avoid common configuration pitfalls:

more_set_headers "X-Country: $geoip2_data_country_name";

If you’re not using Headers-More module already, stick to standard directive:

add_header X-Country $geoip2_data_country_name;

Then check headers via curl -IL https://your.example.com/. This should yield, among other headers:

x-country: Your Country Name

Block countries from accessing your website

Now that GeoIP2 module is confirmed to work, we can restrict a vhost to specific countries. Let’s restrict public directory of this vhost to only visitors from Canada and USA:

map $geoip2_data_country_code $allowed_country {
  default no;
  CA yes;
  US yes;
}
location / {
  if ($allowed_country = no) {
    return 403;
  }
}

Display country ID in nginx access_log

It can be useful for debugging or monitoring to see country code of each visitor in nginx access_log. Simply add $geoip2_data_country_code in your nginx log_format:

log_format main
'$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'$request_time $upstream_response_time $pipe '
'$geoip2_data_country_code';

Literature:

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.