The old GeoIP legacy release (aka. GeoIPCity.dat) has been deprecated and doesn't receive updates for quit some time. It will get removed from Matomo with the next major release.
If you would like to have accurate location detection in Matomo / Piwik the new GeoIP2 module should be used.
Since Debian Buster doesn't ship it with it's PHP packages, there are some manual steps needed to achieve that.
If you use Debian 12 or later, you can install the extension via the package php8.2-maxminddb and skip the manual installation steps.
Location/City and ISP detection
First of all install the needed library, build-tools and the php-dev package in order to be able to build the maxminddb PHP extension. The usage of the PHP extension is optional, the detection will work without the extension as well, but less performant. Continue with the database installation in order to skip this step.
apt-get install libmaxminddb-dev php-dev git build-essential
Next step is to install the MaxMind-DB-Reader-php C extension for PHP. There are two possible ways of doing that.
# method 1 via pecl
pecl install maxminddb
# method 2 from source
cd /usr/local/src
git clone https://github.com/maxmind/MaxMind-DB-Reader-php
cd MaxMind-DB-Reader-php/ext
git checkout $(git describe --tags)
phpize
./configure
make && make install
After that the new PHP module needs to be enabled and Apache or PHP (when using FPM) restarted:
echo "extension=maxminddb.so" > /etc/php/7.3/mods-available/maxminddb.ini
phpenmod maxminddb
# The folder /usr/share/GeoIP needs to be added
# to the PHP open_basedir setting in your php.ini
apache2ctl graceful
service php7.3-fpm restart
Now the database GeoIP2-City.mmdb needs to be installed locally. Since the free version is updated once a month, this is done via a download cronjob.
The databases are provided by DB-IP (thanks). Check their website for usage conditions.
The City database is used to detect the location and the ASN database is used to detect the ISP.
apt-get install python3-requests
mkdir -p /usr/share/GeoIP
cat >> /usr/local/sbin/geoip2_update.py << EOF
#!/usr/bin/env python3
import requests
import datetime
import gzip
import sys
url = 'https://download.db-ip.com/free/'
date = datetime.datetime.now().strftime('%Y-%m')
dbs = {
'GeoIP2-City': {
'output_file': '/usr/share/GeoIP/GeoIP2-City.mmdb',
'download_file': f'dbip-city-lite-{date}.mmdb.gz'
},
'GeoIP2-ASN': {
'output_file': '/usr/share/GeoIP/GeoIP2-ASN.mmdb',
'download_file': f'dbip-asn-lite-{date}.mmdb.gz'
}
}
for k, v in dbs.items():
r = requests.get(url + v['download_file'])
if r.status_code == requests.codes.ok:
with open(v['output_file'], 'wb') as f:
f.write(gzip.decompress(r.content))
else:
sys.stderr.write(f'Download failed for {k}: {r.status_code}\n')
sys.exit(1)
EOF
chmod 700 /usr/local/sbin/geoip2_update.py
bash
cat >> /etc/cron.d/geoip2-update << EOF
MAILTO=root
$(( $RANDOM % 59 + 0 )) $(( $RANDOM % 23 + 0 )) 28 * * root /usr/local/sbin/geoip2_update.py
EOF
Now the GeoIP2 database gets updated once a month automatically and the script should be executed once to get the current version right now and to test the setup as well.
/usr/local/sbin/geoip2_update.py
In order to use GeoIP2 in Matomo two settings need to be done. First of all database Symlinks need to be created.
# adjust path to your matomo misc folder
cd /var/www/matomo/misc/
ln -s /usr/share/GeoIP/GeoIP2-City.mmdb GeoIP2-City.mmdb
ln -s /usr/share/GeoIP/GeoIP2-ASN.mmdb GeoLite2-ASN.mmdb
After that the Plugin GeoIp2 needs to be activated. It's a core package and should be already listed on the Matomo Plugins page in the Admin UI.
Now it should be possible to activate the new module under Geolocation. If your location is listed on the right side, enable the GeoIP2 box and click Save. Check that ISP detection works as well (ASN DB needs Matomo >=4.0).
That's it. The results are much more accurate and quicker.
Testing
If you don't use Matomo a PHP GeoIP2 testscript could be used instead.
<?php
use MaxMind\Db\Reader;
$reader = new Reader('/usr/share/GeoIP/GeoIP2-City.mmdb');
$record = $reader->get($_SERVER['REMOTE_ADDR']);
print($record['continent']['names']['en'] . "\n");
print($record['country']['names']['en'] . "\n");
print($record['subdivisions'][0]['names']['en'] . "\n");
print($record['city']['names']['en'] . "\n");
?>
Your continent, country, subdivision and city should be listed after executing the script via the webserver.