This blog is hosted on a quadcore VPS with 8gb of RAM. The price I pay is 5€ monthly, forever. Link to Contabo with my referral code.

How to install Matomo with docker-compose

How to install Matomo with docker-compose
how to install matomo with docker compose 1024

I’ve never understand how much power has the owner of a website/app in terms of data until I started having websites.

I tried Google Analytics since I wanted to understand a little bit more about my website but I understood immediately that it was very invasive.

It’s my website, I write posts but still I don’t know how user read them. If they read them.

It’s not about spying, it’s about understanding what is good from what is not.

Imagine the owner of a shop with a foulard that cover his view and earplugs in his hears.  Taking care of the shop would me a mess: are clients coming inside the shop? If yes, when they go out? What if most of them go out after checking prices? Do I want this? It could be, maybe I’m aiming to a very particular niche, but since they came in maybe I can offer something to them.

A webmaster or a blogger without a good analytic tool is blind and deaf and can’t understand what happening to his websites’s visitors.

Don’t misunderstand me, I’m not the kind of person that loose more time on analytics than writing (I usually spend most of my time fixing what it’s not working), and I think that having a good open source analytic tool like Matomo doesn’t change the game.

Docker and docker-compose

I suppose you already know what Docker is and that you have both, docker and docker compose, on your host system.

Indeed we’ll use docker compose to run Matomo and if you follow this tutorial everything should work.

If not blame who updated Matomo or docker. 🙂
(and write a comment here so I can update the post)

Matomo docker-compose

Ok, first thing to say is that I took the docker-compose.yml from the official Matomo Github repository.

Create a folder called matomo.

mkdir matomo

Then let’s go inside that folder.

cd matomo

Now you have to create three files. If nano does’t work use sudo in front of nano.


nano docker-compose.yml

version: '3'

    image: mariadb
    command: --max-allowed-packet=64MB
    restart: always
      - db:/var/lib/mysql
      - ./db.env

    image: matomo:fpm-alpine
    restart: always
      - db
#      - ./config:/var/www/html/config:rw
#      - ./logs:/var/www/html/logs
      - matomo:/var/www/html
      - ./db.env

    image: nginx:alpine
    restart: always
      - matomo:/var/www/html:ro
      # see
      - ./matomo.conf:/etc/nginx/conf.d/default.conf:ro
      - 8080:80



Here we specify our enviroment variables. You can directly copy and paste it but make sure to change the password (XXXXXXXX and YYYYYYYY).

nano db.env


You can copy and paste this without modify anything.
nano matomo.conf

upstream php-handler {
    server app:9000;

server {
    listen 80;

    add_header Referrer-Policy origin; # make sure outgoing links don't show the URL to the Matomo instance
    root /var/www/html; # replace with path to your matomo instance
    index index.php;
    try_files $uri $uri/ =404;

    ## only allow accessing the following php files
    location ~ ^/(index|matomo|piwik|js/index|plugins/HeatmapSessionRecording/configs).php {
        # regex to split $uri to $fastcgi_script_name and $fastcgi_path
        fastcgi_split_path_info ^(.+\.php)(/.+)$;

        # Check that the PHP script exists before passing it
        try_files $fastcgi_script_name =404;

        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param HTTP_PROXY ""; # prohibit httpoxy:
        fastcgi_pass php-handler;

    ## deny access to all other .php files
    location ~* ^.+\.php$ {
        deny all;
        return 403;

    ## disable all access to the following directories
    location ~ /(config|tmp|core|lang) {
        deny all;
        return 403; # replace with 404 to not show these directories exist
    location ~ /\.ht {
        deny all;
        return 403;

    location ~ js/container_.*_preview\.js$ {
        expires off;
        add_header Cache-Control 'private, no-cache, no-store';

    location ~ \.(gif|ico|jpg|png|svg|js|css|htm|html|mp3|mp4|wav|ogg|avi|ttf|eot|woff|woff2|json)$ {
        allow all;
        ## Cache images,CSS,JS and webfonts for an hour
        ## Increasing the duration may improve the load-time, but may cause old files to show after an Matomo upgrade
        expires 1h;
        add_header Pragma public;
        add_header Cache-Control "public";

    location ~ /(libs|vendor|plugins|misc/user) {
        deny all;
        return 403;

    ## properly display textfiles in root directory
    location ~/(.*\.md|LEGALNOTICE|LICENSE) {
        default_type text/plain;

# vim: filetype=nginx

I hope it works for you as it worked for me. If you have any suggestions or if you encountered in any problem feel free to leave a message here.

Notable Replies

  1. this post is so interesting!

  2. This is so true. Thank you!

Continue the discussion at