How to run Matomo in Docker locally?

How to run Matomo in Docker locally?

Fast setup for development and testing

Do you want to run Matomo on your local machine for development and testing purposes? Then this article is for you! You will learn how to set up Matomo using docker-compose, how to configure the initial database and how to reset the environment to the original configuration. Resetting is especially handy when you want to run a clean install of Matomo for automated tests.

Let's hop right in!

Based on https://github.com/matomo-org/docker/tree/a9ce756ce0ca0957ed7a8987e562f37e6b5e4a45/.examples/nginx

Initial folder content

Here are the initial files in a folder. Copy and paste the file contents below.

/matomo
|__db.env
|__docker-compose.yml
|__matomo.conf

docker-compose.yml

version: "3"

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

  app:
    image:
      # Select your Matomo container from: 
      # https://hub.docker.com/_/matomo
      matomo:4.13.0-fpm-alpine
    restart: always
    links:
      - db
    volumes:
      #- ./config.ini.php:/var/www/html/config/config.ini.php
      #- ./logs:/var/www/html/logs
      - matomo:/var/www/html
    environment:
      - MATOMO_DATABASE_HOST=db
      - PHP_MEMORY_LIMIT=2048M
    env_file:
      - ./db.env

  web:
    image: nginx:alpine
    restart: always
    volumes:
      - matomo:/var/www/html:ro
      # see https://github.com/matomo-org/matomo-nginx
      - ./matomo.conf:/etc/nginx/conf.d/default.conf:ro
    ports:
      - 8111:80

volumes:
  db:
  matomo:

db.env

MARIADB_ROOT_PASSWORD=root
MYSQL_PASSWORD=matomo
MYSQL_DATABASE=matomo
MYSQL_USER=matomo
MATOMO_DATABASE_ADAPTER=mysql
MATOMO_DATABASE_TABLES_PREFIX=matomo_
MATOMO_DATABASE_USERNAME=matomo
MATOMO_DATABASE_PASSWORD=matomo
MATOMO_DATABASE_DBNAME=matomo
MARIADB_AUTO_UPGRADE=1
MARIADB_INITDB_SKIP_TZINFO=1

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: https://httpoxy.org/
        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

Prepare the database

Ok, we are ready to start the Docker containers. Use --detach switch to run the containers in the background.

# Run the command:
docker-compose up --detach

After running the above command visit http://localhost:8111 and you should see the following Matomo install wizard.

Go through the installation process step by step. After that, depending on your needs, you may want to add some configuration for automated tests or basic development setup.

Mount the config file

The next command will mount the config file created during installation to your host computer for editing.

# Run the command:
docker cp matomo_app_1:/var/www/html/config/config.ini.php .

Now your folder should look like this:

/matomo
|__config.ini.php <-- This is added.
|__db.env
|__docker-compose.yml
|__matomo.conf

Edit the config.ini.php file.

...
[General]
salt = "f5c8452a6d1491ac3b3ac475bb18e8d0" <-- This may differ.
trusted_hosts[] = "localhost:8111" <-- Add the port.
...

Edit the docker-compose.yml file.

...
  app:
    ...
    volumes:
      # Uncomment the below line like this.
      - ./config.ini.php:/var/www/html/config/config.ini.php
      #- ./logs:/var/www/html/logs
      - matomo:/var/www/html
    ...

Export the database volume

Next, we export the database volume by running the command below.

# Run the command:
docker run --rm --volume matomo_db:/dbdata --volume $(pwd):/backup ubuntu tar cvzf /backup/initial-db.gz /dbdata

Now your folder should look like this.

/matomo
|__config.ini.php
|__db.env
|__docker-compose.yml
|__initial-db.gz <-- This is added.
|__matomo.conf

Take it down...

Now we remove the containers and volumes to clean up. Run the below command.

# Run the command.
docker-compose down -v

Now the containers and volumes are gone. Everything you need is ready as files in the folder. You can commit the files to your version control and it's easy to share the same setup with others

...and up again

Let's try to start the containers with the initial database from the files.

# Import the database:
docker run --rm --volume matomo_db:/dbdata --volume $(pwd):/backup ubuntu tar xvzf /backup/initial-db.gz -C /dbdata --strip 1
# Start Matomo:
docker-compose up --detach

Now you should have the Matomo running. Go and check the URL http://localhost:8111.

Extra tip for Node.js users

If you are using Node.js, it might be handy to put something like this in your package.json file.

...
 "scripts": {
    "matomo:start": "cd matomo; docker-compose up --detach",
    "matomo:stop": "cd matomo; docker-compose down",
    "matomo:reset": "cd matomo; npm run matomo:stop; docker run --rm --volume matomo_db:/dbdata --volume $(pwd):/backup ubuntu tar xvzf /backup/initial-db.gz -C /dbdata --strip 1; npm run matomo:start",
    "matomo:destroy": "cd matomo; docker-compose down -v"
  },
...

Now you can simply run:

npm run matomo:start
# OR
npm run matomo:stop
# OR
npm run matomo:reset
# OR
npm run matomo:destroy

Afterwords

Thanks for reading! You are welcome to drop a comment if you found this useful or if you have some ideas to share with the community.