A wizard guides you through the installation itself: system check, database, super user, first website, tracking code. What the wizard does not take care of decides the next few years: whether reports load quickly, whether Matomo sends emails, whether spam distorts the numbers and whether the instance is secure. What runs on which server and what operations involve is covered in Matomo hosting.
Before installing: the concept first
Before the first tracking code is rolled out, a few decisions belong on the table, because later changes usually only apply to new data:
- Which websites? Each property becomes its own website in Matomo with its own time zone and currency. Otherwise new websites get UTC and US dollars.
- Separate development and production. Test and staging environments measure into their own Matomo website so tests do not end up in the real numbers. Matomo Tag Manager has environments for this; besides Live, Dev and Staging are preset.
- Goals, events and e-commerce: what is measured is set by the tracking concept. How events are named is covered in Event tracking.
- Privacy settings: IP masking, retention of raw data, consent. More in Matomo and privacy.
Ways to install
| Way | Good for | Keep in mind |
|---|---|---|
| ZIP package and installation wizard | most own servers | upload via SSH or SFTP, then the setup below |
| Docker | container environments | Docker Compose instead of a single container, archiving as a separate container |
| Installer in the hosting panel | web hosting with Plesk, Softaculous or Installatron | set up the cron job yourself; in Plesk, Matomo advises switching off ModSecurity for the Matomo domain |
| Matomo for WordPress | small WordPress websites | runs inside WordPress, more in WordPress and WooCommerce |
Download the ZIP package from matomo.org, not from third parties, and upload it to the server via SSH or SFTP. The wizard checks the system, creates the tables and asks for the super user and the first website. Matomo recommends a separate database with its own database user. In the last step, it offers to set up a DB-IP geolocation database that updates monthly; without it, Matomo only guesses the country from the browser language. IP masking is switched on by default.
The official Docker image is maintained by the community under the matomo-org umbrella. Matomo recommends Docker Compose; a single container is only meant for testing. The image comes without a cron job; Matomo’s example adds a separate container for archiving. In November 2026 there are images for Matomo 5.14, none for Matomo 6 yet.
Installing from the console is something Matomo itself does not offer. Matomo recommends installs from Git only for development, not for production.
Right after installation
- Archiving via cron. A cron job calls
core:archiveevery hour, as the web server user; the exact line is below. Then switch off browser-triggered archiving under Administration > System > General settings and enforce this in the configuration, so segments do not trigger archiving in the browser either. Why this makes such a difference is covered in Matomo hosting. - Force HTTPS. When Matomo runs over HTTPS,
force_ssl = 1enforces secure access. The wizard enters the trusted hostnames; behind a load balancer or CDN, the proxy headers belong in the configuration. In Matomo 6, both the public and the internal hostname have to be listed there. - Email via SMTP. By default, Matomo sends email via PHP’s
mail()function, which often ends up in spam or does not arrive at all. Under General settings > Email server settings, enter an SMTP server;./console core:test-emailchecks the result. Without working email, neither reports nor alerts arrive. - Upload a logo. Under General settings > Branding settings, your own logo replaces the Matomo logo in the interface and in email reports.
- Set up the websites. Time zone and currency per website, e-commerce switched on where there is a shop, and parameters excluded from addresses that carry sessions or personal details. Matomo removes click IDs such as gclid and fbclid by itself.
- System check. Under Administration > Diagnostic > System check or with
./console diagnostics:run, Matomo shows what is still missing: cron, write permissions, database, PHP settings, protected directories.
The cron job for archiving
On a Linux server, one file under /etc/cron.d/ is enough, for example /etc/cron.d/matomo-archive. It starts archiving every hour at minute five, as the web server user (www-data on Debian and Ubuntu), and writes the output to a log file:
# Matomo: archive reports every hour
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
Adapt the PHP and Matomo paths, the address and the user to your server; the log directory has to belong to that user. In a crontab without a user column, for example with crontab -u www-data -e, www-data drops out of the line. In Plesk it is a scheduled task, in a Docker setup a separate container.
Then switch off browser-triggered archiving. You can do this in the interface or directly in config/config.ini.php:
[General]
enable_browser_archiving_triggering = 0
browser_archiving_disabled_enforce = 1
time_before_today_archive_considered_outdated = 3600
The second line makes sure segments do not trigger archiving in the browser either. The third recalculates today’s reports at most once an hour, which Matomo recommends for medium and high traffic. The system check shows whether the cron job runs: it warns when the last run is older than one day.
Plugins that belong from the start
Alerts for outages. Without an alert, a tracking outage only comes to light when numbers are missing. Matomo’s free Custom Alerts plugin sends an email when a metric crosses a threshold. Feinwerk Sentinel checks each website’s data every hour and also reports problems in Slack or Microsoft Teams.
Set up Tracking Spam Prevention. For Matomo 5, the plugin is free in the Marketplace; in Matomo 6 it is built in and active by default. It is worth going through the settings once:
- Block cloud provider networks, with Matomo’s maintained list.
- Block headless browsers that identify themselves as such.
- Limit actions per visit: by default Matomo records all of them; according to Matomo, most websites have no more than 100 to 300. An email address gets notified about blocked IP addresses.
- Block SDKs and server-side libraries, but only if only the tracking code or the Tag Manager measures.
- Countries and IP lists: only allow or exclude certain countries, allow or block individual networks.
This is basic protection against obvious automation, not spam protection. Bots that come with a real browser from other networks are only detected by a plugin such as Feinwerk Tracking Spam Score. More in Matomo 6.
Campaign reports: by default, Matomo only shows name and keyword for campaigns. Matomo’s free Marketing Campaigns Reporting plugin adds source, medium, content, campaign ID, group and placement, each with reports and segments, for mtm and utm parameters. It belongs in before the first campaigns, because Matomo only stores these fields once the plugin is active. How campaign links are built is covered in Campaign tracking.
For high traffic: the free QueuedTracking plugin buffers tracking requests in Redis or MySQL and writes them to the database in batches.
Security from day one
- Two-factor authentication for all users, enforceable under General settings. It does not cover requests with an API token; how tokens stay safe is covered in API, MCP and OAuth.
- Protected directories: for Apache, Matomo creates
.htaccessfiles that lockconfig,core,langandtmp; this needsAllowOverride All. nginx needs its own rules; both are in the next section. - Keep write permissions tight: files 644, directories 755, never 777. Matomo mainly needs to write to
tmp. - Secure the sign-in: after 20 failed attempts in 60 minutes, Matomo blocks the IP address. A list of allowed IP addresses can be set in the configuration and then also applies to the API.
- Leave plugin upload off: Matomo itself warns that uploading plugins through the interface allows third-party code to run.
More on hardening server and Matomo in the service Security and hardening.
Web server rules for Apache and nginx
Matomo sits in the web root, but not everything in it may be reachable from outside. config holds the database password, tmp holds caches and session data. Only a few files need to be reachable: the interface via index.php, tracking via matomo.php and matomo.js (plus the old names piwik.php and piwik.js) and the Tag Manager containers under js/.
Apache: Matomo creates the rules itself, as .htaccess files. They lock config, core, lang and tmp completely and let only images, scripts, styles and fonts through in libs, vendor, plugins, misc and node_modules. For Apache to read them, the directory needs AllowOverride All. If they are missing, ./console core:create-security-files creates them again. A basic virtual host, with a second lock in case an .htaccess is missing:
<VirtualHost *:80>
ServerName matomo.example.com
Redirect permanent / https://matomo.example.com/
</VirtualHost>
<VirtualHost *:443>
ServerName matomo.example.com
DocumentRoot /var/www/matomo
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/matomo.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/matomo.example.com/privkey.pem
<Directory /var/www/matomo>
# Matomo ships its own .htaccess files
AllowOverride All
Options -Indexes
Require all granted
</Directory>
# Second lock in case an .htaccess is missing
<DirectoryMatch "^/var/www/matomo/(config|core|lang|tmp|\.git)(/|$)">
Require all denied
</DirectoryMatch>
</VirtualHost>
nginx does not read .htaccess files, so the rules belong in the configuration. Matomo maintains a template for this. Its core: only the PHP files Matomo needs from outside are executed, all others answer with 403, and the protected directories are locked. In shortened form:
server {
listen 80;
server_name matomo.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on; # nginx 1.25.1 or later; older versions: listen 443 ssl http2;
server_name matomo.example.com;
root /var/www/matomo;
index index.php;
ssl_certificate /etc/letsencrypt/live/matomo.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/matomo.example.com/privkey.pem;
add_header Referrer-Policy origin always;
add_header X-Content-Type-Options "nosniff" always;
# Only execute these PHP files
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/php8.3-fpm.sock; # path to your PHP version
}
# Block all other PHP files
location ~* ^.+\.php$ { deny all; return 403; }
location / { try_files $uri $uri/ =404; }
# Protected directories and hidden files
location ~ ^/(config|tmp|core|lang) { deny all; return 403; }
location ~ /\.(ht|git) { deny all; return 403; }
# Do not cache Tag Manager preview containers
location ~ js/container_.*_preview\.js$ {
expires off;
add_header Cache-Control 'private, no-cache, no-store';
}
# Allow static files, also in plugins and vendor
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 Cache-Control "public";
}
# The rest of these directories stays locked
location ~ ^/(libs|vendor|plugins|misc|node_modules) { deny all; return 403; }
# Serve text files in the root directory as text
location ~ /(.*\.md|LEGALNOTICE|LICENSE) { default_type text/plain; }
}
Order matters: nginx checks regular-expression locations in sequence, which is why the rule allowing static files comes before the lock on plugins and vendor. Adapt TLS settings, certificates and the PHP path to your server. The system check then shows whether everything works: it requests protected files such as config/config.ini.php from outside and reports if they are reachable.
If you additionally restrict the interface to certain IP addresses, leave tracking open: matomo.php, matomo.js, the old piwik files, the containers under js/ and the opt-out page must stay reachable for all visitors.
Updates via the console
The one-click update is convenient but needs write permissions for the whole Matomo directory. For larger instances, Matomo recommends the console:
- Back up database and code, free space on the database server.
- Put the interface into maintenance mode and pause tracking:
./console config:set General.maintenance_mode=1andTracker.record_statistics=0. ./console core:update --yeson a single server.- Clear caches, switch tracking and interface back on, look at the system check.
./console diagnostics:unexpected-filesfinds files that no longer belong to the release.
Plugins are updated separately, through the Marketplace or the console. What the move to Matomo 6 adds is covered in Matomo 6.
How Matomo gets off to a good start
- Concept first Websites, environments, goals and privacy before the first code.
- Cron from day one Reports are ready in advance, even with more traffic.
- Email and alerts SMTP set up, outages come to light at once.
- Hardened and current Two factors, protected directories, updates via the console.
Typical pitfalls
- Archiving in the browser Reports get slow as traffic grows.
- mail() instead of SMTP Reports and alerts do not arrive.
- Tests in the real numbers Staging measures into the production website.
- Open directories Under nginx without Matomo's rules, config can be read from outside.
Sources
As of 13 November 2026, Matomo 5.14 and 6.0.0-rc1
- Matomo: Installing Matomo
- Matomo: Securing access to the installer
- Matomo: Installing with Docker
- Matomo: Installing with Plesk
- Matomo: Setting up auto-archiving via cron
- Matomo: Forcing HTTPS
- Matomo: Matomo behind a proxy
- Matomo: Email via SMTP
- Matomo: Configuring Matomo for security
- Matomo: Enforcing two-factor authentication
- Matomo: Updating Matomo
- Matomo: Updates for high-traffic servers
- Matomo Marketplace: Custom Alerts
- Matomo Marketplace: Tracking Spam Prevention
- Matomo Marketplace: QueuedTracking
- GitHub: nginx configuration for Matomo
