In this article, I will show you how to self-host Matomo using Docker and Ansible. The final stack will feature:
- A self-hosted Matomo instance on a ~ $10 VPS
- SSL (A+) certificate via Let's Encrypt and Certbot
- Zero-downtime deployments
- A Matomo sidecar container for cronjobs
- Version controlled Matomo plugins
Since Google sunset Google Analytics v3 at the end of June 2023 a lot of people have been underwhelmed with the experience of transitioning to GA 4. On top of that, there is a growing demand for privacy friendly website analytics, especially cookie-less solutions to adhere to GDPR or California online privacy laws.
There are numerous solutions out now that offer a cookie-less way to measure website interactions, one of which is Matomo. It's an open source solution (license here) that is similar to GA3 in its feature set. It has a plugin to import data from GA3 and even comes with its own tag manager (no more third parties for loading your container). While the overall look and feel may be lacking in certain areas, it's an actively developed product.
If you're bored already you can jump ahead and check out the code on GitHub, the README includes all steps necessary to get up and running, it assumes some familiarity with the technologies involved, however.
To follow along, you should have access to a terminal shell. MacOS and Linux users are good to go, for Windows users it'd be best to have WSL2 set-up.
This should be a fresh VPS instance with your SSH key added to the
authorized_keys. It's pretty straight forward to do this with Digital Ocean or Hetzner. Depending on your expected load, make sure to pick a more powerful instance.
If you use my Digital Ocean referral link, you will receive $200 for 60 days to test out this stack.
If you don't know how to set up a VPS with your SSH key, please refer to this tutorial by Digital Ocean.
You will need a Git client installed, this should be pretty straight forward on most operating systems.
In order to access the VPS we will set up in the next steps, it's easiest to add an SSH key to your GitHub account. There is a tutorial provided by GitHub here.
Pipenv is a Python virtualenv management tool that, simply put, locks versions of the Python libraries a project requires. This is crucial to provide a similar working environment for developers. Please refer to the official installation guide to install Pipenv.
Once you've installed the requirements, we're ready to clone the repository. Open your terminal and run:
git clone firstname.lastname@example.org:AltanS/matomo-docker-ansible.git
Using the SSH approach to clone a repository requires your SSH key to be added to your GitHub account.
cd matomo-docker-ansible # create the python environment for this project pipenv shell # install python requirements from Pipfile and lock them pipenv install # install ansible requirements ansible-galaxy install -r requirements.yml
For your final Matomo instance to be available on the public internet, make sure you've configured an A-Record pointing a custom domain (or subdomain) to the IP of the server you've created earlier. For example, this could be
matomo.example.com. In this case, you would have to add an A-Record with a Name (or Hostname) of
matomo and a Value of your server IP. Once this is done, you can check that everything's working by trying to log in via SSH into your server using this newly configured domain name.
Sometimes it can take a while for DNS entries to be populated, so a bit of patience might be necessary for this step.
Next we will provision the server using Ansible. Using Ansible we can define and configure the server as code in our repository, which makes running this stack in production much safer, as the stack is easily reproducible.
- Add your server IP to
.envYou can do this in a terminal command or within your IDE. What's important is that you change the values for:
GITHUB_USER_KEYS: this is the full URL to your public SSH keys
MATOMO_HOSTNAME: this is the domain name configured in the previous step
LETSENCRYPT_ADMIN_EMAIL: this should be an email you have access to
Once all of these steps are complete, you can run
ansible-playbook provision.yml -e "target_host=production"
This will run the
provision.yml playbook with the
target_host set to
production. If you ever decide to add a staging environment, you'd have to change this target_host (and also add /hosts/staging).
The provisioning can take a while, so please be patient. If any errors occur, make sure you've followed all steps correctly.
The deployment playbook (
deploy.yml) will set up and start docker compose for this stack. Docker compose is a way to describe docker containers in a YAML file.
You can adjust the passwords in
group_vars/production/secrets.yml directly or make use of encrypted passwords via Ansible vaults. Please refer to the repository on how to use
vault_pass.txt and Ansible vaults to encrypt your passwords.
Once you've set your secrets, you're ready for deployment.
ansible-playbook deploy.yml -e "target_host=production"
Once the deployment tasks have finished running you should be able to access your Matomo instance via the domain you've configured.
So what was just installed?
- NGINX on Ubuntu 22.04 via APT: handles requests to the
matomo_hostnameand serves the SSL certificate. All requests to port 443 are proxy passed to the Docker Daemon running
- Docker: another NGINX instance, Matomo, MariaDB and another Matomo instance for archival tasks
To install a Matomo plugin in this self-hosted instance, add the plugin folder to
matomo-plugins and then re-run the deployment playbook.
ansible-playbook deploy.yml -e "target_host=production"
This will copy the plugin folder to the remote host and mount it into the docker compose stack.
You can update Matomo via the admin dashboard, do this at your own risk and make sure you have backed up your data before.
You can use any approach to back up a MySQL database. This is a Gist of what this could look like.
I hope this helped someone out. If you find a bug or have an idea on how to improve, please let me know in the comments.