There is a new version of this tutorial available for Ubuntu 16.04 (Xenial Xerus).

Using GeoIP With Nginx On Ubuntu 12.04

Version 1.0
Author: Falko Timme
Follow me on Twitter

This tutorial explains how to use the GeoIP module with nginx on Ubuntu 12.04 to find out where your visitors come from. The GeoIP module sets multiple variables like $geoip_country_name, $geoip_country_code, $geoip_city, etc. that you can use in your PHP scripts or directly in your nginx configuration, for example to serve content in different languages based on the user's country.

I do not issue any guarantee that this will work for you!

 

1 Preliminary Note

I'm using the website www.example.com here with the document root /var/www/www.example.com/web/ and the Nginx vhost configuration file /etc/nginx/sites-enabled/www.example.com.vhost.

A note for Ubuntu users:

Because we must run all the steps from this tutorial with root privileges, we can either prepend all commands in this tutorial with the string sudo, or we become root right now by typing

sudo su

 

2 Find Out If Nginx Has Support For GeoIP

Before we start we must find out if the GeoIP module is built into our nginx server:

nginx -V
root@server1:~# nginx -V
nginx version: nginx/1.1.19
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-log-path=/var/log/nginx/access.log --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --lock-path=/var/lock/nginx.lock --pid-path=/var/run/nginx.pid --with-debug --with-http_addition_module --with-http_dav_module --with-http_geoip_module --with-http_gzip_static_module --with-http_image_filter_module --with-http_realip_module --with-http_stub_status_module --with-http_ssl_module --with-http_sub_module --with-http_xslt_module --with-ipv6 --with-sha1=/usr/include/openssl --with-md5=/usr/include/openssl --with-mail --with-mail_ssl_module --add-module=/build/buildd/nginx-1.1.19/debian/modules/nginx-auth-pam --add-module=/build/buildd/nginx-1.1.19/debian/modules/nginx-echo --add-module=/build/buildd/nginx-1.1.19/debian/modules/nginx-upstream-fair --add-module=/build/buildd/nginx-1.1.19/debian/modules/nginx-dav-ext-module
root@server1:~#

 

3 Download The GeoIP Databases

On Debian and Ubuntu, there is the package geoip-database that can be installed through apt, but it is a bit outdated and only contains GeoIP.dat (country database), not GeoLiteCity.dat (city database). Therefore we don't install that package, but download fresh copies from the GeoIP web site to the /etc/nginx/geoip directory:

mkdir /etc/nginx/geoip
cd /etc/nginx/geoip
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
gunzip GeoIP.dat.gz
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
gunzip GeoLiteCity.dat.gz

 

4 Configure Nginx

Now we configure nginx. Open /etc/nginx/nginx.conf...

vi /etc/nginx/nginx.conf

... and add the geoip_country and geoip_city directives to the http {} container:

[...]
http {
        geoip_country  /etc/nginx/geoip/GeoIP.dat; # the country IP database
        geoip_city     /etc/nginx/geoip/GeoLiteCity.dat; # the city IP database
[...]

The geoip_country directive makes the following variables available:

  • $geoip_country_code - two-letter country code, for example, RU, US.
  • $geoip_country_code3 - three-letter country code, for example, RUS, USA.
  • $geoip_country_name - the (verbose) name of the country, for example, Russian Federation, United States, etc.

The geoip_city directive provides the following variables:

  • $geoip_city_country_code - two-letter country code, for example, RU, US.
  • $geoip_city_country_code3 - three-letter country code, for example, RUS, USA.
  • $geoip_city_country_name - the name of the country, for example, Russian Federation, United States - if available.
  • $geoip_region - the name of region (province, region, state, province, federal land, and the like), for example, Moscow City, DC - if available.
  • $geoip_city - the name of the city, for example, Moscow, Washington, Lisbon, etc. - if available.
  • $geoip_postal_code - zip code or postal code - if available.
  • $geoip_city_continent_code - if available.
  • $geoip_latitude - latitude - if available.
  • $geoip_longitude - longitude - if available.

In order to make these variables available to your PHP scripts as well, we must set a few fastcgi_param directives. It is best to do this in the file /etc/nginx/fastcgi_params where the other fastcgi_param directives are:

vi /etc/nginx/fastcgi_params
[...]
### SET GEOIP Variables ###
fastcgi_param GEOIP_COUNTRY_CODE $geoip_country_code;
fastcgi_param GEOIP_COUNTRY_CODE3 $geoip_country_code3;
fastcgi_param GEOIP_COUNTRY_NAME $geoip_country_name;

fastcgi_param GEOIP_CITY_COUNTRY_CODE $geoip_city_country_code;
fastcgi_param GEOIP_CITY_COUNTRY_CODE3 $geoip_city_country_code3;
fastcgi_param GEOIP_CITY_COUNTRY_NAME $geoip_city_country_name;
fastcgi_param GEOIP_REGION $geoip_region;
fastcgi_param GEOIP_CITY $geoip_city;
fastcgi_param GEOIP_POSTAL_CODE $geoip_postal_code;
fastcgi_param GEOIP_CITY_CONTINENT_CODE $geoip_city_continent_code;
fastcgi_param GEOIP_LATITUDE $geoip_latitude;
fastcgi_param GEOIP_LONGITUDE $geoip_longitude;

(Make sure you have the line include /etc/nginx/fastcgi_params; in your location ~ \.php$ {} container in your vhost configuration, because otherwise the above configuration is useless for your vhost.)

If you use nginx as a reverse proxy and want to pass the GeoIP variables to the backend, you should create/edit the file /etc/nginx/proxy.conf...

vi /etc/nginx/proxy.conf

... and add the following lines to it:

[...]
### SET GEOIP Variables ###
proxy_set_header GEOIP_COUNTRY_CODE $geoip_country_code;
proxy_set_header GEOIP_COUNTRY_CODE3 $geoip_country_code3;
proxy_set_header GEOIP_COUNTRY_NAME $geoip_country_name;

proxy_set_header GEOIP_CITY_COUNTRY_CODE $geoip_city_country_code;
proxy_set_header GEOIP_CITY_COUNTRY_CODE3 $geoip_city_country_code3;
proxy_set_header GEOIP_CITY_COUNTRY_NAME $geoip_city_country_name;
proxy_set_header GEOIP_REGION $geoip_region;
proxy_set_header GEOIP_CITY $geoip_city;
proxy_set_header GEOIP_POSTAL_CODE $geoip_postal_code;
proxy_set_header GEOIP_CITY_CONTINENT_CODE $geoip_city_continent_code;
proxy_set_header GEOIP_LATITUDE $geoip_latitude;
proxy_set_header GEOIP_LONGITUDE $geoip_longitude;

(Make sure you use the line include /etc/nginx/proxy.conf; in your nginx proxy configuration because otherwise the backend cannot use the GeoIP variables.)

Now reload nginx...

/etc/init.d/nginx reload

... for the changes to take effect.

Restart PHP-FPM as follows:

/etc/init.d/php5-fpm restart

 

5 A Short Test

To see if the GeoIP module is working correctly, we can create a small PHP file in our www.example.com web space (e.g. /var/www/www.example.com/web):

vi /var/www/www.example.com/web/geoiptest.php

We can access the GeoIP variables as follows:

$geoip_country_code = getenv(GEOIP_COUNTRY_CODE);

Or like this:

$geoip_country_code = $_SERVER['GEOIP_COUNTRY_CODE'];
<html>
<body>
<?php

$geoip_country_code = getenv(GEOIP_COUNTRY_CODE);
/*
$geoip_country_code = $_SERVER['GEOIP_COUNTRY_CODE']; // works as well
*/
$geoip_country_code3 = getenv(GEOIP_COUNTRY_CODE3);
$geoip_country_name = getenv(GEOIP_COUNTRY_NAME);

$geoip_city_country_code = getenv(GEOIP_CITY_COUNTRY_CODE);
$geoip_city_country_code3 = getenv(GEOIP_CITY_COUNTRY_CODE3);
$geoip_city_country_name = getenv(GEOIP_CITY_COUNTRY_NAME);
$geoip_region = getenv(GEOIP_REGION);
$geoip_city = getenv(GEOIP_CITY);
$geoip_postal_code = getenv(GEOIP_POSTAL_CODE);
$geoip_city_continent_code = getenv(GEOIP_CITY_CONTINENT_CODE);
$geoip_latitude = getenv(GEOIP_LATITUDE);
$geoip_longitude = getenv(GEOIP_LONGITUDE);

echo 'country_code: '.$geoip_country_code.'<br>';
echo 'country_code3: '.$geoip_country_code3.'<br>';
echo 'country_name: '.$geoip_country_name.'<br>';

echo 'city_country_code: '.$geoip_city_country_code.'<br>';
echo 'city_country_code3: '.$geoip_city_country_code3.'<br>';
echo 'city_country_name: '.$geoip_city_country_name.'<br>';
echo 'region: '.$geoip_region.'<br>';
echo 'city: '.$geoip_city.'<br>';
echo 'postal_code: '.$geoip_postal_code.'<br>';
echo 'city_continent_code: '.$geoip_city_continent_code.'<br>';
echo 'latitude: '.$geoip_latitude.'<br>';
echo 'longitude: '.$geoip_longitude.'<br>';

?>
</body>
</html>

Call that file in a browser (http://www.example.com/geoiptest.php), and you should see GeoIP at work (make sure that you're calling the file from a public IP address, not a local one):

It is also possible to use GeoIP varibles directly in the nginx configuration, e.g. as follows:

vi /etc/nginx/sites-enabled/www.example.com.vhost
[...]
        location / {
            index index.html index.php;
            try_files /index_$geoip_country_code.html /index.html;
        }
[...]
/etc/init.d/nginx reload

In this example, if a visitor comes from Germany (country code: DE), and the file index_DE.html exists, then this file is served, otherwise the default index.html file is served:

This can be used to serve content in different languages, based on the user's origin.

 

 

About The Author

Falko Timme is the owner of Boost Your Site mit Timme Hosting - ultra-schnelles nginx-WebhostingTimme Hosting (ultra-fast nginx web hosting). He is the lead maintainer of HowtoForge (since 2005) and one of the core developers of ISPConfig (since 2000). He has also contributed to the O'Reilly book "Linux System Administration".

Share this page:

4 Comment(s)