Matomo is an open-source web analytics platform that you host yourself, so visitor data never leaves your server. In this tutorial you will install Matomo on Ubuntu 24.04 with Nginx, PHP-FPM 8.3 and MySQL 8, secure it with a Let's Encrypt certificate, run the web installer, and set up the cron job that pre-processes reports. You will finish with a tracked website and basic privacy settings.

Prerequisites

To follow this guide you need:

  • A server running Ubuntu 24.04 LTS with at least 2 GB of RAM, for example a CubePath VPS. Busy sites (hundreds of thousands of pageviews per month) need more memory and CPU for archiving.
  • A non-root user with sudo privileges.
  • A domain name for Matomo, referred to as your_domain (for example analytics.example.com), with a DNS A record pointing to your_server_ip.

Step 1 - Installing Nginx and opening the firewall

Install Nginx from the Ubuntu repositories:

sudo apt update
sudo apt install nginx

Allow SSH, HTTP and HTTPS through UFW and enable the firewall:

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

Check that Nginx is running:

systemctl status nginx --no-pager
● nginx.service - A high performance web server and a reverse proxy server
     Active: active (running)

Step 2 - Installing PHP 8.3 and the required extensions

Ubuntu 24.04 ships PHP 8.3, which Matomo 5 supports. Install PHP-FPM with the extensions Matomo's system check asks for:

sudo apt install php-fpm php-cli php-mysql php-xml php-mbstring php-curl php-gd php-intl php-zip unzip

Confirm the version and that the extensions are loaded:

php -v
php -m | grep -E 'curl|gd|intl|mbstring|mysqli|pdo_mysql|xml|zip'

Matomo's reports use more memory than PHP's default 128 MB allows on larger sites. Open the PHP-FPM configuration:

sudo nano /etc/php/8.3/fpm/php.ini

Find and set these values:

memory_limit = 512M
max_execution_time = 300

Restart PHP-FPM to apply them:

sudo systemctl restart php8.3-fpm

Step 3 - Creating the MySQL database

Install MySQL server:

sudo apt install mysql-server

Run the hardening script, which removes anonymous users and the test database:

sudo mysql_secure_installation

On Ubuntu the MySQL root account authenticates through the Unix socket, so sudo mysql logs you in without a password. Open the MySQL shell:

sudo mysql

Create a database and a dedicated user. Replace your_strong_password with a password of your own:

CREATE DATABASE matomo CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER 'matomo'@'localhost' IDENTIFIED BY 'your_strong_password';
GRANT ALL PRIVILEGES ON matomo.* TO 'matomo'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Verify that the new user can connect:

mysql -u matomo -p -e 'SHOW DATABASES;'
+--------------------+
| Database           |
+--------------------+
| information_schema |
| matomo             |
| performance_schema |
+--------------------+

Step 4 - Downloading Matomo

Download the latest release from the official build server and extract it to /var/www:

cd /tmp
curl -fLO https://builds.matomo.org/matomo.zip
sudo unzip -q matomo.zip -d /var/www/

The archive creates /var/www/matomo. Give the PHP-FPM user ownership so Matomo can write its configuration, cache and the web-based updater can replace files:

sudo chown -R www-data:www-data /var/www/matomo
ls /var/www/matomo

You should see index.php, matomo.php, matomo.js and directories such as config, core and plugins.

Step 5 - Configuring the Nginx server block

Create a server block for Matomo:

sudo nano /etc/nginx/sites-available/matomo

This configuration follows Matomo's official Nginx recommendations: only the PHP entry points Matomo needs are executed, and internal directories are blocked.

server {
    listen 80;
    listen [::]:80;
    server_name your_domain;

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

    add_header Referrer-Policy origin always;
    add_header X-Content-Type-Options "nosniff" always;

    location ~ ^/(index|matomo|piwik|js/index|plugins/HeatmapSessionRecording/configs)\.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_param HTTP_PROXY "";
        fastcgi_pass unix:/run/php/php8.3-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;
    }
}

Nginx evaluates regex locations in order, so the static file rule comes before the rule that blocks plugins, letting the browser load plugin images and stylesheets while PHP files in those directories stay blocked.

Enable the site, disable the default one, test and reload:

sudo ln -s /etc/nginx/sites-available/matomo /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx

Step 6 - Enabling HTTPS with Let's Encrypt

Install Certbot and request a certificate. Certbot adds the TLS configuration and an HTTP to HTTPS redirect to the server block:

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d your_domain

Check that renewal works:

sudo certbot renew --dry-run

Step 7 - Running the web installer

Open https://your_domain in your browser and follow the installer:

  1. System Check: every item should be green. If an extension is missing, install it with apt, restart php8.3-fpm and reload the page.
  2. Database Setup: server 127.0.0.1, login matomo, the password you set in Step 3, database name matomo, table prefix matomo_, adapter PDO\MYSQL.
  3. Super User: create the administrator account with a strong password and a real email address.
  4. Set up a Website: enter the name and URL of the first site to track and its time zone.
  5. Tracking Code: copy the snippet shown (you can find it later under Administration > Websites > Tracking Code).

When the installer finishes, force HTTPS for the Matomo interface. Open the configuration file it created:

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

Add force_ssl = 1 under the existing [General] section:

[General]
force_ssl = 1

Step 8 - Adding the tracking code to your website

Paste the snippet from the installer just before the closing </head> tag of every page on the tracked site. It looks like this, with your domain and the site ID Matomo assigned:

<!-- Matomo -->
<script>
  var _paq = window._paq = window._paq || [];
  _paq.push(['trackPageView']);
  _paq.push(['enableLinkTracking']);
  (function() {
    var u="https://your_domain/";
    _paq.push(['setTrackerUrl', u+'matomo.php']);
    _paq.push(['setSiteId', '1']);
    var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
    g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
  })();
</script>
<!-- End Matomo Code -->

Visit the tracked site in a browser without an ad blocker, then open Visitors > Visits Log in Matomo. Your visit appears there within seconds.

Step 9 - Scheduling report archiving

By default Matomo builds reports when someone opens the dashboard, which becomes slow as data grows. The recommended setup is to archive from cron and disable browser-triggered archiving. Create a cron file that runs the archiver every hour as www-data:

echo '5 * * * * www-data /usr/bin/php /var/www/matomo/console core:archive --url=https://your_domain/ > /dev/null' | sudo tee /etc/cron.d/matomo-archive

Run the archiver once by hand to confirm it works:

sudo -u www-data php /var/www/matomo/console core:archive --url=https://your_domain/

The command ends with a summary line reporting how many archives were processed and no errors. Then, in Matomo, go to Administration > System > General settings and set Archive reports when viewed from the browser to No.

Step 10 - Reviewing privacy settings

Matomo can run without consent banners in many jurisdictions when it is configured to minimise personal data. Go to Administration > Privacy > Anonymize data and:

  • Enable IP anonymisation and choose to mask at least 2 bytes of the address.
  • Under Regularly delete old raw data, set a retention period for raw visit logs that matches your privacy policy. Aggregated reports are kept.

If you need visitor consent, the tracking code supports _paq.push(['requireConsent']); together with your consent banner. Check the rules that apply to your audience before deciding.

Step 11 - Backing up Matomo

A complete backup is the database plus config/config.ini.php. Create a script:

sudo nano /usr/local/bin/matomo-backup
#!/usr/bin/env bash
set -euo pipefail

backup_dir="/var/backups/matomo"
stamp="$(date +%Y%m%d-%H%M%S)"

mkdir -p "$backup_dir"
mysqldump --single-transaction --quick matomo | gzip > "$backup_dir/matomo-db-$stamp.sql.gz"
cp /var/www/matomo/config/config.ini.php "$backup_dir/config-$stamp.ini.php"
find "$backup_dir" -type f -mtime +14 -delete

It runs as root, so mysqldump authenticates through the socket without a stored password. Make it executable, test it and schedule it nightly:

sudo chmod 750 /usr/local/bin/matomo-backup
sudo /usr/local/bin/matomo-backup
ls -lh /var/backups/matomo
echo '30 2 * * * root /usr/local/bin/matomo-backup' | sudo tee /etc/cron.d/matomo-backup

Copy the backups to another server or object storage regularly.

Updating Matomo

When a new version is available, Matomo shows a notice to the Super User. Take a backup, then use the one-click updater in the interface or update from the command line after replacing the files:

sudo -u www-data php /var/www/matomo/console core:update

Troubleshooting

  • 502 Bad Gateway: PHP-FPM is not running or the socket path is wrong. Check systemctl status php8.3-fpm and that /run/php/php8.3-fpm.sock exists.
  • The system check reports that tmp is not writable: run sudo chown -R www-data:www-data /var/www/matomo again.
  • No visits recorded: check in the browser developer tools that the request to https://your_domain/matomo.php returns 204 or 200, and test without ad blockers.
  • Archiving runs out of memory: raise memory_limit in /etc/php/8.3/cli/php.ini, which is the file the console command uses.

Conclusion

Matomo is now running on Ubuntu 24.04 with Nginx, PHP 8.3 and MySQL, served over HTTPS, archiving reports from cron and backing up nightly. Next, add your other websites under Administration > Websites > Manage, configure goals for the conversions you care about, and install a geolocation database (Administration > System > Geolocation) for accurate country and city reports.