Photo by Webaroo on Unsplash

Matomo is a web analytics platform, so a thing that allows us to get stats on visitors and our content.

One of the differences between Matomo (and similar) and Google Analytics, is the fact that with the former we have total ownership and control of data.

[ If you speak Italian, you will have fun reading the rest of this post here ]

In this piece we’ll see how to self-host Matomo with:

We also assume that we already have a container with an active web project (e.g. Apache, Ghost, WordPress, …) configured with a reverse proxy; specifically in this tutorial we consider:

What we want

Suppose that we have a web project on mysite.ext and we want to put Matomo in a subdomain stats.mysite.ext .

In this case we just need to:

Configure a CNAME DNS record that makes the subdomain an alias of the main domain.

DNS record that makes the subdomain an alias of the main domain. Install Matomo and expose it on https://stats.mysite.ext .

After we have created the record, we can move on to the second point.

Preparation

Create a ~/matomo directory with two files inside:

docker-compose.yml

version: "2"



services:

matomo:

container_name: matomo

image: matomo

ports:

- 8080:80

environment:

- MATOMO_DATABASE_HOST=matomo_db

- VIRTUAL_HOST=stats.mysite.ext

- LETSENCRYPT_HOST=stats.mysite.ext

- LETSENCRYPT_EMAIL=email@something.ext

env_file:

- ./db.env

networks:

- proxy

- net

depends_on:

- matomo_db

restart: unless-stopped



matomo_db:

container_name: matomo_db

image: mariadb

command: --max-allowed-packet=64MB

environment:

- MYSQL_ROOT_PASSWORD=makeitup

env_file:

- ./db.env

networks:

- net

restart: unless-stopped



networks:

proxy:

external:

name: nginx-proxy

net:

driver: bridge

Remarkable things:

We have attached matomo at the existing network nginx-proxy , where our web container is also attached.

at the existing network , where our web container is also attached. We have defined a new network net with matomo and matomo_db inside; but there is no need (and we don’t want) that the latter also stays in nginx-proxy .

with and inside; but there is no need (and we don’t want) that the latter also stays in . The LETSENCRYPT_* environment variables are used by letsencrypt-nginx-proxy-companion .

environment variables are used by . We have defined a dependency relation (thus startup order too) between the two containers.

db.env

MYSQL_PASSWORD=makeitup2

MYSQL_DATABASE=matomo

MYSQL_USER=matomo

MATOMO_DATABASE_ADAPTER=mysql

MATOMO_DATABASE_TABLES_PREFIX=matomo_

MATOMO_DATABASE_USERNAME=matomo

MATOMO_DATABASE_PASSWORD=

MATOMO_DATABASE_DBNAME=matomo

Once we are ready docker-compose up -d .

Note that at this point we should already have an active and working SSL certificate for our nice subdomain.

Installing Matomo

Once our stack is up and running, let’s go on stats.mysite.ext and the Matomo installation wizard should appear.

We can go on to the DB configuration, that will already by filled (thanks to the MATOMO_* environment variables); the only empty field is the DB password, in which we must put the value of MYSQL_PASSWORD .

After setting it up, the DB connection should be working and Matomo will install itself.

Initial Matomo configuration

Before we paste the tracking code on our site, it is better to configure the report archiving, to avoid slowing down our entire system.

The archiving process is just Matomo putting its data together and making it pretty and visible to us.

By default archiving is triggered by some requests of our visitors, and we may not like it. We want to disable this behavior and gain control of the archiving process, setting up an automated process.

Configuring report archiving

Login on stats.miosito.boh with the SuperUser defined in the installation phase; Go in System->General configuration. Set the browser-activated archiving to No.

Now we have a couple of ways to defined the automatic thing:

Define a sidecar container called matomo_cron with the same image as matomo and possibly the same volumes, with an entrypoint script that basically: sleeps for n seconds, than executed the archive script.

with the same image as and possibly the same volumes, with an script that basically: sleeps for n seconds, than executed the archive script. Simply define a cron job on the host system.

We will follow the second road, even if it is not so elegant Dockerwise.

Cron Job

Login on the host system with the user with which we normally use Docker and: mkdir -p $HOME/logs , then execute crontab -e and paste this thing:

5 * * * * if [ $(docker inspect -f '{{.State.Running}}' matomo) ]; then docker exec -t matomo su -s "/bin/bash" -c "/usr/local/bin/php /var/www/html/console core:archive --url=https://stats.mysite.ext" www-data; fi >> $HOME/logs/matomo-archive.log



Since we defined it with crontab -e , it will be executed in the context of the current user, and the fields have this meaning: minutes, hours, days, months, weekdays, command.

Our crontab:

Will be execute every hour at the minute 05;

If matomo is running, run the archiving process with the in-container user www-data ;

is running, run the archiving process with the in-container user ; Spit out the output in ~/logs/matomo-archive.log .

The last empty line is in the cron specs and removing it may fail the script.

Anyway I suggest to test the script to make sure that there are no problems.

Conclusions

Now we can put the tracking code on our site and enjoy analytics that are:

Homemade;

Easily configurable privacy-wise;

Auto-updating every hour.

If we want to be cool, we can download the Matomo mobile app and read stats from here too.