Skip to content

TutorialsAnalytics

How to install Matomo on Ubuntu or Debian with Nginx and MariaDB

Install Matomo web analytics with Nginx, PHP-FPM and MariaDB on Ubuntu or Debian, add HTTPS, cron archiving, GeoIP and privacy settings, then back it up.

  • Intermediate
  • 50 min read
  • Updated

Tested on: Ubuntu 24.04 LTS, Ubuntu 26.04 LTS, Debian 12, Debian 13

This guide is not available in your language yet, so it is shown in English.

On this page
  1. Prerequisites
  2. Step 1 — Install Nginx, PHP-FPM and MariaDB
  3. Step 2 — Create the database and user
  4. Step 3 — Download Matomo
  5. Step 4 — Open the firewall and get a certificate
  6. Step 5 — Configure Nginx with Matomo's configuration
  7. Step 6 — Run the web installer
  8. Step 7 — Process reports with cron
  9. Step 8 — Set up geolocation
  10. Step 9 — Review the privacy settings
  11. Back up and restore
  12. Update Matomo
  13. Troubleshooting
  14. 502 Bad Gateway
  15. nginx -t reports that it cannot load the certificate
  16. The system check says tmp/ or config/ is not writable
  17. Reports stay empty or are only updated once a day
  18. Matomo warns that it is accessed from an untrusted host
  19. Next steps

Matomo is an open-source web analytics platform that you run on your own server, so visitor data stays in your own database instead of a third-party service. It offers reports similar to commercial analytics tools, plus privacy controls such as IP anonymisation, opt-out and consent tracking.

This guide installs Matomo On-Premise the classic way that Matomo's installation guide describes: Nginx with the configuration that Matomo publishes, PHP-FPM and MariaDB from your distribution, the official matomo.zip release and a Let's Encrypt certificate from Certbot. You then switch report processing to a cron job, set up geolocation and privacy options, and learn how to back up, restore and update Matomo. At the time of writing the current release is Matomo 5.14.1; Matomo 6.0.0 is in beta.

Prerequisites

  • A server running Ubuntu 24.04 LTS, Ubuntu 26.04 LTS, Debian 12 or Debian 13.
  • A non-root user with sudo rights. If you have not set one up yet, follow Secure a new Linux server and Set up SSH keys.
  • A domain name such as matomo.example.com with an A record (and AAAA record if you use IPv6) pointing at your server.
  • Ports 80 and 443 free on the server. This guide runs Nginx as the web server; if the server already uses Caddy or another web server on these ports, install Matomo on a separate server or adapt the configuration yourself.

Matomo publishes recommended server sizes by traffic rather than a strict minimum. The first column shows its recommendation for up to 100,000 page views a month on a single server; the second shows its figure for up to 1 million page views a month:

ResourceMinimum (official)Suggested starting point
CPU2 CPU (up to 100,000 page views a month)4 CPU for up to 1 million page views a month
Memory2 GB RAM8 GB RAM for up to 1 million page views a month
Disk50 GB SSD250 GB SSD for up to 1 million page views a month
PHPPHP 8 for Matomo 5; 8.1 or newer for Matomo 6The PHP 8 release from your distribution
DatabaseMySQL 5.5+ or MariaDB for Matomo 5; MySQL 8.0+ or MariaDB 10.6+ for Matomo 6MariaDB from your distribution

Above about 1 million tracked actions a month, Matomo advises splitting the database and the application onto two servers.

Step 1 — Install Nginx, PHP-FPM and MariaDB

Install the web server, the database, PHP-FPM and the PHP extensions that Matomo requires or recommends (pdo_mysql or mysqli, plus curl, gd, xml, mbstring, intl and zip):

Bash
sudo apt update
sudo apt install nginx mariadb-server php-fpm php-cli php-mysql php-curl php-gd php-xml php-mbstring php-intl php-zip unzip curl

Installing php-fpm instead of the php metapackage keeps Apache off the server. Check the versions and find the PHP-FPM socket name, which contains the PHP version:

Bash
php -v
systemctl status nginx mariadb --no-pager
ls /run/php/

php -v should report PHP 8, and /run/php/ should contain a socket such as php8.3-fpm.sock. The version number differs between Ubuntu and Debian releases; you will use it in Step 5.

Step 2 — Create the database and user

Matomo recommends a dedicated database with a user that can access only that database. Generate a strong password first and keep it for the web installer:

Bash
openssl rand -hex 24
sudo mariadb

On Ubuntu and Debian, sudo mariadb logs you in as the database root user through the local socket. Run these statements, replacing change-me with the generated password:

SQL
CREATE DATABASE matomo;
CREATE USER 'matomo'@'localhost' IDENTIFIED BY 'change-me';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, INDEX, DROP, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES ON matomo.* TO 'matomo'@'localhost';
FLUSH PRIVILEGES;
EXIT;

These are the privileges listed in Matomo's database FAQ. Matomo also mentions an optional global FILE privilege that speeds up archiving with LOAD DATA INFILE; this guide leaves it out to keep the database user limited to its own database.

Step 3 — Download Matomo

Download the official release from builds.matomo.org, unpack it and move it to /var/www/matomo. Matomo asks you not to use third-party download sources, and it publishes GPG signatures if you want to verify the archive:

Bash
cd /tmp
curl -fLO https://builds.matomo.org/matomo.zip
unzip -q matomo.zip
sudo mv /tmp/matomo /var/www/matomo
sudo chown -R www-data:www-data /var/www/matomo
ls /var/www/matomo

You should see folders such as config, core, plugins and tmp, and the console script. Making www-data the owner of the whole folder lets Matomo write to tmp/ and config/, download geolocation databases to misc/, and use its one-click updater.

Step 4 — Open the firewall and get a certificate

Allow SSH and web traffic, then install Certbot with its Nginx plugin:

Bash
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo apt install certbot python3-certbot-nginx

This uses the Certbot packages from your distribution, which include a renewal timer. The Certbot team recommends its snap instead, as shown in Nginx reverse proxy with Certbot; either works, but install only one of them.

Request a certificate for your Matomo domain. certonly obtains the certificate without changing your Nginx files, and the deploy hook reloads Nginx after every renewal so the new certificate is used:

Bash
sudo certbot certonly --nginx -d matomo.example.com --deploy-hook "systemctl reload nginx"
sudo ls /etc/letsencrypt/live/matomo.example.com/
sudo certbot renew --dry-run

You should see fullchain.pem and privkey.pem, and the dry run should report that renewal would succeed. For more background on Certbot, see Nginx with Certbot.

Step 5 — Configure Nginx with Matomo's configuration

Matomo publishes an Nginx configuration in the matomo-nginx repository. It only passes Matomo's entry scripts to PHP, returns 403 for every other PHP file and blocks the config, tmp, core, lang, libs, vendor, plugins and misc folders.

First create the TLS settings snippet. It uses the session and cipher values from Matomo's ssl.conf, adds TLS 1.3 and leaves out OCSP stapling, because Let's Encrypt stopped running OCSP responders in August 2025:

Bash
sudo nano /etc/nginx/snippets/matomo-ssl.conf
Nginx
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;

Then create the site file:

Bash
sudo nano /etc/nginx/sites-available/matomo.conf

Paste Matomo's configuration with your domain, certificate paths, the snippet and the install path filled in:

Nginx
server {
    listen [::]:80;
    listen 80;
    server_name matomo.example.com;
    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen [::]:443 ssl http2;
    listen 443 ssl http2;
    server_name matomo.example.com;
    access_log /var/log/nginx/matomo.access.log;
    error_log /var/log/nginx/matomo.error.log;

    ssl_certificate /etc/letsencrypt/live/matomo.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/matomo.example.com/privkey.pem;
    include snippets/matomo-ssl.conf;

    add_header Referrer-Policy origin always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;

    root /var/www/matomo/;
    index index.php;

    location ~ ^/(index|matomo|piwik|js/index|plugins/HeatmapSessionRecording/configs)\.php$ {
        include snippets/fastcgi-php.conf;
        try_files $fastcgi_script_name =404;
        fastcgi_param HTTP_PROXY "";
        fastcgi_pass unix:/run/php/php-fpm.sock;
    }

    location ~* ^.+\.php$ {
        deny all;
        return 403;
    }

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ ^/(config|tmp|core|lang) {
        deny all;
        return 403;
    }

    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)$ {
        allow all;
        expires 1h;
        add_header Pragma public;
        add_header Cache-Control "public";
    }

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

    location ~/(.*\.md|LEGALNOTICE|LICENSE) {
        default_type text/plain;
    }
}

Point fastcgi_pass at the versioned PHP-FPM socket you saw in Step 1, enable the site, test the configuration and reload Nginx:

Bash
PHPV=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')
sudo sed -i "s#/run/php/php-fpm.sock#/run/php/php${PHPV}-fpm.sock#" /etc/nginx/sites-available/matomo.conf
grep fastcgi_pass /etc/nginx/sites-available/matomo.conf
sudo ln -s /etc/nginx/sites-available/matomo.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
curl -I https://matomo.example.com/

nginx -t should end with "test is successful", and curl should return HTTP/2 200 for the installer page.

Step 6 — Run the web installer

Open https://matomo.example.com/ in your browser right away: until the installer is finished, anyone who reaches the address could complete it. Follow the screens:

  1. Welcome and System check: fix anything marked as an error, then continue.
  2. Database setup: database server localhost (so PHP connects through the local socket, matching the 'matomo'@'localhost' account), login matomo, the password from Step 2, database name matomo. Keep the default table prefix and adapter.
  3. Superuser: create the single Superuser with a unique username and a long password.
  4. First website: enter the name and URL of the site you want to track.
  5. Tracking code: copy the JavaScript snippet and add it to every page of your site, ideally just before the closing head tag or in a shared header template.

Click Continue to Matomo and sign in. Now force HTTPS in Matomo itself. Open the configuration file that the installer wrote:

Bash
sudo nano /var/www/matomo/config/config.ini.php

Find the existing [General] section and add these two lines inside it, below the lines that are already there:

INI
force_ssl = 1
browser_archiving_disabled_enforce = 1

force_ssl redirects every Matomo request to HTTPS. browser_archiving_disabled_enforce stops reports from being processed when someone views them, which the cron job in the next step takes over. Finally, turn on two-factor authentication for your account under Administration → Personal → Security and store the recovery codes safely.

Matomo sends email reports, user invitations and password reset links through the SMTP server you set under Administration → System → General settings in the Email server settings section, for example host smtp.example.com on port 587 with STARTTLS; test it with sudo -u www-data php /var/www/matomo/console core:test-email [email protected].

Step 7 — Process reports with cron

In Administration → System → General settings, set Archive reports when viewed from the browser to No and Archive reports at most every X seconds to 3600, then save. Create a log folder outside the web root and test the archiver as the web server user:

Bash
sudo install -d -o www-data -g www-data -m 750 /var/log/matomo
sudo -u www-data /usr/bin/php /var/www/matomo/console core:archive --matomo-domain=https://matomo.example.com

A successful run ends with a summary that reports no errors. --matomo-domain replaces the older --url option, which Matomo deprecated in version 5. Now schedule the archiver to run at five minutes past every hour, as Matomo recommends:

Bash
sudo nano /etc/cron.d/matomo-archive
Text
5 * * * * www-data /usr/bin/php /var/www/matomo/console core:archive --matomo-domain=https://matomo.example.com > /var/log/matomo/archive.log 2>&1

The sixth field runs the job as www-data, so the files it creates have the same owner as the rest of Matomo. Check /var/log/matomo/archive.log after the next full hour. If a run ever takes longer than an hour, Matomo suggests running it less often, for example every 2, 6 or 12 hours.

Step 8 — Set up geolocation

Matomo looks up each visitor's country, region and city in a geolocation database stored on your own server, so IP addresses are not sent to an outside service for this. Go to Administration → System → Geolocation:

  1. In the section Setup automatic updates of GeoIP databases at the bottom of the page, let Matomo download the free DB-IP city database, or enter the download URL of a MaxMind GeoIP2 database if you have a MaxMind account.
  2. Choose an update period, weekly or monthly. The updates run as part of the archiving cron job from Step 7.
  3. Select the provider DBIP / GeoIP 2 (Php) and save. It should show as Installed.

The database is stored in /var/www/matomo/misc/, which is why that folder must be writable by www-data. New visits are located from now on; earlier visits keep the location they were given when they were tracked.

Step 9 — Review the privacy settings

Matomo offers several privacy controls under Administration → Privacy. Which ones you need depends on the rules that apply to your websites; this guide only describes what each one does.

  • Anonymize data: select Anonymize Visitors' IP addresses and choose how many bytes to mask (1, 2 or 3, or full masking). You also decide whether geolocation uses the masked address (higher privacy, lower accuracy) or the full one. The same page can replace User IDs with a pseudonym and Regularly delete old raw data while keeping aggregated reports.
  • Users opt-out: copy the opt-out form code into your privacy page. Visitors who opt out get the mtm_consent_removed cookie and are no longer tracked. Matomo marks the Support Do Not Track preference option as deprecated.
  • Consent: if your site asks for consent, add _paq.push(['requireConsent']); (no tracking until consent) or _paq.push(['requireCookieConsent']); (tracking without cookies until consent) at the top of the tracking code, before trackPageView, and call the matching setConsentGiven or rememberConsentGiven functions from your consent banner. To track without any cookies, add _paq.push(['disableCookies']); before trackPageView.
  • GDPR Overview and GDPR Tools: find, export or delete the data of an individual visitor.

Back up and restore

A complete Matomo backup has two parts: the MariaDB database, which holds all tracking data and reports, and the Matomo folder, especially config/config.ini.php, which contains the database login, the salt and the list of enabled plugins. Matomo's backup FAQ uses mysqldump with these options; on MariaDB the same tool is called mariadb-dump:

Bash
sudo mkdir -p /opt/backups && sudo chown $USER:$USER /opt/backups && chmod 700 /opt/backups
sudo mariadb-dump --extended-insert --no-autocommit --quick --single-transaction matomo | gzip > /opt/backups/matomo-db-$(date +%F).sql.gz
sudo tar czf /opt/backups/matomo-files-$(date +%F).tar.gz --exclude=matomo/tmp -C /var/www matomo
ls -lh /opt/backups

The dump contains visitor data, so keep it private and copy it off the server. For databases larger than about 10 GB or more than a million actions a month, Matomo suggests Percona XtraBackup instead of a dump.

To restore on a new server, repeat Steps 1 to 5 (packages, database and user, certificate and Nginx), but unpack your file backup instead of downloading a fresh matomo.zip. Then import the database dump:

Bash
sudo tar xzf /opt/backups/matomo-files-2026-10-09.tar.gz -C /var/www
sudo install -d -o www-data -g www-data /var/www/matomo/tmp
sudo chown -R www-data:www-data /var/www/matomo
gunzip -c /opt/backups/matomo-db-2026-10-09.sql.gz | sudo mariadb matomo

Use the same database name, user and password as in the restored config.ini.php, re-create /etc/cron.d/matomo-archive, and open Matomo to check that your reports are back.

Update Matomo

Read the changelog and back up the database and config/config.ini.php before every update. When a new version is available, Matomo shows a notice in Administration to Superusers; with the ownership from Step 3, you can apply it with the one-click update button.

To update from the command line instead, which Matomo recommends for busier servers, download the new release, copy it over the existing files and run the database upgrade. The archive does not contain config/config.ini.php, so your configuration is kept:

Bash
cd /tmp
rm -rf /tmp/matomo /tmp/matomo.zip
curl -fLO https://builds.matomo.org/matomo.zip
unzip -q matomo.zip
sudo cp -a /tmp/matomo/. /var/www/matomo/
sudo chown -R www-data:www-data /var/www/matomo
sudo -u www-data php /var/www/matomo/console core:update
sudo -u www-data php /var/www/matomo/console diagnostics:unexpected-files

The last command lists files left over from older versions; after reviewing the list, remove them with diagnostics:unexpected-files --delete. Afterwards open Administration → Diagnostics → System check and follow its recommendations. Keep the OS packages current with sudo apt update && sudo apt upgrade as well.

Matomo 6 requires PHP 8.1 or newer and MySQL 8.0 or MariaDB 10.6 or newer. Check php -v and mariadb --version before you move to it, and read its release notes.

Troubleshooting

502 Bad Gateway

Nginx cannot reach PHP-FPM. Compare the socket in grep fastcgi_pass /etc/nginx/sites-available/matomo.conf with the file in ls /run/php/, fix the path, then run sudo nginx -t && sudo systemctl reload nginx. Check that PHP-FPM runs with systemctl status 'php*-fpm' --no-pager.

nginx -t reports that it cannot load the certificate

The certificate for the domain was not issued yet, or the domain in the file does not match it. Run sudo certbot certificates to list existing certificates, fix the DNS record if the challenge failed, and repeat Step 4 before reloading Nginx.

The system check says tmp/ or config/ is not writable

The files are not owned by the PHP-FPM user. Run sudo chown -R www-data:www-data /var/www/matomo and reload the page. If you chose the stricter permissions from the tip in Step 3, make sure tmp/ and config/config.ini.php are still writable.

Reports stay empty or are only updated once a day

Browser archiving is off but the cron job is not running. Check /var/log/matomo/archive.log and grep CRON /var/log/syslog (or journalctl -u cron on Debian), and run the command from Step 7 by hand as www-data to see the error. Make sure /etc/cron.d/matomo-archive ends with a newline.

Matomo warns that it is accessed from an untrusted host

Matomo only accepts the hostnames it knows. If you reach it under a new name, add a line such as trusted_hosts[] = "matomo.example.com" to the [General] section of config/config.ini.php.

Next steps

Frequently asked questions

Should I install Matomo with Docker or the classic way?

Both are official. Matomo's installation guide describes the classic setup with a web server, PHP and MySQL or MariaDB, which this guide follows. The matomo-org/docker project publishes the matomo image on Docker Hub if you prefer containers.

Why do I need a cron job for Matomo?

Matomo turns raw visits into reports in a step called archiving. Without cron, reports are processed when someone opens them, which is slow and loads the database. Matomo recommends cron archiving once a site gets more than a few hundred visits a day.

Does Matomo anonymise IP addresses?

Matomo can mask one, two or three bytes of each IP address, or all of it, under Administration, Privacy, Anonymize data. It can still use the full address for the geolocation lookup on your own server unless you choose to use the masked one.

Which PHP and database versions does Matomo need?

Matomo's requirements page lists PHP 8 and MySQL 5.5 or newer or MariaDB for Matomo 5. Matomo 6.0.0 requires PHP 8.1 or newer and MySQL 8.0 or MariaDB 10.6 or newer, so plan for those versions now.

Which HyperDC servers can run Matomo?

Matomo runs on any HyperDC Linux VPS, VDS or dedicated server with root access and a supported Ubuntu or Debian release. Size it with Matomo's published recommendations for your monthly page views.

Sources

מחולל סיסמאות

Please confirm