Matomo - Google Analytics Alternative
How I self hosted Matomo with Docker and got rid of cookie consent popups
General Data Protection Regulation
If you surf the web nowadays, sooner or later you will be confronted with an annoying cookie consent popup. Websites need to show these cookie popups under specific circumstances since May 25, 2018 due to the entry into force of the General Data Protection Regulation (GDPR) in the European Union. The official information website of the GDPR states really clear if the GDPR applies to one:
[...] if you process the personal data of EU citizens or residents, or you offer goods or services to such people, then the GDPR applies to you even if you’re not in the EU.
If the above applies to you and you are using cookies on your website, you have to be really careful. According to the official GDPR site you must:
- Receive users’ consent before you use any cookies except strictly necessary cookies.
- Provide accurate and specific information about the data each cookie tracks and its purpose in plain language before consent is received.
- Document and store consent received from users.
- Allow users to access your service even if they refuse to allow the use of certain cookies
- Make it as easy for users to withdraw their consent as it was for them to give their consent in the first place.
Google Analytics
What does this mean for website analytic services like Google Analytics? If you embed the Google Analytics script on your page, this will automatically add a tracking cookie to your users browser. As per GDPR definition, you would need to add a mechanism for your users to explicitly opt-in to add the tracking cookie. You would also need to provide information about the data which is being tracked, store the consent received from the user and add functionality for the user to withdraw their consent. All of this is not straight forward to implement, but it is required to comply with the law if you want to use Google Analytics.
Matomo
For my personal site and this blog I thought about not having any analytics at all. On the one hand I don't like to be tracked online, I think user's privacy is important. On the other hand I find it really interesting to see how people find my website and how many visits different pages or articles get. I also like to own the collected data and have full access to the data if I want and need to. For these reasons I have chosen Matomo as an analytics solution. Matomo can be set up to not use cookies at all and be completely GDPR compliant.
Matomo User Interface
Matomo offers a hosted cloud solution and also a self hosted on-premise version. Some more advanced features like Heatmaps and Session Recordings are included in the cloud version and can be chargeable added as an add-on to the self hosted version. When making the decision I was happy with the feature set of the free self hosted version.
Nginx and Let's Encrypt SSL Certificate with Docker
I am using Docker to host Matomo, get Let's Encrypt SSL certificates and run Nginx as a reverse proxy. To make things really easy, we can setup the awesome evertramos/nginx-proxy-automation project. Follow the instructions in the README to setup the containers via Docker. This will automatically create a Docker network called webproxy
.
The started containers will automatically detect if a container joins the same network and will automatically create the Nginx reverse proxy configuration and provisions a Let's Encrypt certificate. The certificate will automatically be renewed.
Once the setup is complete, you can run docker ps
, which should show you that three containers are running:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
712c1fded215 jrcs/letsencrypt-nginx-proxy-companion:stable "/bin/bash /app/entr…" 4 weeks ago Up 4 weeks nginx-letsencrypt
857936f1827b jwilder/docker-gen "/usr/local/bin/dock…" 4 weeks ago Up 4 weeks nginx-gen
9f829ab43818 nginx:stable-alpine "/docker-entrypoint.…" 4 weeks ago Up 4 weeks 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nginx-web
Self Host Matomo with Docker
To make things easier I am using Docker Compose to configure multiple containers and run these with a single command. As a starting point for the docker compose configuration I've used the official example docker-compose.yml and tweaked it to work with the Nginx setup above. The configuration will create a "db" container which is a mariadb database and an "app" container which is the Matomo app itself.
All configuration files below are available in a Github project. Tweaked docker-compose.yml
:
version: "3"
services:
db:
image: mariadb
container_name: matomo_db
command: --max-allowed-packet=64MB
restart: always
volumes:
- ./db_data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=YOUR_ROOT_PW
env_file:
- ./db.env
app:
build: .
container_name: matomo_app
restart: always
links:
- db
environment:
- MATOMO_DATABASE_HOST=db
- VIRTUAL_HOST=yoursub.domain.com
- LETSENCRYPT_HOST=yoursub.domain.com
- [email protected]
env_file:
- ./db.env
volumes:
db:
matomo:
networks:
default:
external:
name: webproxy
As you can see, the "app" container is build from a Dockerfile
in the same directory. The official example is just using the "matomo" image. I had file permission issues, so I decided to create a cutomized image which automatically sets the correct permissions. This is the Dockerfile
:
FROM matomo
RUN chown -R www-data:www-data /var/www/html
RUN find /var/www/html/tmp -type f -exec chmod 644 {} \; || true
RUN find /var/www/html/tmp -type d -exec chmod 755 {} \; || true
RUN find /var/www/html/tmp/assets/ -type f -exec chmod 644 {} \; || true
RUN find /var/www/html/tmp/assets/ -type d -exec chmod 755 {} \; || true
RUN find /var/www/html/tmp/cache/ -type f -exec chmod 644 {} \; || true
RUN find /var/www/html/tmp/cache/ -type d -exec chmod 755 {} \; || true
RUN find /var/www/html/tmp/logs/ -type f -exec chmod 644 {} \; || true
RUN find /var/www/html/tmp/logs/ -type d -exec chmod 755 {} \; || true
RUN find /var/www/html/tmp/tcpdf/ -type f -exec chmod 644 {} \; || true
RUN find /var/www/html/tmp/tcpdf/ -type d -exec chmod 755 {} \; || true
RUN find /var/www/html/tmp/templates_c/ -type f -exec chmod 644 {} \; || true
RUN find /var/www/html/tmp/templates_c/ -type d -exec chmod 755 {} \; || true
We are mapping the database from a local directory to the container via a volume. Create the directory:
mkdir db_data
We also need a db.env
file:
MYSQL_PASSWORD=YOUR_ROOT_PW
MYSQL_DATABASE=matomo
MYSQL_USER=matomo
MATOMO_DATABASE_ADAPTER=mysql
MATOMO_DATABASE_TABLES_PREFIX=matomo_
MATOMO_DATABASE_USERNAME=matomo
MATOMO_DATABASE_PASSWORD=YOUR_ROOT_PW
MATOMO_DATABASE_DBNAME=matomo
Now we have finally created all files and we can run docker-compose up
to start the matomo database and the matomo app. Due to the configured network, this will automatically create a Nginx configuration for the configured VIRTUAL_HOST, which is yoursub.domain.com in the above docker-compose.yml
and provision a SSL certificate for the domain. 👍
If you now take a look at docker ps
to show the running containers, it should look like this:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4e15e25485cb matomo_app "/entrypoint.sh apac…" 4 weeks ago Up 4 weeks 80/tcp matomo_app
2b76c0ccaab1 mariadb "docker-entrypoint.s…" 4 weeks ago Up 4 weeks 3306/tcp matomo_db
712c1fded215 jrcs/letsencrypt-nginx-proxy-companion:stable "/bin/bash /app/entr…" 4 weeks ago Up 4 weeks nginx-letsencrypt
857936f1827b jwilder/docker-gen "/usr/local/bin/dock…" 4 weeks ago Up 4 weeks nginx-gen
9f829ab43818 nginx:stable-alpine "/docker-entrypoint.…" 4 weeks ago Up 4 weeks 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nginx-web
You can now open yoursub.domain.com in the browser, if everything is working fine you should see the Matomo welcome screen. Matomo will guide you through the setup process. During the setup process Matomo will provide you a Javascript code snippet which you need to integrate on your website, which looks something like this:
<!-- Matomo -->
<script type="text/javascript">
var _paq = (window._paq = window._paq || []);
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(["trackPageView"]);
_paq.push(["enableLinkTracking"]);
(function () {
var u = "//yoursub.domain.com/";
_paq.push(["setTrackerUrl", u + "matomo.php"]);
_paq.push(["setSiteId", "1"]);
var d = document,
g = d.createElement("script"),
s = d.getElementsByTagName("script")[0];
g.type = "text/javascript";
g.async = true;
g.src = u + "matomo.js";
s.parentNode.insertBefore(g, s);
})();
</script>
<!-- End Matomo Code -->
Now you are ready to go! There are many configuration options for Matomo, which you can look up on their official user guides. To get rid of the annoying cookie popups make sure to configure Matomo correctly. If everything works like expected you should now see visits to your site.
I run this exact same setup on a $5 Digital Ocean droplet. If you register via my referal link you will get $100 in credit for the first 60 days.
Thanks for reading, I hope I could help you with setting up Matomo 👋