Matomo is one of the most powerful open-source analytics platforms available, and running it on your own server gives you complete control over your data. This matomo self-hosted setup guide walks you through every step, from installing the required software stack to hardening your instance for production use. If you are building a privacy-first analytics workflow, this tutorial is part of our self-hosted analytics complete guide where we cover the broader landscape of self-hosted solutions.
By the end of this tutorial you will have a fully functional Matomo installation running behind Nginx with SSL, optimized for performance, and configured with GDPR-compliant privacy settings. No third-party data processors, no cloud dependency, just your server and your data.
Prerequisites
Before you begin, make sure you have the following in place:
- A VPS or dedicated server running Ubuntu 22.04 or later (Debian 12 works too with minor adjustments).
- At least 2 GB of RAM and 1 vCPU. For sites with more than 100,000 monthly pageviews, consider 4 GB of RAM.
- A registered domain name (e.g.,
analytics.yourdomain.com) with a DNS A record pointing to your server IP. - Root or sudo access to the server via SSH.
- A basic understanding of the Linux command line.
This guide assumes you are starting from a clean Ubuntu 22.04 server. If you already have Nginx, PHP, or MariaDB installed, skip the relevant parts and adjust accordingly.
Step 1: Install the Stack (Nginx, MariaDB, PHP 8.x)
Matomo requires a web server, a database, and PHP. We will use Nginx as the web server, MariaDB as the database engine, and PHP 8.1 (the default on Ubuntu 22.04) with the extensions Matomo needs.
Start by updating your package lists and installing the core packages:
sudo apt update && sudo apt upgrade -y
Install Nginx
sudo apt install nginx -y
sudo systemctl enable nginx
sudo systemctl start nginx
Install MariaDB
sudo apt install mariadb-server mariadb-client -y
sudo systemctl enable mariadb
sudo systemctl start mariadb
Run the security hardening script to set a root password and remove test databases:
sudo mysql_secure_installation
Answer yes to all prompts: set a root password, remove anonymous users, disallow remote root login, remove the test database, and reload privilege tables.
Install PHP 8.1 and Required Extensions
Matomo needs several PHP extensions for full functionality. Install them all at once:
sudo apt install php8.1-fpm php8.1-mysql php8.1-xml php8.1-curl \
php8.1-gd php8.1-mbstring php8.1-intl php8.1-cli \
php8.1-zip php8.1-bcmath php8.1-opcache -y
Verify PHP is installed and running:
php -v
sudo systemctl status php8.1-fpm
Tune PHP for Matomo
Open the PHP-FPM configuration and adjust a few values that Matomo benefits from:
sudo nano /etc/php/8.1/fpm/php.ini
Find and update these directives:
memory_limit = 256M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 300
date.timezone = UTC
Restart PHP-FPM to apply changes:
sudo systemctl restart php8.1-fpm
Step 2: Create the Database
Matomo stores all analytics data in a MySQL-compatible database. Log in to MariaDB and create a dedicated database and user:
sudo mysql -u root -p
Run the following SQL commands inside the MariaDB prompt:
CREATE DATABASE matomo_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'matomo_user'@'localhost' IDENTIFIED BY 'YourStrongPasswordHere';
GRANT ALL PRIVILEGES ON matomo_db.* TO 'matomo_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Replace YourStrongPasswordHere with a strong, unique password. Save this password because you will need it during the Matomo web installer step.
Important: The utf8mb4 character set is required for Matomo to properly store multilingual content and emoji characters in page titles and custom dimensions.
Step 3: Download and Install Matomo
Download the latest stable release of Matomo directly from the official website. At the time of writing, the latest version is 5.x:
cd /tmp
wget https://builds.matomo.org/matomo-latest.zip
sudo apt install unzip -y
sudo unzip matomo-latest.zip -d /var/www/
This creates a /var/www/matomo directory containing all Matomo files. Now set the correct ownership and permissions so Nginx can read and write to the necessary directories:
sudo chown -R www-data:www-data /var/www/matomo
sudo chmod -R 755 /var/www/matomo
The www-data user is the default user for Nginx and PHP-FPM on Ubuntu. Matomo needs write access to its tmp/, config/, and misc/ directories during installation and normal operation.
Step 4: Configure Nginx
Create a new Nginx server block for your Matomo instance. This configuration handles PHP processing via PHP-FPM and includes security headers:
sudo nano /etc/nginx/sites-available/matomo
Paste the following configuration, replacing analytics.yourdomain.com with your actual domain:
server {
listen 80;
server_name analytics.yourdomain.com;
root /var/www/matomo;
index index.php;
# Limit request body size
client_max_body_size 64M;
# Security headers
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Block access to sensitive directories and files
location ~ ^/(config|tmp|core|lang) {
deny all;
return 403;
}
location ~ /\.ht {
deny all;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_read_timeout 300;
}
location / {
try_files $uri $uri/ =404;
}
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
}
Enable the site and test the Nginx configuration:
sudo ln -s /etc/nginx/sites-available/matomo /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
If nginx -t returns “syntax is ok” and “test is successful,” your configuration is correct.
Step 5: Secure with SSL
Running analytics over plain HTTP exposes tracking data in transit. Use Let’s Encrypt with Certbot to add free SSL encryption:
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d analytics.yourdomain.com
Certbot will ask for your email address (for renewal notifications) and whether to redirect HTTP to HTTPS. Choose to redirect all traffic to HTTPS for the best security posture.
Verify automatic renewal is configured:
sudo certbot renew --dry-run
Certbot adds a systemd timer that handles renewals automatically every 60 days. After SSL is active, your Matomo instance will be accessible at https://analytics.yourdomain.com.
For additional SSL hardening, you can add these directives inside your Nginx server block after Certbot has modified it:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Step 6: Complete the Web Installer
Open your browser and navigate to https://analytics.yourdomain.com. The Matomo installation wizard will launch automatically. Here is what to expect at each stage:
- Welcome screen: Click “Next” to begin the system check.
- System check: Matomo verifies that all required PHP extensions are installed. If everything from Step 1 was installed correctly, you should see all green checkmarks. Address any warnings before proceeding.
- Database setup: Enter the credentials you created in Step 2. Set the database server to
127.0.0.1, the database name tomatomo_db, the username tomatomo_user, and the password you chose. Leave the table prefix asmatomo_. - Super user creation: Create your admin account. Use a strong, unique password and an email address you control. This account has full access to all Matomo settings.
- First website setup: Add the first website you want to track. Enter the site name, URL, and timezone. You can add more websites later from the Matomo admin panel.
- Tracking code: Matomo displays the JavaScript tracking snippet. Copy it now or retrieve it later from Settings > Tracking Code.
After completing the wizard, log in to your new Matomo dashboard. Before adding tracking code to your website, spend a few minutes configuring privacy settings first.
Step 7: GDPR and Privacy Configuration
One of the biggest reasons people choose a matomo self-hosted setup over cloud-based analytics is privacy control. Matomo includes built-in tools that make GDPR compliance straightforward. If you are evaluating analytics tools based on privacy, our comparison of Matomo vs Plausible vs Fathom covers how each platform approaches data protection.
Anonymize IP Addresses
Navigate to Administration > Privacy > Anonymize Data. Enable IP anonymization and set it to mask at least 2 bytes (e.g., 192.168.xxx.xxx). This prevents Matomo from storing full visitor IP addresses. If you mask 3 bytes, tracking becomes fully anonymous but reduces geographic accuracy to country level.
Respect Do Not Track (DNT)
Under Privacy > Users Opt-Out, enable the “Respect Do Not Track” preference. When enabled, Matomo will not track visitors whose browsers send a DNT header. Note that major browsers have been deprecating DNT, so this setting alone is not a complete consent mechanism.
Cookie-Free Tracking
Matomo supports tracking without cookies, which eliminates the need for a cookie consent banner in many jurisdictions. To enable this, add the following line to your tracking code before the trackPageView call:
_paq.push(['disableCookies']);
With cookies disabled, Matomo uses a fingerprinting-free method to estimate unique visitors. This approach aligns well with cookie-free analytics principles and can simplify your legal compliance posture significantly.
Consent Management
If you prefer to use cookies for more accurate returning-visitor tracking, Matomo provides two consent modes:
- Tracking consent: No data is collected until the visitor explicitly consents. Use
_paq.push(['requireConsent'])before the tracking call and_paq.push(['setConsentGiven'])after consent is granted. - Cookie consent: Tracking happens immediately but cookies are only set after consent. Use
_paq.push(['requireCookieConsent'])and_paq.push(['setCookieConsentGiven']).
Data Retention Policies
Go to Administration > Privacy > Data Retention. Configure how long Matomo keeps raw visitor logs and aggregated reports. A common configuration:
- Raw visitor data: Delete after 6 months.
- Aggregated reports: Keep indefinitely (these contain no personal data).
Enable the “Regularly delete old visitor logs” option and set the schedule. This automated purging reduces your database size over time and limits the personal data you retain.
Step 8: Add Tracking to Your Website
With privacy settings configured, it is time to add the tracking snippet to your website. Go to Administration > Tracking Code in Matomo and copy the JavaScript snippet. It looks like this:
<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];
_paq.push(['disableCookies']);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="https://analytics.yourdomain.com/";
_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>
<noscript>
<img referrerpolicy="no-referrer-when-downgrade"
src="https://analytics.yourdomain.com/matomo.php?idsite=1&rec=1"
style="border:0" alt="" />
</noscript>
<!-- End Matomo Code -->
Paste this snippet just before the closing </head> tag of every page you want to track. If you use a CMS like WordPress, add it through your theme’s header template or use a header injection plugin.
Verify Tracking Is Working
After adding the code, visit your website in a browser, then check the Matomo dashboard. Go to Visitors > Real-time to see if your visit appears. If it does not show up within a few seconds, check the following:
- Make sure the site ID in the snippet matches the site ID in Matomo.
- Verify there are no JavaScript errors in your browser console (press F12).
- Confirm that the Matomo URL in the snippet is accessible and not blocked by a firewall.
- If you enabled “Respect Do Not Track,” your browser might be sending a DNT header. Temporarily disable it for testing.
Performance Tuning for Production
The default Matomo configuration works for small sites, but production environments with significant traffic need optimization. Here are the essential tweaks.
Enable Cron-Based Report Archiving
By default, Matomo processes reports when a user views the dashboard. This is slow for sites with lots of data. Switch to cron-based archiving so reports are pre-computed in the background:
First, disable browser-triggered archiving in Administration > System > General Settings. Then add a cron job:
sudo crontab -u www-data -e
Add this line to run archiving every hour:
5 * * * * /usr/bin/php /var/www/matomo/console core:archive --url=https://analytics.yourdomain.com > /dev/null 2>&1
This ensures your dashboard loads instantly because all reports are already computed.
Install the GeoIP2 Database
Accurate geolocation requires a MaxMind GeoIP2 database. Matomo ships with a basic one, but for production accuracy:
- Create a free MaxMind account at
maxmind.com. - Generate a license key in your MaxMind account dashboard.
- In Matomo, go to Administration > System > Geolocation.
- Select “GeoIP 2 (PHP)” as the location provider.
- Enter your MaxMind license key to enable automatic database updates.
Enable OPcache
PHP OPcache stores precompiled script bytecode in memory, which dramatically reduces page load times for Matomo’s PHP-heavy interface. Verify it is enabled:
php -m | grep OPcache
If it is not listed, ensure the php8.1-opcache package from Step 1 is installed. Fine-tune the settings in /etc/php/8.1/fpm/conf.d/10-opcache.ini:
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60
Add a Redis or Memcached Cache Layer
For high-traffic installations, adding a cache layer reduces database queries significantly. Redis is the more popular choice:
sudo apt install redis-server php8.1-redis -y
sudo systemctl enable redis-server
sudo systemctl restart php8.1-fpm
Then edit the Matomo configuration file at /var/www/matomo/config/config.ini.php and add a Redis backend under the [Cache] section:
[Cache]
backend = chained
[ChainedCache]
backends[] = array
backends[] = redis
[RedisCache]
host = "127.0.0.1"
port = 6379
timeout = 0.0
database = 14
This configuration uses a chained cache that first checks a fast in-memory array cache and falls back to Redis. The result is noticeably faster dashboard loading, especially when multiple users access Matomo simultaneously.
Database Optimization
Add these settings to your MariaDB configuration at /etc/mysql/mariadb.conf.d/50-server.cnf under the [mysqld] section for better Matomo performance:
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
max_connections = 100
Set innodb_buffer_pool_size to roughly 50-70% of your available RAM if the server is dedicated to Matomo. Restart MariaDB after making changes:
sudo systemctl restart mariadb
Keeping Matomo Updated
Regular updates are critical for security patches, bug fixes, and new features. Matomo makes this straightforward with its CLI update command.
Before Every Update: Back Up
Always create backups of both your database and Matomo files before updating:
# Back up the database
mysqldump -u matomo_user -p matomo_db > /home/backups/matomo_db_$(date +%Y%m%d).sql
# Back up Matomo files
tar -czf /home/backups/matomo_files_$(date +%Y%m%d).tar.gz /var/www/matomo
Update via the Command Line
The CLI method is more reliable than updating through the web interface, especially for large installations:
cd /var/www/matomo
sudo -u www-data php console core:update
This command checks for available updates, downloads them, and runs any necessary database migrations. You can also update the files manually by downloading the latest release:
cd /tmp
wget https://builds.matomo.org/matomo-latest.zip
sudo unzip -o matomo-latest.zip -d /var/www/
sudo chown -R www-data:www-data /var/www/matomo
cd /var/www/matomo
sudo -u www-data php console core:update
Automate Update Checks
Matomo can notify you about new releases via email. Enable this under Administration > System > General Settings > Update Communication. This way you stay informed about security patches without manually checking.
For the best maintenance workflow, schedule a monthly routine: check for Matomo updates, update PHP packages with apt update && apt upgrade, review log files for errors, and verify that your cron archiving job is running correctly with:
sudo -u www-data php /var/www/matomo/console core:archive --url=https://analytics.yourdomain.com --force-all-websites
Bottom Line
A matomo self-hosted setup gives you a production-grade analytics platform with no ongoing costs beyond your server hosting. You own every byte of visitor data, you control exactly how it is processed, and you can customize the installation to match your specific needs.
The setup process outlined above takes roughly 30 to 45 minutes for the initial installation, plus another 15 minutes for privacy configuration and performance tuning. Once running, Matomo requires minimal maintenance beyond regular updates and occasional database optimization.
If you are comparing self-hosted analytics options before committing, read our Matomo vs Plausible vs Fathom comparison to see how Matomo stacks up on features, performance, and privacy. And for a broader look at the self-hosted analytics landscape, start with our complete self-hosted analytics guide.
The investment in a self-hosted analytics stack pays for itself quickly. You eliminate third-party data dependencies, simplify GDPR compliance, and gain analytics capabilities that rival any commercial platform.
