Skip to main content

IP Geolocation - nginx + geoip2

I use Matomo on various projects to track engagement. Matomo gives me the option to utilize a couple of IP geolocation providers so I can see where my projects are being accessed from (for the most part). The first one, called default, relies on the language the user has set on their computer. This is not reliable enough for me. The next two are on based on DBIP or MaxMind databases. I went with using MaxMind databases because they provide a free version, where DBIP charges at least €49.90 a year. The first is a PHP implementation. I had issues with it intermittently not working correctly. The second is a http server module implementation. Nginx is my web server of choice, so the ngx_http_geoip2 module was my last resort.

All of the guides I was able to find didn’t give me all of what I needed to get a complete geolocation configuration in Matomo. In order to do that, I manually queried the databases to see what they would give me.

Using mmdblookup to query the databases manually.
root@hosting:~# mmdblookup --file /usr/share/GeoIP/GeoLite2-City.mmdb --ip 23.12.147.93
  {
    "continent":
      {
        "code":
          "NA" <utf8_string>
        "geoname_id":
          6255149 <uint32>
        "names":
          {
            "de":
              "Nordamerika" <utf8_string>
            "en":
              "North America" <utf8_string>
            "es":
              "Norteamérica" <utf8_string>
            "fr":
              "Amérique du Nord" <utf8_string>
            "ja":
              "北アメリカ" <utf8_string>
            "pt-BR":
              "América do Norte" <utf8_string>
            "ru":
              "Северная Америка" <utf8_string>
            "zh-CN":
              "北美洲" <utf8_string>
          }
      }
    "country":
      {
        "geoname_id":
          6252001 <uint32>
        "iso_code":
          "US" <utf8_string>
        "names":
          {
            "de":
              "Vereinigte Staaten" <utf8_string>
            "en":
              "United States" <utf8_string>
            "es":
              "Estados Unidos" <utf8_string>
            "fr":
              "États Unis" <utf8_string>
            "ja":
              "アメリカ" <utf8_string>
            "pt-BR":
              "EUA" <utf8_string>
            "ru":
              "США" <utf8_string>
            "zh-CN":
              "美国" <utf8_string>
          }
      }
    "registered_country":
      {
        "geoname_id":
          6252001 <uint32>
        "iso_code":
          "US" <utf8_string>
        "names":
          {
            "de":
              "Vereinigte Staaten" <utf8_string>
            "en":
              "United States" <utf8_string>
            "es":
              "Estados Unidos" <utf8_string>
            "fr":
              "États Unis" <utf8_string>
            "ja":
              "アメリカ" <utf8_string>
            "pt-BR":
              "EUA" <utf8_string>
            "ru":
              "США" <utf8_string>
            "zh-CN":
              "美国" <utf8_string>
          }
      }
  }

After figuring out the layout of the databases, I was able to build my nginx configurations relatively easily.

nginx.conf

http {
    ...
    geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
            auto_reload 5m;
            $geoip2_metadata_country_build metadata build_epoch;
            $geoip2_data_country_code default=US country iso_code;
            $geoip2_data_country_name country names en;
            $geoip2_data_continent_code default=NA continent code;
            $geoip2_data_continent_name default=North America continent names en;
    }

    geoip2 /usr/share/GeoIP/GeoLite2-City.mmdb {
            auto_reload 5m;
            $geoip2_data_city_name default=New York city names en;
            $geoip2_data_region_code subdivisions iso_code;
            $geoip2_data_region_name subdivisions names en;
            $geoip2_data_latitude location latitude;
            $geoip2_data_longitude location longitude;
            $geoip2_data_postal_code postal code;
    }
}

domain.conf

location ~ ^/(index|matomo|piwik|js/index|plugins/HeatmapSessionRecording/configs)\.php$ {
    fastcgi_param CONTINENT_CODE $geoip2_data_continent_code;
    fastcgi_param CONTINENT_NAME $geoip2_data_continent_name;
    fastcgi_param COUNTRY_CODE $geoip2_data_country_code;
    fastcgi_param COUNTRY_NAME $geoip2_data_country_name;
    fastcgi_param REGION_CODE $geoip2_data_region_code;
    fastcgi_param REGION_NAME $geoip2_data_region_name;
    fastcgi_param LATITUDE $geoip2_data_latitude;
    fastcgi_param LONGITUDE $geoip2_data_longitude;
    fastcgi_param POSTAL_CODE $geoip2_data_postal_code;
    fastcgi_param CITY_NAME $geoip2_data_city_name;
}

[This page was last updated on September 25, 2023.]