Setup HTTPS for Matomo

Mandatory if you use the javascript tracker, recommended no matter what, here's how to secure communication with Matomo via HTTPS. And yes, it's again about certificates...

It almost became a reflex, as soon as we set up a web service: we secure it with an HTTPS connection.

In fact, the best thing to do is to first ask yourself the question: "is this relevant for this service?". And if the answer is yes, then install the certificates and setup the connection.

After having installed matomo in our private network and having setup logging, we could indeed ask ourselves why so many efforts? After all, it can only be accessed locally ! The answer lies in two points:

  1. Personal data. The requests made by the javascript tracker are, by definition, private data and must be protected against modifications and fraudulent access. Likewise, if you forgot to anonymize the results, these too must be protected (while waiting to be anonymized of course 😉).
  2. Defense in depth. Even if we do not use the tracker, if your data is anonymized, if the server can only be accessed locally and if statistics are accessible only after access control, we are not immune to error.

To be transparent with you, I appreciate when things are done well and getting my hands dirty for these certificate details, that relaxes me...

As you will see, the subtlety with Matomo is that part of the configuration is done in the classic way with the web server (here, apache2) but some details are done via Matomo's configuration files ...

Deploy the certificate and the key

I'm assuming that you already know how to generate a certificate and its key. Otherwise, here's how to generate them with XCA. For simplicity, I will also assume that you have exported these two files:

Unsurprisingly, these files must be uploaded to your Matomo server. Technically, you could put them wherever you want, but the tradition has two directories designed for that:

Like all traditions, you can chose to be rebels, it will work very well but you will have communication problems with your colleagues...

The advantage of using these two directories is that they are already setup to minimize the risk of leaks of this sensitive data.

But since a problem can always happen, we will do defense in depth (again and again) and change the rights of the two files (root owner and access rights):

sudo chown root:root /etc/ssl/certs/matomo.crt
sudo chown root:root /etc/ssl/private/matomo.key
sudo chmod 640 /etc/ssl/private/matomo.key

Why the root user and not www-data? Because when the application server starts, it does so with the identity of root, to open the network ports (80 and 443 that only root can open) and read its configuration. It is only once launched that it drop its privileges and changes to the identity www-data. At this point, there is no longer any justification for reading the configuration files.

Setup the web server

Since I am using a blank server and its default configuration, I will modify the default configuration file for HTTPS connections: /etc/apache2/site-available/default-ssl.conf.

Change the configuration. As these change are classics, you only have to look for the two lines of SSL/TLS directives concerning the certificate and the key and adapt the path to your files. Something like this:

SSLCertificateFile    /etc/ssl/certs/matomo.crt
SSLCertificateKeyFile /etc/ssl/private/matomo.pem

Enable HTTPS. By default, your apache2 server has not yet enabled the module (ssl) and virtual host for HTTPS connections. Their activation is done in three simple commands:

sudo a2enmod ssl
sudo a2ensite default-ssl
sudo service apache2 restart

Bonus : HSTS

Another defense in depth task, we can also setup the web server to notify browsers not to contact it through unsecured channels. We call that HTTP Strict Transport Security and in other words, it asks browsers to refuse to load resources or send data via HTTP and to use only HTTPS.

Nothing complicated to do, you have to add a directive line to the previous SSL/TLS vhost file:

Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

For this to work, you must also activate the headers module which manages this configuration line and which will insert this header to HTTP responses. Two commands to launch and it will works:

sudo a2enmod headers
sudo service apache2 restart

Force the HTTPS connection

Your site is now accessible in HTTPS but some visitors could still use HTTP.

We could of course setup apache2 to automatically redirect all HTTP requests to HTTPS but as Matomo has something made internally (this is even explained in the official documentation, I prefer to go through it.

I agree: it is not a good practice to mix the layers and partially setup SSL/TLS in two different systems. But from experience, this kind of thing often hides technical debt and unpredictable side effects. So to avoid wasting hours in improbable debugging, I prefer to follow the documentation.

To force HTTPS connections, you must then modify the matomo configuration file (from the Matomo directory: config/config.ini) and uncomment theforce_ssl line:

force_ssl = 1

The redirection will therefore not be done by apache2 but by matomo's PHP. So there is no need to enable mod_rewrite on apache.

And after ?

Your application and your web server are now accessible via HTTPS, communications are secured by TLS. The HSTS makes it possible to avoid some forgotten resources being accessed in HTTP and Matomo will redirect these accesses to the HTTPS version anyway.

Of course, for it to be really secure, the CA that signed your certificate must be recognized by your users' browsers. If you have your own PKI, that means deploying your CA to your visitors.

This is the case with the arsouyes. As we do not use javascript but log files, our Matomo can only be accessed by the arsouyes to read reports. And since we have other internal applications using TLS with certificates signed by our PKI, we had already deployed our CA on our browsers.

If your matomo is going to be accessible to anyone, it is going to be difficult to deploy your CA everywhere. In this case, going through an already recognized CA will make it easier for you (and in this case, you could use lets encrypt).