Metabase es una herramienta de business intelligence de código abierto que permite consultar bases de datos, crear gráficos y compartir dashboards sin escribir SQL, aunque también admite consultas SQL nativas. En este tutorial desplegarás Metabase en Ubuntu 24.04 con Docker Compose, usando PostgreSQL como base de datos de la aplicación, lo publicarás con Nginx y un certificado de Let's Encrypt, y conectarás una base de datos de negocio con un usuario de solo lectura.

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 vCPU y 4 GB de RAM (Metabase se ejecuta en la JVM y usa 1-2 GB por sí solo).
  • Un usuario no root con privilegios sudo.
  • Docker Engine y el plugin Docker Compose instalados desde el repositorio oficial de Docker.
  • Un dominio o subdominio, por ejemplo metabase.your_domain, con un registro DNS A que apunte a la IP del servidor.
  • Los puertos 80 y 443 accesibles desde Internet.

Paso 1: Preparar el proyecto y los secretos

Metabase guarda usuarios, preguntas, dashboards y credenciales de conexión en su propia base de datos (la "base de datos de la aplicación"). Por defecto usa un archivo H2 dentro del contenedor, que Metabase desaconseja para producción, así que usarás PostgreSQL.

Crea un directorio para el despliegue:

mkdir -p ~/metabase
cd ~/metabase

Genera dos valores aleatorios: la contraseña de PostgreSQL y la clave con la que Metabase cifra las credenciales de las bases de datos conectadas:

openssl rand -hex 24
openssl rand -hex 32

Crea el archivo .env, que Docker Compose lee automáticamente, y pega los dos valores:

nano ~/metabase/.env
POSTGRES_PASSWORD=primer_valor_generado
MB_ENCRYPTION_SECRET_KEY=segundo_valor_generado
MB_SITE_URL=https://metabase.your_domain

Restringe los permisos del archivo, ya que contiene secretos:

chmod 600 ~/metabase/.env

Paso 2: Crear el archivo de Docker Compose

Crea compose.yaml con dos servicios: PostgreSQL para la base de datos de la aplicación y Metabase:

nano ~/metabase/compose.yaml
services:
  metabase-db:
    image: postgres:17
    restart: unless-stopped
    environment:
      POSTGRES_DB: metabase
      POSTGRES_USER: metabase
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - metabase-db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U metabase -d metabase"]
      interval: 10s
      timeout: 5s
      retries: 5

  metabase:
    image: metabase/metabase:latest
    restart: unless-stopped
    depends_on:
      metabase-db:
        condition: service_healthy
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      MB_DB_TYPE: postgres
      MB_DB_DBNAME: metabase
      MB_DB_PORT: 5432
      MB_DB_USER: metabase
      MB_DB_PASS: ${POSTGRES_PASSWORD}
      MB_DB_HOST: metabase-db
      MB_ENCRYPTION_SECRET_KEY: ${MB_ENCRYPTION_SECRET_KEY}
      MB_SITE_URL: ${MB_SITE_URL}
      JAVA_OPTS: "-Xmx2g"
    healthcheck:
      test: ["CMD-SHELL", "curl --fail -I http://localhost:3000/api/health || exit 1"]
      interval: 15s
      timeout: 5s
      retries: 5

volumes:
  metabase-db-data:

Algunos detalles de esta configuración:

  • El puerto se publica solo en 127.0.0.1. Docker añade sus propias reglas de iptables y un puerto publicado en todas las interfaces quedaría abierto aunque UFW lo bloquee; así solo Nginx llega a Metabase.
  • depends_on con service_healthy hace que Metabase no arranque hasta que PostgreSQL acepte conexiones.
  • JAVA_OPTS: "-Xmx2g" limita el heap de Java. Con 4 GB de RAM es un valor razonable; súbelo si el servidor tiene más memoria.
  • latest siempre descarga la última versión estable. Si prefieres controlar las actualizaciones, sustitúyelo por una versión concreta de las publicadas en https://github.com/metabase/metabase/releases.

Paso 3: Arrancar Metabase

Descarga las imágenes y levanta los contenedores:

docker compose up -d

El primer arranque tarda uno o dos minutos, porque Metabase crea su esquema en PostgreSQL. Sigue los logs hasta ver el mensaje de inicialización completa y pulsa Ctrl+C para salir:

docker compose logs -f metabase
metabase-1  | ... INFO metabase.core.core :: Metabase Initialization COMPLETE in 58.2 s

Comprueba el endpoint de salud desde el propio servidor:

curl http://127.0.0.1:3000/api/health
{"status":"ok"}

Paso 4: Publicar Metabase con Nginx y HTTPS

Instala Nginx y Certbot con su plugin para Nginx:

sudo apt update
sudo apt install -y nginx certbot python3-certbot-nginx

Crea un bloque de servidor que reenvíe las peticiones a Metabase:

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

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Activa el sitio, valida la sintaxis y recarga Nginx:

sudo ln -s /etc/nginx/sites-available/metabase /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Si usas UFW, permite SSH y el tráfico web:

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

Solicita el certificado. Certbot modifica el bloque de servidor para servir HTTPS y redirigir HTTP:

sudo certbot --nginx -d metabase.your_domain
Successfully deployed certificate for metabase.your_domain to /etc/nginx/sites-enabled/metabase
Congratulations! You have successfully enabled HTTPS on https://metabase.your_domain

El paquete de Certbot instala un temporizador de systemd que renueva el certificado automáticamente. Puedes probar la renovación con sudo certbot renew --dry-run.

Paso 5: Completar el asistente inicial

Abre https://metabase.your_domain en el navegador. El asistente te pedirá:

  1. El idioma de la interfaz.
  2. Los datos de la cuenta de administrador. Usa una contraseña robusta: esta cuenta tiene acceso a todo.
  3. Tu primera base de datos. Puedes saltar este paso y añadirla después, como se explica a continuación.
  4. Las preferencias de recogida de datos de uso anónimos.

Al terminar llegarás a la página de inicio, con la base de datos de ejemplo de Metabase disponible para explorar.

Paso 6: Conectar una base de datos con un usuario de solo lectura

Metabase solo necesita leer los datos, así que crea un usuario específico sin permisos de escritura. En PostgreSQL, conéctate a la base de datos de negocio como administrador y ejecuta lo siguiente, sustituyendo your_database y la contraseña:

CREATE ROLE metabase_ro WITH LOGIN PASSWORD 'your_strong_password';
GRANT CONNECT ON DATABASE your_database TO metabase_ro;
GRANT USAGE ON SCHEMA public TO metabase_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO metabase_ro;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO metabase_ro;

La última sentencia hace que las tablas que se creen en el futuro también sean legibles por metabase_ro.

La base de datos debe ser accesible desde el contenedor de Metabase. Si está en otro servidor, permite en su firewall solo la IP de tu servidor de Metabase en el puerto correspondiente (5432 en PostgreSQL, 3306 en MySQL). Puedes comprobar la conectividad desde el host con:

nc -zv db_host 5432
Connection to db_host 5432 port [tcp/postgresql] succeeded!

En Metabase, abre el icono del engranaje, entra en Admin settings, sección Databases, y pulsa Add database. Elige el motor, introduce host, puerto, nombre de la base de datos, metabase_ro y su contraseña, y activa SSL si el servidor lo admite. Tras guardar, Metabase sincroniza el esquema y escanea los valores de las columnas; en bases de datos grandes puede tardar unos minutos.

Paso 7: Crear una pregunta y un dashboard

En Metabase, cada consulta guardada se llama pregunta. Para crear una:

  1. Pulsa + New y elige Question.
  2. Selecciona la base de datos y la tabla.
  3. Añade filtros y un resumen, por ejemplo "Count" agrupado por una columna de fecha por mes.
  4. Pulsa Visualize, elige el tipo de gráfico y guarda la pregunta.

Si prefieres SQL, elige SQL query en el menú + New y escribe la consulta directamente.

Para agruparlas en un dashboard, pulsa + New, elige Dashboard, dale un nombre y añade las preguntas guardadas. Puedes añadir filtros de dashboard (por fecha, por categoría) y conectarlos a varias tarjetas a la vez.

Para dar acceso a tu equipo, invita a los usuarios desde Admin settings, sección People, y asígnales grupos. En la sección Permissions decides a qué bases de datos y colecciones puede acceder cada grupo.

Paso 8: Copias de seguridad y actualizaciones

Todo el contenido de Metabase vive en PostgreSQL, así que basta con volcar esa base de datos. Crea una copia comprimida desde el directorio del proyecto:

cd ~/metabase
docker compose exec -T metabase-db pg_dump -U metabase metabase | gzip > "metabase-$(date +%F).sql.gz"

Comprueba que el archivo no está vacío con ls -lh metabase-*.sql.gz y guárdalo fuera del servidor junto con el archivo .env.

Para actualizar Metabase, haz antes una copia y después descarga la nueva imagen y recrea el contenedor. Metabase aplica las migraciones de su esquema al arrancar:

docker compose pull
docker compose up -d

Solución de problemas

Nginx devuelve 502 Bad Gateway. Metabase aún está arrancando o se ha detenido. Revisa docker compose ps y docker compose logs --tail 100 metabase.

El contenedor se reinicia en bucle con errores de conexión a la base de datos. Comprueba que POSTGRES_PASSWORD no ha cambiado desde el primer arranque: PostgreSQL solo aplica esa variable al inicializar el volumen. Si la cambiaste después, vuelve al valor original o cambia la contraseña dentro de PostgreSQL con ALTER ROLE.

java.lang.OutOfMemoryError en los logs. Aumenta -Xmx en JAVA_OPTS sin superar aproximadamente la mitad de la RAM del servidor y ejecuta docker compose up -d.

Los enlaces de los correos o de los dashboards compartidos apuntan a otra URL. Revisa MB_SITE_URL en .env y recrea el contenedor con docker compose up -d.

Conclusión

Tienes Metabase funcionando en Ubuntu 24.04 con PostgreSQL como base de datos de la aplicación, servido por HTTPS a través de Nginx y conectado a tus datos con un usuario de solo lectura. Como siguientes pasos puedes programar la copia con pg_dump mediante un temporizador de systemd, configurar el envío de correo en Admin settings para suscripciones a dashboards y alertas, o activar la caché de resultados para las preguntas más lentas.