FreeBSD is Fun

Practical recipes for FreeBSD

Geolocating users in nginx

Posted

by

Category

I know, I know… why not just use Cloudflare? Except, there is cases where you can’t; or not the free version anyway.

One such case I experienced recently happened when I needed to fetch the user’s IP for an application which only supports IPv4. Turns out, that the free Cloudflare account doesn’t have the option of forcing a particular protocol, so I ended up with useless IPv6 addresses. Thus, I had to remove Cloudflare from my site. My site routes users to different pages based on their country, a task made simple by Cloudflare which sends an optional country header if you enable this option in the Network tab:

Cloudflare IP Geolocation Setting

Without Cloudflare, I had to find a way to do nginx geolocation in FreeBSD by myself.

Now diving into the topic of country-level geolocation (let’s ignore the city, longitude and latitude which in my experience are way too unaccurate to be of any use) it’s important to know some things first.

The translation of a given IP into a country is not a permanent, immutable thing. IP blocks constantly get transferred between organizations residing in different countries, thus changing their so-called location. This creates a need for up-to-date databases called geoip databases, which are often sold as subscriptions. Fortunately, there are free versions we can use if the accuracy of the data is not critical (or we simply don’t have money the money to spare.)

Armed with this knowledge, we will create an account in one of such providers, MaxMind, which offers a free version of their ip2country database alongside their premium and allegedly more accurate premium products.

https://www.maxmind.com/en/geolite2/signup

Once we are signed up, we will click on Manage License Keys and then Create a new key, a step which is necessary in order to update our database automatically. We will also be offered pre filled a configuration file for our server, which we will download.

Now it’s FreeBSD fun time. You probably installed your nginx from packages as most people do these days, but this time we need to reinstall it and compile it with different options.

portsnap auto
cd /usr/ports/www/nginx
make config reinstall clean

When presented with the list of optional modules, we will choose HTTP_GEOIP and leave the rest as it is.

After FreeBSD is done compiling nginx, we will edit /usr/local/etc/nginx/nginx.conf to load this module from the main context – that is, after the user and worker_processes lines, if we have a typical nginx.conf file

load_module /usr/local/libexec/nginx/ngx_stream_module.so;
load_module /usr/local/libexec/nginx/ngx_stream_geoip2_module.so;
load_module /usr/local/libexec/nginx/ngx_http_geoip2_module.so;

Now it’s time to install the geoip package to automatically download the latest geoip database:

pkg install geoipupdate

Now replace /usr/local/etc/GeoIP.conf with the contents of the configuration file we downloaded earlier from MaxMind.

Finally, let’s put our newly acquired capabilities to work. Here’s an example of the http context settings, setting up a flag ($alt_country) for users from Turkey, Hungary and Portugal. A full list of country codes can be found here.

    geoip2 /usr/local/share/GeoIP/GeoLite2-Country.mmdb {
        $geoip2_data_country_iso_code country iso_code;
    }

    map $geoip2_data_country_iso_code $alt_country {
        default no;
        TR yes;
        PT yes;
        HU yes;
    }

Later on in the server location, I use this flag to direct users from these countries to a special site:

location / {

    if ($alt_country = yes) {
        return 301 https://anothersite.com$request_uri;
    }

}

Not feeling confident? You can always hire me to perform this or any other of the administrative tasks described in this blog.


Leave a Reply

Your email address will not be published. Required fields are marked *