Tutoriales de VPS
Umami autoalojado en un VPS para analítica web (2026): Docker Compose, PostgreSQL, HTTPS con Caddy y configuración anti bloqueadores de anuncios
Este tutorial explica cómo autoalojar Umami en un VPS y montar un sistema de analítica de visitas ligero y respetuoso con la privacidad. Cubre la elección entre Umami y Plausible, la configuración del VPS, Docker Compose, PostgreSQL, HTTPS con Caddy, el script de seguimiento, las medidas anti bloqueadores de anuncios, las copias de seguridad, las actualizaciones, el endurecimiento de la seguridad y la resolución de problemas habituales.

Umami autoalojado en un VPS para analítica web (2026): Docker Compose, PostgreSQL, HTTPS con Caddy y configuración anti bloqueadores de anuncios
Muchos administradores de sitios empiezan usando Google Analytics directamente. Es gratis, potente y tiene mucha documentación, pero hay varios problemas inevitables: carga lento, los bloqueadores de anuncios lo bloquean, la presión por cumplimiento de privacidad es alta y los datos siempre están en manos de otro.
Si solo quieres saber cuántas visitas recibe tu sitio cada día, de dónde vienen los visitantes y qué páginas son más populares, en realidad no necesitas una plataforma de analítica muy pesada. Umami es más bien una herramienta ligera de analítica web autoalojada: la interfaz es limpia, no depende de cookies, respeta la privacidad por defecto y se ejecuta en un VPS pequeño.
Este artículo trata de cómo desplegar Umami en un VPS. Usaremos Docker Compose para ejecutar Umami y PostgreSQL, y luego Caddy para obtener HTTPS automáticamente. Más adelante también cubriremos el script de seguimiento, las medidas anti bloqueadores de anuncios, las copias de seguridad, las actualizaciones y los problemas habituales.
Entre las opciones habituales de analítica web autoalojada están Umami, Plausible, Matomo y otras.
Matomo es muy completo en funciones, pero relativamente más pesado, más parecido a una plataforma de analítica completa. La experiencia de Plausible es muy buena, pero la Community Edition autoalojada requiere PostgreSQL más ClickHouse, lo que implica mayor consumo de recursos y copias de seguridad más complejas.
Las ventajas de Umami son directas:
- Despliegue sencillo; basta con el contenedor de la aplicación más PostgreSQL.
- Amigable con VPS pequeños; 1 GB de memoria puede ejecutar un sitio ligero.
- Panel limpio; no hace falta aprender informes complejos.
- Soporta analítica de múltiples sitios, adecuado para administradores individuales y equipos pequeños.
- Puedes personalizar el nombre del script de seguimiento para reducir la probabilidad de ser detectado por bloqueadores de anuncios.
- Los datos están en tu propia base de datos, así que las copias de seguridad y migraciones están bajo tu control.
Si tu sitio ya tiene mucho tráfico, o dependes fuertemente del rendimiento de consultas de nivel ClickHouse, Plausible también merece consideración. Pero para la mayoría de usuarios de VPS, Umami encaja mejor en el autoalojamiento ligero, especialmente en máquinas pequeñas con presupuesto limitado.
Umami no es pesado; lo que realmente crece son los datos de visitas en PostgreSQL.
| Escenario | Configuración recomendada |
|---|---|
| Blog personal, sitio de herramientas, web corporativa de bajo tráfico | 1 vCPU / 1 GB RAM / 20 GB SSD |
| Varios sitios, de miles a decenas de miles de PV al día | 2 vCPU / 2 GB RAM / 40 GB SSD |
| Uso en equipo, retención a largo plazo de grandes volúmenes de datos históricos | 2-4 vCPU / 4 GB RAM / 80 GB+ SSD |
Si ya tienes un VPS ejecutando Caddy, Nginx, Uptime Kuma, Vaultwarden o NocoDB, Umami puede ejecutarse junto a ellos como servicio adicional. Pero si esa máquina solo tiene 512 MB de memoria, ten cuidado: PostgreSQL más otros servicios pueden atraer al OOM killer.
Este artículo asume que ya tienes:
- Ubuntu 22.04 / 24.04 o Debian 12.
- Docker y Docker Compose V2.
- Un dominio, por ejemplo
analytics.example.com. - El registro A del dominio ya apunta a la IP pública del VPS.
- Los puertos 80 y 443 abiertos para que Caddy obtenga HTTPS.
Comprueba Docker:
docker version
docker compose version
Si aún no tienes Docker instalado, instálalo primero antes de continuar. Este artículo se centra en Umami en sí y no repite los conceptos básicos de Docker.
Crea el directorio:
sudo mkdir -p /opt/umami
sudo chown -R "$USER":"$USER" /opt/umami
cd /opt/umami
mkdir -p backups caddy-data caddy-config
Genera dos secretos aleatorios:
openssl rand -hex 32
openssl rand -base64 32
El primero se usa como APP_SECRET, el segundo como contraseña de PostgreSQL. APP_SECRET debe mantenerse sin cambios a largo plazo; los reinicios, actualizaciones y migraciones posteriores deben seguir usando el mismo valor; no lo regeneres en cada despliegue.
Crea .env:
nano .env
Escribe el siguiente contenido, sustituyendo el dominio y las contraseñas por los tuyos:
UMAMI_DOMAIN=analytics.example.com
POSTGRES_PASSWORD=replace_with_a_long_database_password
APP_SECRET=replace_with_openssl_rand_hex_32
TRACKER_SCRIPT_NAME=metrics.js
COLLECT_API_ENDPOINT=/api/web-events
Explicación de algunas variables:
UMAMI_DOMAIN: el dominio usado por el proxy inverso de Caddy.POSTGRES_PASSWORD: la contraseña de la base de datos PostgreSQL.APP_SECRET: una cadena aleatoria que Umami usa para proteger los tokens de autenticación; cada instancia debe ser diferente, y no la cambies a la ligera una vez en producción.TRACKER_SCRIPT_NAME: cambia el script de seguimiento predeterminado por un nombre personalizado para reducir la probabilidad de ser detectado por bloqueadores de anuncios.COLLECT_API_ENDPOINT: cambia el endpoint de recolección predeterminado por una ruta personalizada, lo que también puede reducir la coincidencia de reglas.
El archivo .env es un secreto de producción; no lo subas a Git ni lo pongas en un directorio accesible desde la web.
Crea docker-compose.yml:
nano docker-compose.yml
Escribe:
services:
umami:
image: ghcr.io/umami-software/umami:latest
container_name: umami
restart: unless-stopped
env_file:
- .env
environment:
DATABASE_URL: postgresql://umami:${POSTGRES_PASSWORD}@db:5432/umami
APP_SECRET: ${APP_SECRET}
TRACKER_SCRIPT_NAME: ${TRACKER_SCRIPT_NAME}
COLLECT_API_ENDPOINT: ${COLLECT_API_ENDPOINT}
DISABLE_TELEMETRY: "1"
depends_on:
db:
condition: service_healthy
ports:
- "127.0.0.1:3000:3000"
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:3000/api/heartbeat || exit 1"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s
db:
image: postgres:15-alpine
container_name: umami-db
restart: unless-stopped
environment:
POSTGRES_DB: umami
POSTGRES_USER: umami
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- umami-db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U umami -d umami"]
interval: 10s
timeout: 5s
retries: 5
caddy:
image: caddy:2-alpine
container_name: umami-caddy
restart: unless-stopped
env_file:
- .env
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./caddy-data:/data
- ./caddy-config:/config
depends_on:
- umami
volumes:
umami-db-data:
Algunos puntos clave aquí:
umamise enlaza solo a127.0.0.1:3000; el exterior no puede acceder directamente al 3000.- PostgreSQL no mapea el 5432; la base de datos se usa solo dentro de la red de Docker.
- Lo que realmente se expone al exterior son los puertos 80 y 443 de Caddy.
DISABLE_TELEMETRY=1es opcional; actívalo si no quieres participar en la telemetría anónima.
Un enfoque más estable en producción es fijar la versión de la imagen de Umami en lugar de usar latest a largo plazo. Para el primer despliegue puedes usar latest para ponerlo en marcha; para uso formal a largo plazo, se recomienda consultar la versión estable actual en Umami GitHub Release o en el registro de imágenes y luego fijar manualmente la etiqueta.
Crea Caddyfile:
nano Caddyfile
Escribe:
{$UMAMI_DOMAIN} {
encode zstd gzip
reverse_proxy umami:3000
}
Abre el firewall:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload
Si usas un VPS de un proveedor cloud, también debes permitir 80 y 443 en el grupo de seguridad. Muchos fallos de certificados de Caddy terminan siendo porque el grupo de seguridad del cloud no permite los puertos.
Ejecuta:
cd /opt/umami
docker compose up -d
Comprueba los contenedores:
docker compose ps
Comprueba los registros:
docker compose logs -f --tail=100 umami
El primer arranque inicializa la base de datos; esperar uno o dos minutos es normal. Abre en el navegador:
https://analytics.example.com
La cuenta predeterminada es:
用户名:admin
密码:umami
Cambia la contraseña inmediatamente después del primer inicio de sesión. No aplaces este paso; usar la contraseña predeterminada en un servicio público es uno de los incidentes de seguridad más comunes.
Después de iniciar sesión en el panel, haz clic para añadir un sitio web y rellena:
- Nombre del sitio: por ejemplo
My Blog - Dominio: por ejemplo
example.com
Tras guardar, Umami genera un fragmento de seguimiento. Se parece aproximadamente a esto:
<script defer src="https://analytics.example.com/metrics.js" data-website-id="your-website-id"></script>
Colócalo en el <head> de tu sitio web. Para la mayoría de blogs estáticos, temas de WordPress y proyectos Next.js, basta con ponerlo donde se cargue en todas las páginas.
Si solo quieres que el script tenga efecto en un dominio especificado, puedes añadir data-domains:
<script defer src="https://analytics.example.com/metrics.js" data-website-id="your-website-id" data-domains="example.com,www.example.com"></script>
Si quieres respetar la configuración Do Not Track del navegador, puedes añadir:
<script defer src="https://analytics.example.com/metrics.js" data-website-id="your-website-id" data-do-not-track="true"></script>
Después de visitar tu sitio web, vuelve al panel de Umami; los datos suelen aparecer en segundos o decenas de segundos.
Los bloqueadores de anuncios suelen bloquear rutas de scripts de analítica evidentes, como analytics, track, script.js, /api/send y similares.
Umami ofrece dos variables muy prácticas:
TRACKER_SCRIPT_NAME=metrics.js
COLLECT_API_ENDPOINT=/api/web-events
Así el script de seguimiento ya no es el script.js predeterminado, y el endpoint de recolección ya no es la ruta predeterminada. Cambiar solo el nombre del script es incompleto; es mejor cambiar también el endpoint de recolección. No garantiza eludir el 100 % de todas las reglas, pero es más estable que usar directamente las rutas predeterminadas.
Después de modificar .env, reinicia:
docker compose up -d
Luego vuelve a copiar el código de seguimiento generado en el panel, o cambia manualmente la dirección del script en tu sitio web a la nueva ruta.
Nota: no engañes a los usuarios ni eludas elecciones explícitas de privacidad por el bien de la analítica. Si un usuario activa Do Not Track, se recomienda respetarlo.
Si tu dominio de analítica pasa por el proxy de Cloudflare, Umami puede ver la IP del nodo de Cloudflare en lugar de la IP real del visitante.
Puedes especificar la cabecera de IP del cliente en las variables de entorno:
CLIENT_IP_HEADER=CF-Connecting-IP
Luego añade a docker-compose.yml en umami.environment:
CLIENT_IP_HEADER: CF-Connecting-IP
Reinicia Umami después del cambio.
Esta configuración solo es adecuada cuando el tráfico realmente pasa por Cloudflare en todo el recorrido. Si la IP de origen puede eludirse con conexiones directas, no confíes ciegamente en las cabeceras CF-Connecting-IP proporcionadas externamente; es mejor usar un firewall o grupo de seguridad para permitir solo a las IP de origen de Cloudflare acceder a 80/443.
Si no usas Cloudflare, o solo usas resolución DNS, no necesitas configurar esta variable.
Los datos centrales de Umami están todos en PostgreSQL. Lo más importante es exportar la base de datos periódicamente.
Crea un script de copia de seguridad:
nano backup-umami.sh
Escribe:
#!/usr/bin/env bash
set -euo pipefail
APP_DIR="/opt/umami"
BACKUP_DIR="$APP_DIR/backups"
DATE="$(date +%F-%H%M)"
mkdir -p "$BACKUP_DIR/$DATE"
cd "$APP_DIR"
docker exec umami-db pg_dump -U umami umami | gzip > "$BACKUP_DIR/$DATE/umami.sql.gz"
tar czf "$BACKUP_DIR/$DATE/umami-config.tar.gz" docker-compose.yml Caddyfile .env
find "$BACKUP_DIR" -mindepth 1 -maxdepth 1 -type d -mtime +14 -exec rm -rf {} \;
echo "Backup saved to $BACKUP_DIR/$DATE"
Añade permiso de ejecución y prueba:
chmod +x backup-umami.sh
./backup-umami.sh
ls -lh backups
Añade una tarea programada:
crontab -e
Copia de seguridad todos los días a las 3 de la madrugada:
0 3 * * * /opt/umami/backup-umami.sh >> /opt/umami/backups/backup.log 2>&1
Las copias locales solo protegen contra errores, no contra fallos del disco. Un enfoque más fiable es sincronizar también con rclone a almacenamiento de objetos, un NAS u otro VPS.
Antes de restaurar, prepara el mismo docker-compose.yml, Caddyfile y .env. Los comandos de restauración siguientes asumen que la base de datos de destino es una base nueva y vacía; si quieres sobrescribir una instancia existente, detén primero la aplicación y confirma que quieres borrar los datos antiguos, luego reconstruye la base de datos o el volumen, para evitar mezclar datos nuevos y antiguos.
Inicia la base de datos:
cd /opt/umami
docker compose up -d db
sleep 20
Restaura el SQL:
gunzip -c umami.sql.gz | docker exec -i umami-db psql -U umami umami
Luego inicia todos los servicios:
docker compose up -d
Después de restaurar, comprueba:
- Si puedes iniciar sesión en el panel.
- Si existe la lista de sitios web.
- Si los datos históricos de visitas siguen ahí.
- Si el script de seguimiento sigue usando el dominio actual.
Después de escribir el script de copia de seguridad, es mejor usar un VPS de prueba para ensayar una restauración una vez. Una copia de seguridad sin ensayo de restauración solo es consuelo psicológico.
Haz copia de seguridad antes de actualizar:
cd /opt/umami
./backup-umami.sh
Si usas latest:
docker compose pull
docker compose up -d
Comprueba los registros después de actualizar:
docker compose logs --tail=100 umami
La documentación oficial de Umami advierte que tras actualizaciones de versión mayor, las estadísticas de PostgreSQL pueden quedar obsoletas, provocando consultas lentas en instancias grandes. Después de actualizar, puedes entrar en la base de datos y ejecutar:
docker exec -it umami-db psql -U umami -d umami
Luego ejecuta:
ANALYZE;
Este comando actualiza las estadísticas del planificador de consultas de PostgreSQL y normalmente puede ejecutarse de forma segura en línea.
Como mínimo, haz esto:
- Cambia la contraseña predeterminada inmediatamente después de iniciar sesión.
- No expongas 3000 y 5432 a internet público.
- Usa contraseñas fuertes aleatorias para
APP_SECRETy la contraseña de la base de datos. - No pongas
.envni los archivos de copia de seguridad en un directorio web. - Abre solo 80, 443 y los puertos SSH necesarios.
- Actualiza regularmente el sistema y las imágenes de los contenedores.
- Si el panel es solo para ti, puedes añadir otra capa como Cloudflare Access, Tailscale o WireGuard.
- Elimina puntualmente miembros que se van, cuentas de outsourcing y cuentas temporales.
Si compartes Umami con un equipo, también debes prestar atención a los permisos y al aislamiento de sitios. No hagas que todos usen la misma cuenta de administrador.
Primero mira el estado de los contenedores:
docker compose ps
Luego mira los registros de Caddy:
docker compose logs --tail=100 caddy
Comprueba especialmente:
- Si el registro A del dominio es correcto.
- Si el firewall del VPS permite 80/443.
- Si el grupo de seguridad del cloud permite 80/443.
- Si Cloudflare tiene activado un modo de proxy incorrecto.
Al solicitar el certificado por primera vez, se recomienda poner Cloudflare primero en «solo DNS» y activar el proxy según sea necesario después de que funcione.
Mira los registros de la aplicación:
docker compose logs --tail=100 umami
Causas habituales:
- La contraseña de
DATABASE_URLno coincide con la contraseña de inicialización de PostgreSQL. - Se cambió
.env, pero el volumen antiguo de la base de datos todavía tiene la contraseña antigua. - El contenedor
dbaún no está healthy. - Error de indentación en el archivo Compose.
Si cambiaste la contraseña de la base de datos después del primer arranque, el volumen de PostgreSQL no cambia automáticamente. En un entorno de prueba puedes borrar el volumen y empezar de nuevo; en producción debes entrar en la base de datos y cambiar la contraseña.
Abre las herramientas de desarrollador del navegador y comprueba Network:
- Si
metrics.jsse carga correctamente. - Si el endpoint de recolección devuelve 200 o 204.
- Si lo bloquea un bloqueador de anuncios.
- Si el CSP del sitio web prohíbe cargar scripts externos.
- Si
data-website-idse copió mal.
Si usaste data-domains, confirma que el dominio está escrito correctamente, incluyendo www y no www.
Posibles causas:
- Los bloqueadores de anuncios bloquearon algunas solicitudes.
- Los usuarios activaron Do Not Track.
- Tu script solo está en algunas páginas.
- La integración con el enrutamiento SPA o el framework frontend es incorrecta.
- La CDN cacheó el script equivocado.
La analítica web nunca puede ser 100 % precisa. Es más adecuada para ver tendencias que para tomarse como cifras absolutas de nivel financiero.
Primero mira los recursos de los contenedores:
docker stats
Si las consultas de PostgreSQL van lentas, puedes ejecutar el comando mencionado antes:
ANALYZE;
En instancias con mucho tráfico, también considera aumentar la memoria del VPS, acortar la retención de datos o migrar a un servidor de base de datos más potente.
Conclusión simple:
- Sitios pequeños, blogs personales, sitios de herramientas, equipos pequeños: prioriza Umami.
- Mucho tráfico, mucha importancia a informes bonitos e informes por correo: puedes considerar Plausible.
- Quieres algo más ligero, más fácil de respaldar y con menos mantenimiento: prioriza Umami.
- Ya tienes un VPS de 4 GB o más y puedes aceptar ClickHouse: Plausible también está bien.
La versión autoalojada de Plausible requiere PostgreSQL y ClickHouse. ClickHouse tiene un rendimiento de consultas potente, pero para un VPS pequeño es una carga adicional. Las copias de seguridad tampoco consisten solo en exportar un PostgreSQL.
La ventaja de Umami es que es suficientemente ligero y suficientemente simple. Para la mayoría de administradores, poner la analítica en marcha, hacer bien las copias de seguridad y configurar HTTPS es más importante que perseguir un sistema de analítica más complejo.
Comprueba antes del uso formal:
- El dominio ya resuelve al VPS.
- 80/443 están permitidos en el firewall y el grupo de seguridad.
- Umami está enlazado solo a
127.0.0.1:3000. - PostgreSQL no expone el 5432.
- Las contraseñas en
.envyAPP_SECRETse han sustituido. -
APP_SECRETse ha registrado en un gestor de contraseñas y no se regenerará en futuras actualizaciones. - Has iniciado sesión en el panel y cambiado la contraseña predeterminada.
- Has añadido el primer sitio web.
- El script de seguimiento se ha colocado en el
<head>del sitio web. - El panel Network muestra solicitudes de recolección exitosas.
- El script de copia de seguridad se ha ejecutado correctamente.
- Has hecho al menos un ensayo de restauración.
Umami es mejor para responder a estas preguntas: si las visitas subieron hoy, de dónde viene el tráfico de búsqueda, qué artículo es más popular, qué país o región visita más y si la promoción reciente tuvo efecto.
No es adecuado para análisis de comportamiento de usuario muy pesados, y no debería tomarse como la única fuente de datos de negocio. La analítica web es esencialmente una herramienta de tendencias, no una verdad absoluta.
Si ya tienes un VPS, quieres alejarte de Google Analytics y no quieres mantener una pila de analítica más pesada como ClickHouse, Umami es una opción muy adecuada. Es sencillo de desplegar, tiene copias de seguridad claras y usa pocos recursos; para analítica de visitas en blogs, sitios de herramientas, webs corporativas y proyectos de equipos pequeños, es justo lo que hace falta.