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
- Prerequisites
- Step 1 — Install Nginx, PHP-FPM and MariaDB
- Step 2 — Create the database and user
- Step 3 — Download Matomo
- Step 4 — Open the firewall and get a certificate
- Step 5 — Configure Nginx with Matomo's configuration
- Step 6 — Run the web installer
- Step 7 — Process reports with cron
- Step 8 — Set up geolocation
- Step 9 — Review the privacy settings
- Back up and restore
- Update Matomo
- Troubleshooting
- 502 Bad Gateway
- nginx -t reports that it cannot load the certificate
- The system check says tmp/ or config/ is not writable
- Reports stay empty or are only updated once a day
- Matomo warns that it is accessed from an untrusted host
- 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
sudorights. 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.comwith 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:
| Resource | Minimum (official) | Suggested starting point |
|---|---|---|
| CPU | 2 CPU (up to 100,000 page views a month) | 4 CPU for up to 1 million page views a month |
| Memory | 2 GB RAM | 8 GB RAM for up to 1 million page views a month |
| Disk | 50 GB SSD | 250 GB SSD for up to 1 million page views a month |
| PHP | PHP 8 for Matomo 5; 8.1 or newer for Matomo 6 | The PHP 8 release from your distribution |
| Database | MySQL 5.5+ or MariaDB for Matomo 5; MySQL 8.0+ or MariaDB 10.6+ for Matomo 6 | MariaDB 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):
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 curlInstalling 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:
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:
openssl rand -hex 24
sudo mariadbOn 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:
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:
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/matomoYou 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:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo apt install certbot python3-certbot-nginxThis 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:
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-runYou 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:
sudo nano /etc/nginx/snippets/matomo-ssl.confssl_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:
sudo nano /etc/nginx/sites-available/matomo.confPaste Matomo's configuration with your domain, certificate paths, the snippet and the install path filled in:
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:
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:
- Welcome and System check: fix anything marked as an error, then continue.
- Database setup: database server
localhost(so PHP connects through the local socket, matching the'matomo'@'localhost'account), loginmatomo, the password from Step 2, database namematomo. Keep the default table prefix and adapter. - Superuser: create the single Superuser with a unique username and a long password.
- First website: enter the name and URL of the site you want to track.
- Tracking code: copy the JavaScript snippet and add it to every page of your site, ideally just before the closing
headtag 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:
sudo nano /var/www/matomo/config/config.ini.phpFind the existing [General] section and add these two lines inside it, below the lines that are already there:
force_ssl = 1
browser_archiving_disabled_enforce = 1force_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:
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.comA 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:
sudo nano /etc/cron.d/matomo-archive5 * * * * www-data /usr/bin/php /var/www/matomo/console core:archive --matomo-domain=https://matomo.example.com > /var/log/matomo/archive.log 2>&1The 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:
- 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.
- Choose an update period, weekly or monthly. The updates run as part of the archiving cron job from Step 7.
- 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_removedcookie 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, beforetrackPageView, and call the matchingsetConsentGivenorrememberConsentGivenfunctions from your consent banner. To track without any cookies, add_paq.push(['disableCookies']);beforetrackPageView. - 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:
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/backupsThe 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:
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 matomoUse 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:
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-filesThe 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
- Compare a lighter, cookie-free alternative: How to install Umami or Plausible Community Edition.
- Learn more about Certbot and Nginx in Nginx with Certbot.
- Track a WordPress site you host yourself: WordPress on a LEMP stack.
- See servers for self-hosted analytics on the web analytics hosting page.
- Harden the installation further with Matomo's security recommendations.
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
- matomo.org/faq/on-premise/matomo-requirements
- matomo.org/faq/on-premise/installing-matomo
- matomo.org/faq/how-to-install/faq_23484
- matomo.org/faq/how-to-install/install-php-on-linux-for-matomo
- github.com/matomo-org/matomo-nginx
- raw.githubusercontent.com/matomo-org/matomo-nginx/master/sites-avai…
- raw.githubusercontent.com/matomo-org/matomo-nginx/master/ssl.conf
- matomo.org/faq/on-premise/how-to-set-up-auto-archiving-of-your-reports
- matomo.org/faq/how-to/setting-up-accurate-visitors-geolocation
- matomo.org/faq/general/configure-privacy-settings-in-matomo
- developer.matomo.org/guides/tracking-consent
- matomo.org/faq/general/faq_157