I put a Google Analytics tag on sites for years without thinking much about it. Then GDPR happened, and I found myself having to add cookie consent banners, update privacy policies, and explain to clients why visitor data was going to a third party.
Matomo changed the equation. Self-hosted Matomo gives you the same analytics — visitor counts, sessions, page views, conversion goals, heatmaps — with data that stays on your own server. No cookie consent banner required by default, no third-party data access, and no concerns about data leaving your infrastructure.
Fastest path for Lighthouse users: Lighthouse has a pre-built Matomo application image — select it at instance creation and Matomo is fully installed and ready to configure in under 10 minutes. This guide covers both the image path and the manual installation for those who want custom configuration.
I run Matomo on Tencent Cloud Lighthouse. The Matomo application image is the recommended starting point — the entire stack (Nginx + PHP + MySQL + Matomo) is pre-configured when the server provisions. For analytics specifically, Lighthouse's data sovereignty advantage is important: visitor data never leaves your server infrastructure. The CBS cloud disk expansion handles Matomo's growing database as you track more sites and events, and fixed monthly bandwidth pricing means tracking high-traffic sites doesn't add variable costs.
- Key Takeaways
Self-hosting Matomo gives you:
| Requirement | Notes |
|---|---|
| Cloud server | Tencent Cloud Lighthouse — select Matomo application image for instant setup |
| PHP 7.4+ | Pre-installed with the Matomo image |
| MySQL 5.7+ | Pre-installed with the Matomo image |
| 2 GB+ RAM | More RAM = faster report generation |
When ready, open the Lighthouse console → Application Management on the instance:
Done — skip to Part 3 — Matomo Configuration. The manual installation below is only needed if you're adding Matomo to an existing server or need custom PHP configuration.
ssh ubuntu@YOUR_SERVER_IP
sudo apt update && sudo apt upgrade -y
sudo add-apt-repository ppa:ondrej/php -y && sudo apt update
sudo apt install -y nginx php8.2-fpm php8.2-mysql php8.2-xml \
php8.2-gd php8.2-curl php8.2-mbstring php8.2-zip \
php8.2-cli php8.2-intl php8.2-opcache \
mysql-server unzip wget
sudo ufw allow ssh
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo systemctl start mysql && sudo systemctl enable mysql
sudo mysql_secure_installation
sudo mysql
CREATE DATABASE matomo_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'matomo_user'@'localhost' IDENTIFIED BY 'strong_password_here';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX, CREATE TEMPORARY TABLES
ON matomo_db.* TO 'matomo_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
cd /tmp
wget https://builds.matomo.org/matomo-latest.zip
unzip matomo-latest.zip
sudo mv matomo /var/www/matomo
sudo chown -R www-data:www-data /var/www/matomo
sudo find /var/www/matomo -type d -exec chmod 755 {} \;
sudo find /var/www/matomo -type f -exec chmod 644 {} \;
sudo chmod 777 /var/www/matomo/tmp
sudo chmod 777 /var/www/matomo/config
sudo nano /etc/nginx/sites-available/matomo
server {
listen 80;
server_name analytics.yourdomain.com;
root /var/www/matomo;
index index.php;
access_log /var/log/nginx/matomo_access.log;
error_log /var/log/nginx/matomo_error.log;
# Matomo tracking API
location ~ ^/(index|matomo|piwik|js/index|plugins/HeatmapSessionRecording/configs)\.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Deny access to PHP files in subdirectories
location ~* ^.+\.php$ {
deny all;
}
# Static files
location / {
try_files $uri $uri/ =404;
}
# Protect config directory
location ~ ^/config/config\.ini\.php$ {
return 403;
}
# Gzip
gzip on;
gzip_types text/plain text/css application/json application/javascript;
}
sudo ln -s /etc/nginx/sites-available/matomo /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Visit http://analytics.yourdomain.com. The Matomo setup wizard runs:
matomo_usermatomo_dbmatomo_sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d analytics.yourdomain.com
After HTTPS is enabled, update the Matomo config:
In Matomo admin: System → General Settings → Force SSL/HTTPS → Enable.
Matomo generates a JavaScript tracking snippet. Add it to every page you want to track:
<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];
_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>
<!-- End Matomo Code -->
Place this just before the closing </head> tag on every page.
For WordPress: Install the WP-Matomo plugin. Enter your Matomo URL and authentication token.
For Next.js:
// pages/_document.js or app/layout.tsx
<Script
strategy="afterInteractive"
src="https://analytics.yourdomain.com/matomo.js"
/>
Matomo processes raw tracking data into reports via an archiving process. For high-traffic sites, configure this to run via cron instead of on-demand:
In Matomo admin: System → General Settings → Archive Reports:
Then set up cron:
# Edit crontab as www-data user
sudo crontab -u www-data -e
# Add:
5 * * * * /usr/bin/php /var/www/matomo/console core:archive --url=https://analytics.yourdomain.com > /var/log/matomo-archive.log 2>&1
This runs archiving every hour at 5 minutes past. Adjust frequency based on traffic volume.
In Matomo admin: System → General Settings → Performance:
sudo nano /etc/php/8.2/fpm/conf.d/10-opcache.ini
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60
sudo systemctl restart php8.2-fpm
Add to MySQL config for better performance with Matomo's write-heavy workload:
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
innodb_buffer_pool_size = 512M
innodb_flush_log_at_trx_commit = 2
innodb_log_file_size = 128M
By default, Matomo archives reports when someone views the dashboard — which means the first load after a quiet period can be very slow (30+ seconds) for high-traffic sites.
The fix: disable browser-triggered archiving and configure cron archiving instead (see Part 8). This pre-builds reports on a schedule so dashboard loads are fast.
Signs you need cron archiving:
# Run archiving manually
sudo -u www-data php /var/www/matomo/console core:archive --url=https://analytics.yourdomain.com
# Check for updates
sudo -u www-data php /var/www/matomo/console core:update
# Purge old logs (free up disk space)
sudo -u www-data php /var/www/matomo/console privacy:purge-data-subjects
# Export visits to CSV
# Via Matomo admin: Reports → Export
# View database size
mysql -u matomo_user -p -e "
SELECT table_name,
ROUND(data_length/1024/1024, 2) AS data_mb
FROM information_schema.tables
WHERE table_schema = 'matomo_db'
ORDER BY data_length DESC LIMIT 10;"
| Issue | Likely Cause | Fix |
|---|---|---|
| Connection refused | Service not running or wrong port | Check systemctl status SERVICE and verify firewall rules |
| Permission denied | Wrong file ownership or permissions | Check file ownership with ls -la and use chown/chmod to fix |
| 502 Bad Gateway | Backend service not running | Restart the backend service; check logs with journalctl -u SERVICE |
| SSL certificate error | Certificate expired or domain mismatch | Run sudo certbot renew and verify domain DNS points to server IP |
| Service not starting | Config error or missing dependency | Check logs with journalctl -u SERVICE -n 50 for specific error |
| Out of disk space | Logs or data accumulation | Run df -h to identify usage; clean logs or attach CBS storage |
| High memory usage | Too many processes or memory leak | Check with htop; consider upgrading instance plan if consistently high |
| Firewall blocking traffic | Port not open in UFW or Lighthouse console | Open port in Lighthouse console firewall AND sudo ufw allow PORT |
Is self-hosted Matomo GDPR compliant?
Self-hosted Matomo can be configured to be GDPR compliant — no data leaves your server, and many configurations don't require cookie consent banners because no personally identifiable data is collected.
How accurate is self-hosted analytics compared to other services?
Self-hosted analytics that serves tracking scripts from your own domain (avoiding ad blocker detection) often measures more accurately than third-party scripts that are commonly blocked.
How do I add tracking to multiple websites?
Most self-hosted analytics tools support multiple sites from a single installation. Add each site in the admin panel and get a separate tracking code for each.
How much server resource does Matomo need?
Analytics databases grow over time. The 2 vCPU / 4 GB RAM plan handles millions of monthly pageviews. Use CBS cloud disk expansion as the database grows.
Deploy your private analytics today:
👉 Tencent Cloud Lighthouse — PHP-ready Ubuntu VPS
👉 View current pricing and promotions
👉 Explore all active deals and offers