Matomo es una plataforma de analítica web de código abierto que ofrece informes comparables a los de Google Analytics, pero con los datos almacenados en tu propio servidor. En este tutorial instalarás Matomo en Ubuntu 24.04 con Nginx, PHP 8.3 y MySQL 8, lo publicarás con HTTPS, activarás el procesamiento de informes por cron y configurarás las opciones de privacidad necesarias para cumplir el RGPD.

Requisitos previos

Para seguir esta guía necesitas:

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 2 GB de RAM y 20 GB libres en disco. Los sitios con mucho tráfico necesitan más memoria y disco para la base de datos.
  • Un usuario no root con privilegios sudo.
  • Un subdominio para Matomo, por ejemplo analytics.example.com, con un registro DNS A apuntando a la IP del servidor. En esta guía se usa your_domain.
  • Los puertos 22, 80 y 443 abiertos.

Paso 1: Instalar Nginx, PHP y MySQL

Matomo necesita PHP con las extensiones de MySQL, GD, XML, cURL y mbstring. Ubuntu 24.04 incluye PHP 8.3, compatible con Matomo 5:

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

Comprueba que PHP-FPM está activo:

systemctl status php8.3-fpm --no-pager
● php8.3-fpm.service - The PHP 8.3 FastCGI Process Manager
     Active: active (running)

El archivado de informes consume bastante memoria. Aumenta el límite de PHP tanto para PHP-FPM como para la línea de comandos, que es la que usará el cron del paso 7:

sudo sed -i 's/^memory_limit = .*/memory_limit = 512M/' /etc/php/8.3/fpm/php.ini /etc/php/8.3/cli/php.ini
sudo systemctl restart php8.3-fpm

Verifica el valor de la línea de comandos:

php -i | grep '^memory_limit'
memory_limit => 512M => 512M

Si usas UFW, abre los puertos web:

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

Paso 2: Crear la base de datos

Ejecuta el asistente de seguridad de MySQL y responde Y a las preguntas:

sudo mysql_secure_installation

Abre la consola de MySQL como root (en Ubuntu se autentica por socket con sudo):

sudo mysql

Crea la base de datos y su usuario. Sustituye your_strong_password por una contraseña robusta:

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;

Comprueba el acceso con el nuevo usuario:

mysql -u matomo -p -e "SELECT CURRENT_USER();"
+-------------------+
| CURRENT_USER()    |
+-------------------+
| matomo@localhost  |
+-------------------+

Paso 3: Descargar Matomo

Descarga la última versión estable desde el servidor oficial de builds y descomprímela en /var/www. El archivo contiene un directorio matomo/:

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

El zip incluye también un archivo How to install Matomo.html fuera del directorio matomo/, que ha quedado en /var/www. No lo necesitas, así que elimínalo:

sudo rm -f "/var/www/How to install Matomo.html"

Comprueba que los archivos principales están en su sitio:

ls /var/www/matomo/index.php /var/www/matomo/console
/var/www/matomo/console  /var/www/matomo/index.php

Matomo necesita escribir en config/ y tmp/; al asignar todo a www-data ya tiene esos permisos. No uses permisos 777.

Paso 4: Configurar Nginx

La configuración recomendada por Matomo solo permite ejecutar los scripts PHP públicos (index.php, matomo.php y los de seguimiento) y bloquea el acceso directo a directorios internos como config/, tmp/ o core/. Crea el bloque de servidor:

sudo nano /etc/nginx/sites-available/matomo
server {
    listen 80;
    listen [::]:80;
    server_name your_domain;

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

    # Solo estos scripts PHP son accesibles desde fuera
    location ~ ^/(index|matomo|piwik|js/index|plugins/HeatmapSessionRecording/configs)\.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }

    # Cualquier otro .php se bloquea
    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 ~ \.(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;
    }
}

El orden importa: Nginx evalúa las expresiones regulares de arriba abajo, de modo que los recursos estáticos de plugins/ (JavaScript, CSS, imágenes) se sirven, y el resto de ese directorio queda bloqueado.

Activa el sitio, desactiva el sitio por defecto y comprueba la sintaxis:

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
nginx: configuration file /etc/nginx/nginx.conf test is successful

Verifica que el directorio de configuración no es accesible:

curl -s -o /dev/null -w '%{http_code}\n' http://your_domain/config/config.ini.php
403

Paso 5: Activar HTTPS con Let's Encrypt

Instala Certbot con su plugin de Nginx y solicita el certificado. Certbot configurará TLS y la redirección de HTTP a HTTPS:

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

Comprueba que la renovación automática funciona:

sudo certbot renew --dry-run
Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/your_domain/fullchain.pem (success)

Paso 6: Completar el asistente de instalación

Abre https://your_domain en el navegador. El asistente de Matomo te guiará por estas pantallas:

  1. Comprobación del sistema: todas las comprobaciones obligatorias deben aparecer en verde. Si falta alguna extensión de PHP, instálala con apt, reinicia php8.3-fpm y recarga la página.
  2. Base de datos: servidor 127.0.0.1, usuario matomo, la contraseña del paso 2, base de datos matomo, prefijo matomo_ y adaptador PDO\MYSQL.
  3. Superusuario: crea la cuenta de administrador con un correo real y una contraseña robusta.
  4. Primer sitio web: nombre, URL y zona horaria del sitio que quieres medir.
  5. Código de seguimiento: Matomo muestra el fragmento de JavaScript de ese sitio.

Al terminar, la configuración queda guardada en /var/www/matomo/config/config.ini.php. Para forzar que el panel se use siempre por HTTPS, edita ese archivo:

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

Añade la línea force_ssl dentro de la sección [General], que ya existe y contiene trusted_hosts[]:

[General]
force_ssl = 1

Paso 7: Programar el archivado de informes

Por defecto, Matomo genera los informes cuando alguien abre el panel, lo que lo vuelve lento con tráfico real. Lo recomendado es desactivar ese comportamiento y procesar los informes cada hora con el comando core:archive.

En el panel, ve a Administración > Sistema > Configuración general y, en Configuración de archivado, marca que los informes no se archiven desde el navegador. Guarda los cambios.

Crea después la tarea programada, que se ejecuta como 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

Lanza el archivado una vez a mano para comprobar que funciona:

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

La salida termina con un resumen de los sitios procesados y sin errores. Si ves Allowed memory size exhausted, aumenta memory_limit en /etc/php/8.3/cli/php.ini.

Paso 8: Añadir el código de seguimiento

Copia el código que muestra Matomo en Administración > Sitios web > Código de seguimiento. Para el sitio con ID 1 tiene esta forma:

<!-- 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 -->

Insértalo antes del cierre de </head> en todas las páginas. Para verificarlo, visita tu web en una ventana privada y abre Visitantes > Visitas en tiempo real en Matomo: la visita aparece en unos segundos, aunque los informes agregados no se actualizarán hasta la siguiente ejecución del archivado.

Para registrar acciones concretas, como un clic en un botón de descarga, envía un evento con categoría, acción y nombre:

<button onclick="_paq.push(['trackEvent', 'Descargas', 'Clic', 'Catálogo PDF']);">Descargar catálogo</button>

Paso 9: Configurar la privacidad para el RGPD

Matomo incluye las opciones de privacidad en Administración > Privacidad. Revisa al menos estas:

  • Anonimizar datos: activa la anonimización de la IP de los visitantes. Enmascarar 2 bytes es un buen equilibrio entre privacidad y precisión de la geolocalización.
  • Eliminar datos antiguos: programa el borrado automático de los registros de visitas en bruto pasado un tiempo (por ejemplo, 180 días). Los informes ya agregados se conservan.
  • Consentimiento: si tu política exige consentimiento previo, añade _paq.push(['requireConsent']); antes de trackPageView y llama a _paq.push(['setConsentGiven']); cuando el usuario acepte.

Paso 10: Programar copias de seguridad

Lo imprescindible es la base de datos y el archivo config/config.ini.php, que contiene la sal usada por Matomo. Crea un script:

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

BACKUP_DIR="/var/backups/matomo"
STAMP="$(date +%F_%H%M)"

mkdir -p "$BACKUP_DIR"
chmod 700 "$BACKUP_DIR"

mysqldump --single-transaction 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

El script se ejecuta como root, que accede a MySQL por socket sin guardar contraseñas. Hazlo ejecutable, pruébalo y prográmalo cada noche:

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

Guarda también copias fuera del servidor.

Actualizar Matomo

Cuando haya una versión nueva, Matomo lo indica en el panel y permite actualizar con un clic desde Administración > Sistema > Actualizar. Haz antes una copia de seguridad. Si la actualización requiere cambios en la base de datos y el sitio tiene mucho tráfico, aplícalos desde la línea de comandos para evitar tiempos de espera del navegador:

sudo /usr/local/bin/matomo-backup
sudo -u www-data php /var/www/matomo/console core:update --yes

Solución de problemas

  • "Hostname de confianza no válido": añade el dominio a trusted_hosts[] en la sección [General] de config/config.ini.php.
  • El panel va muy lento: el archivado desde el navegador sigue activo o el cron no se ejecuta. Revisa el paso 7 y los registros de cron con journalctl -u cron --since today.
  • Los estilos o iconos no cargan: el bloque de recursos estáticos debe ir antes del que bloquea plugins/ en la configuración de Nginx.
  • 502 Bad Gateway: comprueba systemctl status php8.3-fpm y que existe /run/php/php8.3-fpm.sock.

Conclusión

Matomo está instalado en Ubuntu 24.04 con Nginx y HTTPS, con archivado de informes por cron, IP anonimizadas y copias de seguridad diarias. Como siguientes pasos, puedes definir objetivos de conversión, crear usuarios con acceso de solo lectura para tu equipo y configurar el envío de informes por correo con un servidor SMTP.