How to manually set up GeoIP geolocation using MaxMind and without using a package manager

GeoIP is the process of determining a geographic location of a requestor based on an IP address.

On many Linux systems, like Centos, Debian or Ubuntu, you can install an Apache mod called mod_geoip, which you can then use either within your Apache stanza config, .htaccess or within PHP by calling a function with the IP as an argument.

In this tutorial, I will briefly show you how to set up GeoIP using MaxMind Reader and GeoLite2 Free Geolocation Data.

You will need two things:

  • The MaxMind Reader class, which is free to download and available from here. You can download the whole project as a Zip file. If you’re on the command-line, you can right-click on the green link to grab the URL. At the time of writing, it was here.
  • The GeoLiteIP database from MaxMind. GeoLite2 Database is located here, and is free. Unfortunately, you will need to register first to download it. The download page is here, and in this example we’ll use the ‘GeoLite2 Country’ binary database which has the file extension .mmdb

Download the MaxMind project folder and put it in a subfolder of the PHP page from which it will be needed. Let’s say we have an index.php page which is at the document root, which has the path /var/www/public_html/mywebsite/index.php. Your unzipped folder of MaxMind will be named: MaxMind-DB-Reader-php-main. Rename it ‘MaxMind’.

Inside the MaxMind project folder should be a file called ‘autoload.php’ and a subfolder named ‘src’.

Next, download the GeoLite2 .mmdb Country database. By convention, this should go in the: /usr/share/GeoIP/ folder or subfolder, but you can put it wherever you like.

We can now add some code to our index.php page to use the MaxMind libraries and perform a GeoIP lookup.

First, load the autoloader in the MaxMind folder. Next you need the ‘use‘ keyword to use to declare the namespace. Third, create a variable pointing to the MaxMind database you just downloaded. Finally, instantiate a reader of the MaxMind Reader class:

require('MaxMind/autoload.php');
use MaxMind\Db\Reader;
$databaseFile = "/usr/share/GeoIP/GeoLite2-Country.mmdb";
$reader = new Reader($databaseFile);

Once you’ve done those four things, you’re ready to look up the geo-location of an IP.

If you want to test for a proxy IP (HTTP_X_FORWARDED_FOR), then I suggest you use the following code:

if (getenv('HTTP_X_FORWARDED_FOR')) {
        $pipaddress = getenv('HTTP_X_FORWARDED_FOR');
        $ipaddress = getenv('REMOTE_ADDR');
        //echo "Your Proxy IP address is : ".$pipaddress." (via $ipaddress)";
} else {
        $ipaddress = getenv('REMOTE_ADDR');
        //echo "Your IP address is : $ipaddress";
}

After that, you can call the reader class to do a lookup:

if (isset($pipaddress)) {
        $geoip_array = $reader->get($pipaddress);
} else {
        $geoip_array = $reader->get($ipaddress);
}

The reader class will return an array of different information you can use. Here is an example of a print_r statement on the $geoip_array variable on a test page accessed by a Tor Browser:

Array
(
    [continent] => Array
        (
            [code] => EU
            [geoname_id] => 6255148
            [names] => Array
                (
                    [de] => Europa
                    [en] => Europe
                    [es] => Europa
                    [fr] => Europe
                    [ja] => ヨーロッパ
                    [pt-BR] => Europa
                    [ru] => Европа
                    [zh-CN] => 欧洲
                )

        )

    [country] => Array
        (
            [geoname_id] => 2750405
            [is_in_european_union] => 1
            [iso_code] => NL
            [names] => Array
                (
                    [de] => Niederlande
                    [en] => Netherlands
                    [es] => Holanda
                    [fr] => Pays-Bas
                    [ja] => オランダ王国
                    [pt-BR] => Holanda
                    [ru] => Нидерланды
                    [zh-CN] => 荷兰
                )

        )

    [registered_country] => Array
        (
            [geoname_id] => 2750405
            [is_in_european_union] => 1
            [iso_code] => NL
            [names] => Array
                (
                    [de] => Niederlande
                    [en] => Netherlands
                    [es] => Holanda
                    [fr] => Pays-Bas
                    [ja] => オランダ王国
                    [pt-BR] => Holanda
                    [ru] => Нидерланды
                    [zh-CN] => 荷兰
                )

        )

    [traits] => Array
        (
            [is_anonymous_proxy] => 1
        )

)

If you just want the Country ISO code, for example, you can use the code:

$geo_location = $geoip_array['country']['iso_code'];