Search

Geo features

Geo features

Another very powerful piece of information you can retrieve is the geographical location of the client.

Although there are APIs you can call using vmod_http, the overhead may slow us down at scale. A superior solution is to use MaxMind’s geoIP database. This proprietary database, which has a free version, maps IP addresses to geographical locations.

There are both open source VMODs and proprietary VMODs available. They all rely on libmaxminddb.

As a developer, you can go to https://dev.maxmind.com/ to obtain a free version of the geoIP database:

  • GeoLite2-Country.mmdb: a database that only contains country and continent information
  • GeoLite2-City.mmdb: an extended version of the database that contains country, continent, city and geolocation information

As an administrator, it is your responsibility to keep the database up-to-date.

Being able to geographically locate the user allows you to perform geotargeting, but even geoblocking.

Geotargeting involves putting the user in a certain category based on their location. This is important when you build your own CDN because you can send users to the closest point of presence (PoP). Having content as close to your users as possible will decrease latency and increase the quality of experience.

Another example of geotargeting is presenting localized content to the user. Many multinational corporations have separate websites per country. Being able to suggest the right one based on the client IP address contributes to a good user experience.

Geoblocking is used to refuse access to certain content. Websites or OTT video platforms that are funded with taxpayer money will refuse access to their platforms for users outside of the country.

vmod_geoip2

vmod_geoip2 is an open source VMOD that is available on https://github.com/fgsch/libvmod-geoip2.

The geoip2.geoip2() function loads the MaxMind GeoIP database and returns an object. This object uses the .lookup() method to retrieve geographical information.

Here’s a very simple geoblocking example:

vcl 4.1;

import geoip2;

sub vcl_init {
	new country = geoip2.geoip2("/etc/varnish/GeoLite2-Country.mmdb");
}

sub vcl_recv {
	if(country.lookup("country/iso_code", client.ip) != "BE") {
		return(403,"Access from " + country.lookup("country/names/en", client.ip) + " not allowed");
	}
}

vmod_mmdb

vmod_mmdb is a Varnish Enterprise module that uses the same database file provided by MaxMind. Here’s the equivalent of the previous example:

vcl 4.1;

import mmdb;

sub vcl_init {
	new country = mmdb.init("/etc/varnish/GeoLite2-Country.mmdb");
}

sub vcl_recv {
	// there is a convenience function to
	// retrieve the country code directly, let's use it!
	if(country.country_code(client.ip) != "BE") {
		return(403,"Access from " + country.lookup(client.ip, "country/names/en") + " not allowed");
	}
}

Lookup filters

Both VMODs have a .lookup() method that takes a lookup path. This path is used to retrieve the information from the database.

The GeoLite2-Country.mmdb database only contains country and continent information. Here are a couple of examples of various paths:

  • continent/code: for example EU
  • continent/names/en: for example Europe
  • country/is_in_european_union: for example true
  • country/names/iso_code: for example BE
  • country/names/en: for example Belgium

There is a German, Spanish, French, Japanese, Portuguese, Russian and Chinese alternative for continent/names/en and country/names/en.

Here’s an overview of paths you can use to retrieve the country name in the various supported languages:

  • country/names/de
  • country/names/en
  • country/names/es
  • country/names/fr
  • country/names/ja
  • country/names/pt-BR
  • country/names/ru
  • country/names/zh-CN

These language codes are also available for continent names.

The GeoLite2-City.mmdb also contains all of the above but is supplemented with city and geolocation information.

Here’s an overview of additional lookup filters for the city database:

  • city/names/de
  • city/names/en
  • city/names/es
  • city/names/fr
  • city/names/ja
  • city/names/pt-BR
  • city/names/ru
  • city/names/zh-CN
  • location/accuracy_radius
  • location/latitude
  • location/longitude
  • location/time_zone
  • postal/code

There is also a subdivision field that describes states, provinces, or communities within a country, but we’re not going to cover this in the book.

Backend geotargeting example

The following example looks up the continent code for the client IP address based on the GeoLite2-Country.mmdb databases, and matches this with available backends stored using vmod_kvstore.

If no corresponding backend is found, the default one is used.

vcl 4.1;

import kvstore;
import mmdb;
import std;

backend default {
    .host="default.backend.example.com";
}

backend de {
    .host="de.backend.example.com";
}

backend us {
    .host="us.backend.example.com";
}

backend br {
    .host="br.backend.example.com";
}

backend jp {
    .host="jp.backend.example.com";
}

backend sa {
    .host="sa.backend.example.com";
}

backend au {
    .host="au.backend.example.com";
}

sub vcl_init {
    new geo = mmdb.init("/etc/varnish/GeoLite2-Country.mmdb");
    new backends = kvstore.init();
    backends.set_backend("EU",de);
    backends.set_backend("NA",us);
    backends.set_backend("SA",br);
    backends.set_backend("AS",jp);
    backends.set_backend("OC",au);
    backends.set_backend("AF",sa);
}

sub vcl_recv {
    set req.backend_hint = backends.get_backend(
        geo.lookup(
            client.ip,
            "continent/code"
        ),
        default
    );
}

The example above features backends in Germany, the United States, Brazil, Japan, Australia and South Africa. Each of these endpoints is associated with the corresponding continent code.

If you’re in Antarctica, or there is an issue mapping the IP address to a location, the default backend is used.

This same example can easily be reproduced using the open source vmod_ geoip2.


®Varnish Software, Wallingatan 12, 111 60 Stockholm, Organization nr. 556805-6203