Despliegue de Apache Superset en un VPS: Docker, PostgreSQL, Redis, SSL y conexión de bases de datos
TL;DR
Apache Superset puede desplegarse en un VPS con Docker Compose, con contenedores independientes para PostgreSQL, Redis, Celery y Caddy: el resultado será una plataforma BI propia y protegida para dashboards, consultas SQL y conexión de bases de datos externas mediante HTTPS.
- Para un despliegue production pequeño, bastan 4 vCPU, 8 GB de RAM y un disco NVMe de 80–120 GB.
- PostgreSQL almacena los metadatos de Superset: usuarios, configuraciones, gráficos, dashboards y conexiones.
- Redis se utiliza como broker de tareas Celery y caché de resultados de consultas.
- Caddy emite y renueva automáticamente los certificados TLS de Let’s Encrypt.
- Las bases de datos analíticas externas se conectan desde la interfaz de Superset o mediante SQLAlchemy URI.
- Para production, establezca obligatoriamente un
SECRET_KEYpermanente, habilite las copias de seguridad de PostgreSQL y restrinja el acceso al servidor mediante reglas de firewall.
Qué configuramos y por qué
Apache Superset es una plataforma BI open-source para trabajar con datos. A través de su interfaz web permite conectar PostgreSQL, MySQL, ClickHouse, Microsoft SQL Server, Trino, BigQuery, Snowflake, DuckDB y decenas de otras fuentes mediante controladores SQLAlchemy. El usuario crea conjuntos de datos, consultas SQL, gráficos, tablas, tarjetas KPI y dashboards interactivos.
En esta guía se desplegará un stack production de Apache Superset en Ubuntu Server 24.04 LTS. Superset se ejecuta en Docker Compose, los metadatos se almacenan en PostgreSQL 16, Redis 7 se utiliza para colas y caché, y Caddy recibe tráfico HTTPS en los puertos 80 y 443. El contenedor web de Superset no se publica directamente en Internet: solo el reverse proxy es accesible externamente.
La arquitectura es adecuada para un equipo pequeño, una startup, la analítica interna de un producto SaaS, una agencia o un departamento con hasta varias decenas de usuarios activos. También resulta práctica para un entorno analítico personal: por ejemplo, cuando los datos de la aplicación se encuentran en PostgreSQL, los eventos se recopilan en ClickHouse y los informes deben proporcionarse a los gerentes sin acceso directo a las bases de datos.
| Componente | Propósito | Acceso externo |
|---|---|---|
| Apache Superset | Interfaz web BI, SQL Lab, gráficos y dashboards | Solo mediante Caddy |
| PostgreSQL 16 | Metadatos de Superset, usuarios, roles, conexiones | No |
| Redis 7 | Celery broker, resultados de tareas, caché | No |
| Celery worker | Consultas asíncronas, informes, tareas en segundo plano | No |
| Caddy | HTTPS, reverse proxy, certificados automáticos | Puertos 80 y 443 |
Qué se obtendrá tras la configuración
Después de completar los pasos, tendrá una URL como https://superset.example.com, protegida por un certificado TLS válido. El administrador podrá crear usuarios, asignarles roles Gamma, Alpha o roles personalizados, registrar bases de datos externas y crear dashboards. Los resultados de consultas largas podrán ejecutarse mediante Celery sin bloquear el proceso web.
PostgreSQL en este esquema no es una base de datos para datos de negocio. Almacena exclusivamente el estado de servicio de Superset. Si elimina su volume sin una copia de seguridad, desaparecerán las cuentas, conexiones de datos, consultas SQL, dashboards, etiquetas y configuraciones. Por ello, PostgreSQL debe respaldarse regularmente, por separado de las imágenes Docker.
Superset self-hosted y BI managed
Los servicios BI cloud-managed se ponen en marcha más rápido: normalmente basta con conectar el almacén de datos e invitar a los empleados. A cambio, la organización entrega al proveedor los metadatos, las consultas SQL, la estructura de las tablas, en ocasiones los resultados analíticos y los datos de usuarios. Además, el coste suele depender del número de editores o visualizaciones.
Apache Superset self-hosted en un VPS requiere administración, actualizaciones y copias de seguridad propias. A cambio, usted controla la topología de red, las versiones, los logs, los roles, el dominio y la ubicación de almacenamiento de los datos. Esto es especialmente útil si la base solo está disponible en la red interna, existen requisitos de localización de datos o la analítica debe funcionar sin depender de un SaaS externo.
Superset normalmente no copia los datos en PostgreSQL de metadatos. Se conecta a la base de datos de origen y ejecuta consultas SQL en nombre de un usuario técnico independiente. Sin embargo, SQL Lab y la caché pueden guardar los resultados durante un tiempo limitado, por lo que los permisos y el período de retención de la caché deben planificarse con antelación.
Qué configuración de VPS se necesita para esta tarea
La carga de Superset depende no solo del número de usuarios. Son más importantes el número de consultas SQL simultáneas, el volumen de resultados, la complejidad de los gráficos, el uso de informes programados y la ubicación de la base analítica. Superset no debe realizar agregaciones pesadas en lugar de ClickHouse, PostgreSQL o un warehouse: los cálculos deben trasladarse a la base de datos de origen, data marts o materialized views.
| Escenario | vCPU | RAM | Disco NVMe | Adecuado para |
|---|---|---|---|---|
| Entorno de pruebas | 2 | 4 GB | 40–60 GB | 1–3 usuarios, sin tareas pesadas |
| Production pequeño | 4 | 8 GB | 80–120 GB | 5–30 usuarios activos |
| Equipo e informes regulares | 6–8 | 16 GB | 160–250 GB | 30–100 usuarios, Celery y caché |
| Alta carga | 8+ | 32 GB+ | 300 GB+ | Varios worker, muchos dashboards |
Para el primer despliegue production, un mínimo práctico es 4 vCPU, 8 GB de RAM, 100 GB NVMe y una conexión de al menos 100 Mbit/s. En este servidor funcionan correctamente Superset, PostgreSQL, Redis, Caddy y uno o dos procesos Celery worker. Deje al menos un 20–30% de espacio libre en disco para PostgreSQL WAL, capas Docker, logs y copias de seguridad antes de subirlas al almacenamiento externo.
Por ejemplo, puede contratar un VPS con las características indicadas, instalar Ubuntu 24.04 LTS y asignar una IPv4 pública estática. Al elegirlo, compruebe que el proveedor no bloquee los puertos entrantes 80 y 443: Caddy los necesita para la validación HTTP del dominio y HTTPS.
Cuándo se necesita un dedicated en lugar de un VPS
Un servidor dedicado tiene sentido si Superset atiende a un gran número de usuarios simultáneos, si en el mismo host se ejecutan analíticas pesadas de ClickHouse o PostgreSQL, si se necesitan 32–128 GB de RAM, IOPS predecibles o un aislamiento estricto de recursos. Dedicated también es preferible ante requisitos de cumplimiento que impidan alojar datos de producción en infraestructura virtualizada.
Sin embargo, si Superset se conecta a un managed PostgreSQL independiente, ClickHouse Cloud, BigQuery o un warehouse remoto, el servidor propio de Superset normalmente no requiere una CPU potente. En este caso, suele bastar un VPS con 4–8 vCPU y 8–16 GB de RAM. Los recursos deben aumentarse después de observar la RAM, la cola de Celery, el tiempo de respuesta y la carga de la base de origen.
Elección de ubicación
La ubicación afecta la latencia entre Superset y las fuentes de datos. Si PostgreSQL o ClickHouse se encuentran en un centro de datos europeo, aloje el VPS de Superset en la misma región o al menos en el mismo país. Una latencia de 2–10 ms casi no afecta a las consultas normales, pero 80–150 ms ralentiza notablemente los filtros interactivos y los dashboards con decenas de widgets.
Si Superset está disponible para empleados de un solo país, elija la ubicación más cercana. Si el acceso está limitado mediante una VPN corporativa, es más conveniente colocar el servidor cerca de la private network o del gateway VPN. No exponga la fuente PostgreSQL a Internet para conectar Superset: es mejor utilizar una red privada, un túnel WireGuard, SSH-tunnel o permitir la IP específica del VPS.
Preparación del servidor
La guía está diseñada para una Ubuntu Server 24.04 LTS limpia con acceso SSH como el usuario root. Antes de empezar, cree un registro DNS de tipo A: superset.example.com debe apuntar a la IPv4 pública del servidor. Caddy no podrá emitir un certificado hasta que el DNS se haya propagado y los puertos 80/443 estén disponibles desde el exterior.
Creación del administrador y actualización del sistema operativo
No ejecute permanentemente el stack Docker como root. Cree un usuario independiente, añádalo a los grupos sudo y docker, y utilícelo para las acciones posteriores.
apt update && apt upgrade -y
apt install -y sudo curl wget ca-certificates gnupg lsb-release \
ufw fail2ban unattended-upgrades jq nano git
adduser deploy
usermod -aG sudo deploy
El comando instala actualizaciones de seguridad, utilidades básicas, firewall y fail2ban, y luego crea el usuario deploy. La contraseña del usuario solo será necesaria como opción de respaldo: las claves SSH deben ser el método principal de acceso.
Configuración de la clave SSH
En el equipo local, cree una clave si aún no la tiene. Para una clave nueva, utilice Ed25519 y establezca una passphrase. A continuación, copie la parte pública al servidor.
ssh-keygen -t ed25519 -a 100 -C "[email protected]"
ssh-copy-id deploy@SERVER_IP
ssh deploy@SERVER_IP
Compruebe que el acceso con el usuario deploy funciona en una terminal independiente. Solo después de esta comprobación deshabilite el acceso root y la autenticación por contraseña. No cierre la sesión root actual hasta confirmar el acceso mediante clave.
sudo nano /etc/ssh/sshd_config.d/99-hardening.conf
Cree un archivo con el siguiente contenido.
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
X11Forwarding no
MaxAuthTries 3
AllowUsers deploy
Compruebe la configuración y reinicie el servicio SSH.
sudo sshd -t && sudo systemctl restart ssh
Firewall y fail2ban
Internet externo solo necesita SSH, HTTP y HTTPS. No abra el puerto 8088 de Superset, el 6379 de Redis ni el 5432 de PostgreSQL: entre los contenedores funcionan en la red interna de Docker.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose
Idealmente, limite SSH a una IP específica de la oficina o a una subred VPN. Si la IP es dinámica, mantenga OpenSSH abierto, pero use únicamente claves y fail2ban.
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
sudo systemctl enable --now unattended-upgrades
Fail2ban bloquea IP tras intentos de inicio de sesión fallidos repetidos. Las actualizaciones automáticas de Ubuntu instalan parches de seguridad, pero las imágenes Docker de Superset, PostgreSQL y Redis deben actualizarse manualmente según un calendario controlado.
Comprobación de recursos antes de la instalación
free -h
df -h /
nproc
curl -4 ifconfig.me
Asegúrese de disponer de al menos 7 GB de memoria RAM para el escenario recomendado, de al menos 70 GB de espacio libre en disco y de que el comando curl devuelva la IP pública esperada. Si la RAM es exactamente de 4 GB, cree una swap de 2–4 GB: no sustituye la memoria, pero puede evitar la finalización inesperada de procesos durante un pico temporal.
Instalación del software: paso a paso
A continuación se utilizan Docker Engine y Docker Compose Plugin del repositorio oficial de Docker. Para 2026, utilice la rama estable actual de Docker Engine 27/28 y Compose v2; las versiones exactas se pueden ver después de la instalación. Para Superset, en el ejemplo se fija la imagen apache/superset:5.0.0. Antes de actualizar en producción, consulte la página de versiones de Apache Superset y el changelog de la etiqueta seleccionada.
Instalación de Docker Engine
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
Los comandos añaden la clave GPG oficial de Docker al almacén de claves del sistema APT.
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
Este bloque añade el repositorio oficial de Docker para Ubuntu 24.04.
sudo apt install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker deploy
newgrp docker
docker version
docker compose version
Después de añadir el usuario al grupo docker, vuelva a iniciar sesión por SSH o ejecute newgrp docker. La pertenencia a este grupo concede de facto privilegios de root en el host, por lo que añada únicamente administradores de confianza.
Creación de la estructura del proyecto
Ubicaremos la configuración en /opt/superset. El directorio contendrá el archivo Compose, las variables de entorno, la configuración de la aplicación, Caddyfile y scripts de mantenimiento. Docker gestionará los volúmenes de Docker por separado.
sudo mkdir -p /opt/superset/{config,caddy,data,backups,scripts}
sudo chown -R deploy:deploy /opt/superset
cd /opt/superset
umask 077
openssl rand -base64 48
openssl rand -hex 24
Los dos últimos comandos generan secretos. Guarde la primera clave aleatoria larga como SUPERSET_SECRET_KEY y use la segunda como contraseña de PostgreSQL. No incluya estos valores en Git, tickets, capturas de pantalla ni chats compartidos.
Creación del archivo de variables
cd /opt/superset
nano .env
chmod 600 .env
Docker Compose leerá el archivo .env, pero no debe estar accesible para otros usuarios del sistema.
SUPERSET_TAG=5.0.0
SUPERSET_SECRET_KEY=PASTE_A_LONG_RANDOM_BASE64_SECRET_HERE
POSTGRES_DB=superset
POSTGRES_USER=superset
POSTGRES_PASSWORD=PASTE_A_LONG_RANDOM_PASSWORD_HERE
POSTGRES_HOST=db
POSTGRES_PORT=5432
REDIS_HOST=redis
REDIS_PORT=6379
SUPERSET_DOMAIN=superset.example.com
[email protected]
TZ=Europe/Moscow
Sustituya el dominio, el email, la zona horaria y ambos secretos. La clave de Superset no se puede cambiar después de iniciar el sistema sin un procedimiento especial de rotación: los valores cifrados, como las contraseñas de conexiones a bases de datos, dejarán de poder descifrarse.
Construcción de una imagen personalizada con controladores
La imagen base de Superset no tiene por qué incluir todos los controladores de las fuentes necesarias. Para PostgreSQL, MySQL y ClickHouse crearemos una pequeña imagen derivada. Si no se necesita un controlador, se puede eliminar del archivo.
nano Dockerfile
nano requirements-local.txt
ARG SUPERSET_TAG=5.0.0
FROM apache/superset:${SUPERSET_TAG}
USER root
COPY requirements-local.txt /tmp/requirements-local.txt
RUN pip install --no-cache-dir -r /tmp/requirements-local.txt
USER superset
psycopg2-binary==2.9.10
pymysql==1.1.1
clickhouse-connect==0.8.15
trino==0.333.0
duckdb-engine==0.13.4
Aquí se añaden controladores para las fuentes más habituales. No instale paquetes sin necesidad: cada controlador amplía la superficie de actualizaciones. Para Microsoft SQL Server puede ser necesario un controlador independiente pymssql o pyodbc y bibliotecas del sistema.
Creación de la configuración de Superset
nano config/superset_config.py
En la siguiente sección se proporcionará el contenido completo de este archivo. Después de crearlo, cree la definición de Compose.
nano compose.yaml
El archivo Compose inicia seis servicios: PostgreSQL, Redis, Superset web, Celery worker, Celery beat y Caddy. El comando docker compose up -d --build construirá la imagen local y creará la red interna.
docker compose config
docker compose build
docker compose up -d
docker compose ps
El comando docker compose config primero comprueba la sintaxis y la sustitución de variables. No continúe con la inicialización hasta que todos los contenedores alcancen el estado running o se comprenda la causa del error mediante los logs.
docker compose logs --tail=100 db
docker compose logs --tail=100 superset
docker compose logs --tail=100 worker
Revisar los logs inmediatamente después del primer inicio ayuda a detectar una contraseña incorrecta de PostgreSQL, un puerto ocupado, un error de controlador Python o falta de memoria antes de configurar el dominio y HTTPS.
Configuración de Superset, PostgreSQL, Redis y SSL
Configuración de la aplicación Superset
El archivo config/superset_config.py se pasa al contenedor como /app/pythonpath/superset_config.py. Define el URI de metadatos, la caché de Redis, Celery, los encabezados de proxy y los límites de carga. Los secretos se obtienen únicamente de las variables de entorno.
import os
from cachelib.redis import RedisCache
SECRET_KEY = os.environ["SUPERSET_SECRET_KEY"]
SQLALCHEMY_DATABASE_URI = (
f"postgresql+psycopg2://{os.environ['POSTGRES_USER']}:"
f"{os.environ['POSTGRES_PASSWORD']}@"
f"{os.environ['POSTGRES_HOST']}:"
f"{os.environ['POSTGRES_PORT']}/{os.environ['POSTGRES_DB']}"
)
REDIS_HOST = os.environ.get("REDIS_HOST", "redis")
REDIS_PORT = int(os.environ.get("REDIS_PORT", "6379"))
REDIS_URL = f"redis://{REDIS_HOST}:{REDIS_PORT}/0"
CACHE_CONFIG = {
"CACHE_TYPE": "RedisCache",
"CACHE_DEFAULT_TIMEOUT": 300,
"CACHE_KEY_PREFIX": "superset_cache_",
"CACHE_REDIS_HOST": REDIS_HOST,
"CACHE_REDIS_PORT": REDIS_PORT,
"CACHE_REDIS_DB": 1,
}
DATA_CACHE_CONFIG = CACHE_CONFIG
class CeleryConfig:
broker_url = REDIS_URL
result_backend = "redis://redis:6379/2"
imports = (
"superset.sql_lab",
"superset.tasks",
"superset.tasks.thumbnails",
"superset.tasks.reports",
)
worker_prefetch_multiplier = 1
task_acks_late = True
beat_schedule = {}
CELERY_CONFIG = CeleryConfig
FEATURE_FLAGS = {
"ALERT_REPORTS": True,
"THUMBNAILS": True,
"DASHBOARD_RBAC": True,
}
ENABLE_PROXY_FIX = True
WTF_CSRF_ENABLED = True
WTF_CSRF_EXEMPT_LIST = []
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = "Lax"
PREFERRED_URL_SCHEME = "https"
SUPERSET_WEBSERVER_TIMEOUT = 120
SQLLAB_TIMEOUT = 300
ROW_LIMIT = 100000
VIZ_ROW_LIMIT = 100000
UPLOAD_FOLDER = "/app/superset_home/uploads"
MAX_CONTENT_LENGTH = 50 1024 1024
TALISMAN_ENABLED = False
El parámetro ENABLE_PROXY_FIX es necesario para que Superset detecte correctamente HTTPS detrás de Caddy y no genere enlaces inseguros. El valor TALISMAN_ENABLED = False simplifica el inicio inicial: al reforzar posteriormente la CSP, configure los encabezados de forma consciente, ya que una Content Security Policy estricta puede bloquear visualizaciones y plugins.
Archivo Compose
Guarde el siguiente archivo como /opt/superset/compose.yaml. Los puertos de PostgreSQL, Redis y Superset no se publican en el host. El único servicio publicado es Caddy.
services:
db:
image: postgres:16.8
container_name: superset-db
restart: unless-stopped
env_file: .env
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
TZ: ${TZ}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 10s
timeout: 5s
retries: 10
networks:
- superset_internal
redis:
image: redis:7.4-alpine
container_name: superset-redis
restart: unless-stopped
command: ["redis-server", "--appendonly", "yes", "--save", "60", "1000"]
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 10
networks:
- superset_internal
superset:
build:
context: .
args:
SUPERSET_TAG: ${SUPERSET_TAG}
image: local/superset:${SUPERSET_TAG}
container_name: superset-web
restart: unless-stopped
env_file: .env
environment:
SUPERSET_CONFIG_PATH: /app/pythonpath/superset_config.py
PYTHONPATH: /app/pythonpath
TZ: ${TZ}
command: ["/usr/bin/run-server.sh"]
volumes:
- ./config/superset_config.py:/app/pythonpath/superset_config.py:ro
- superset_home:/app/superset_home
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
expose:
- "8088"
networks:
- superset_internal
worker:
image: local/superset:${SUPERSET_TAG}
container_name: superset-worker
restart: unless-stopped
env_file: .env
environment:
SUPERSET_CONFIG_PATH: /app/pythonpath/superset_config.py
PYTHONPATH: /app/pythonpath
TZ: ${TZ}
command: ["celery", "--app=superset.tasks.celery_app:app", "worker", "-O", "fair", "-l", "INFO", "-c", "2"]
volumes:
- ./config/superset_config.py:/app/pythonpath/superset_config.py:ro
- superset_home:/app/superset_home
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
networks:
- superset_internal
beat:
image: local/superset:${SUPERSET_TAG}
container_name: superset-beat
restart: unless-stopped
env_file: .env
environment:
SUPERSET_CONFIG_PATH: /app/pythonpath/superset_config.py
PYTHONPATH: /app/pythonpath
TZ: ${TZ}
command: ["celery", "--app=superset.tasks.celery_app:app", "beat", "-l", "INFO"]
volumes:
- ./config/superset_config.py:/app/pythonpath/superset_config.py:ro
- superset_home:/app/superset_home
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
networks:
- superset_internal
caddy:
image: caddy:2.8-alpine
container_name: superset-caddy
restart: unless-stopped
env_file: .env
ports:
- "80:80"
- "443:443"
volumes:
- ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
depends_on:
- superset
networks:
- superset_internal
networks:
superset_internal:
name: superset_internal
volumes:
postgres_data:
redis_data:
superset_home:
caddy_data:
caddy_config:
La persistencia de Redis está habilitada mediante AOF. No es crítica para la caché, pero ayuda a conservar parte del estado de las colas después de un reinicio breve. PostgreSQL sigue siendo la fuente de verdad. El contenedor worker tiene configurada la concurrencia -c 2; en un servidor con 8 GB de RAM, no la aumente sin supervisar la memoria.
Caddy y TLS automático
Cree el archivo /opt/superset/caddy/Caddyfile. Caddy obtendrá automáticamente un certificado de Let’s Encrypt si el DNS ya apunta al servidor y los puertos 80/443 están disponibles.
nano /opt/superset/caddy/Caddyfile
{
email {$LETSENCRYPT_EMAIL}
auto_https on
}
{$SUPERSET_DOMAIN} {
encode zstd gzip
reverse_proxy superset:8088 {
header_up Host {host}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
}
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
}
log {
output stdout
format console
}
}
Después de guardar los archivos, compile e inicie la pila. El primer inicio requiere una inicialización independiente del esquema y la creación de un administrador.
cd /opt/superset
docker compose up -d --build
docker compose exec superset superset db upgrade
docker compose exec superset superset fab create-admin \
--username admin \
--firstname Superset \
--lastname Admin \
--email [email protected] \
--password 'CHANGE_THIS_PASSWORD_NOW'
docker compose exec superset superset init
docker compose restart superset worker beat caddy
El comando superset db upgrade aplica las migraciones de la base de datos de metadatos. create-admin crea un administrador local y superset init crea roles y permisos básicos. Inmediatamente después de iniciar sesión, cambie la contraseña temporal por una contraseña única de un gestor de contraseñas.
Verificación del funcionamiento
docker compose ps
docker compose exec db pg_isready -U superset -d superset
docker compose exec redis redis-cli ping
curl -I http://127.0.0.1
curl -I https://superset.example.com
docker compose logs --tail=100 caddy
La respuesta esperada de Redis es PONG. La solicitud HTTPS debe devolver HTTP/2 200 o HTTP/2 302 a la página de inicio de sesión. Si Caddy devuelve un error de certificado, primero compruebe el DNS, el firewall y los registros con docker compose logs caddy.
Conexión de bases de datos externas
Cree un usuario técnico independiente de solo lectura en cada base de datos analítica. No utilice root, postgres, sa ni el propietario del esquema. Para Superset, normalmente bastan los permisos CONNECT, USAGE en los esquemas necesarios y SELECT en las tablas o views.
Ejemplo para una fuente PostgreSQL. Ejecútelo en el servidor de la base de datos, sustituyendo el nombre de la base de datos, el esquema y la contraseña.
CREATE ROLE superset_reader LOGIN PASSWORD 'LONG_UNIQUE_PASSWORD';
GRANT CONNECT ON DATABASE appdb TO superset_reader;
GRANT USAGE ON SCHEMA analytics TO superset_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA analytics TO superset_reader;
ALTER DEFAULT PRIVILEGES IN SCHEMA analytics
GRANT SELECT ON TABLES TO superset_reader;
En la interfaz de Superset, abra Settings → Database Connections → + Database. Para PostgreSQL, el URI tendrá este aspecto:
postgresql+psycopg2://superset_reader:[email protected]:5432/appdb
Si la contraseña contiene los símbolos @, :, / o #, codifíquela como URL. Por ejemplo, @ se convierte en %40. En la configuración de conexión, active Expose in SQL Lab si los usuarios necesitan SQL Lab y desactive Allow DML si no se requiere editar datos.
Para ClickHouse con el controlador clickhouse-connect, utilice un URI de la siguiente forma:
clickhousedb://superset_reader:[email protected]:8123/analytics
Al conectarse a través de una red pública, active TLS en el lado de la fuente, utilice redes privadas o WireGuard. No almacene contraseñas de producción en descripciones de dashboards, comentarios SQL ni variables que puedan incluirse en una exportación.
Copias de seguridad y mantenimiento
La copia de seguridad mínima de Superset debe incluir la metadata database de PostgreSQL, el archivo .env, compose.yaml, config/superset_config.py, Caddyfile y, si es necesario, el Docker volume superset_home. Lo más importante es el volcado de PostgreSQL: contiene todos los objetos de la interfaz y los datos de conexión cifrados.
No considere un Docker volume como una copia de seguridad. El volume se encuentra en el mismo disco que el servidor y no protegerá contra la eliminación del VPS, un error del administrador, un fallo del sistema de archivos o ransomware. Siga la regla 3-2-1: al menos tres copias, en dos tipos de medios, con una copia fuera del servidor principal.
Script de copia de seguridad de PostgreSQL
El siguiente script crea un volcado comprimido, copia la configuración y después puede enviar el archivo a un almacenamiento compatible con S3 mediante restic. Restic cifra los datos en el cliente; guarde la contraseña del repositorio por separado en un gestor de secretos.
sudo apt install -y restic
mkdir -p /opt/superset/backups
nano /opt/superset/scripts/backup.sh
chmod 700 /opt/superset/scripts/backup.sh
#!/usr/bin/env bash
set -euo pipefail
BASE_DIR="/opt/superset"
DATE="$(date +%F_%H-%M-%S)"
BACKUP_DIR="${BASE_DIR}/backups/${DATE}"
mkdir -p "${BACKUP_DIR}"
cd "${BASE_DIR}"
docker compose exec -T db pg_dump \
-U "${POSTGRES_USER}" \
-d "${POSTGRES_DB}" \
--format=custom \
--no-owner \
--no-privileges \
> "${BACKUP_DIR}/superset_metadata.dump"
tar -czf "${BACKUP_DIR}/config.tar.gz" \
.env compose.yaml Dockerfile requirements-local.txt \
config/superset_config.py caddy/Caddyfile
docker run --rm \
-v superset_superset_home:/source:ro \
-v "${BACKUP_DIR}:/backup" \
alpine:3.20 \
tar -czf /backup/superset_home.tar.gz -C /source .
find "${BASE_DIR}/backups" -mindepth 1 -maxdepth 1 -type d -mtime +3 -exec rm -rf {} \;
export RESTIC_REPOSITORY="s3:s3.amazonaws.com/YOUR_BUCKET/superset"
export RESTIC_PASSWORD_FILE="/root/.config/restic/superset-password"
export AWS_ACCESS_KEY_ID="YOUR_ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="YOUR_SECRET_KEY"
restic backup "${BACKUP_DIR}"
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
Antes de usarlo, reemplace el endpoint de S3, el bucket y las credenciales. No escriba AWS_SECRET_ACCESS_KEY directamente en el script: es mejor colocar las variables en un archivo accesible para root /root/.config/restic/superset-env con permisos 600 y cargarlo mediante source.
Programación de cron y verificación de restauración
sudo crontab -e
30 2 * /opt/superset/scripts/backup.sh >> /var/log/superset-backup.log 2>&1
La copia de seguridad se ejecutará diariamente a las 02:30. No se limite a un mensaje de ejecución correcta: una vez por trimestre, levante un contenedor de prueba de PostgreSQL y restaure el volcado. Solo una restauración exitosa confirma que la copia de seguridad realmente es utilizable.
docker compose exec -T db pg_restore \
-U superset \
-d superset \
--clean --if-exists \
< /path/to/superset_metadata.dump
El comando de restauración no debe ejecutarse en production en funcionamiento sin una ventana de mantenimiento: eliminará y recreará los objetos de la metadata database. Verifique la restauración en un stack de prueba independiente o en una base de datos temporal.
Actualización de Superset y contenedores
Para un solo VPS, use una maintenance window. Una rolling update sin interrupciones requiere al menos dos instancias de Superset detrás de un balanceador, compatibilidad de migraciones y una estrategia independiente para Celery. Para una instalación pequeña, es más seguro informar sobre una breve ventana de mantenimiento, hacer una copia de seguridad, actualizar un componente y realizar un smoke-test.
cd /opt/superset
./scripts/backup.sh
docker compose pull
docker compose build --pull
docker compose up -d
docker compose exec superset superset db upgrade
docker compose exec superset superset init
docker compose logs --tail=100 superset
docker compose ps
No use la etiqueta latest para Superset en production: puede incorporar un cambio incompatible sin una decisión explícita del administrador. Cambie SUPERSET_TAG en .env a una versión concreta probada, revise las release notes y primero reproduzca la actualización en un entorno staging.
Supervisión del estado
Como mínimo una vez por semana, compruebe el espacio libre en disco, los reinicios de contenedores, el tamaño de PostgreSQL y los registros de errores. Un disco lleno de logs o PostgreSQL WAL puede provocar una detención completa de la base de datos.
cd /opt/superset
docker compose ps
docker stats --no-stream
docker system df
df -h
docker compose exec db psql -U superset -d superset -c \
"SELECT pg_size_pretty(pg_database_size('superset'));"
docker compose logs --since=24h superset | grep -iE "error|exception|traceback"
No ejecute sin pensar docker system prune -a en un servidor production: el comando elimina imágenes no utilizadas y puede dificultar una reversión rápida. Use una limpieza controlada después de confirmar que las imágenes antiguas realmente no son necesarias.
Solución de problemas y FAQ
¿Por qué Caddy no emite un certificado TLS y hay un ACME error en los logs?
Primero asegúrese de que el registro A del dominio apunta a la IP del VPS: dig +short superset.example.com debe devolver la dirección del servidor. Luego compruebe que UFW permite 80 y 443, y que otro servidor web no ocupa esos puertos: sudo ss -ltnp | grep -E ':80|:443'. También desactive el proxy DNS mediante CDN durante la primera emisión del certificado o configure DNS challenge. Consulte la causa exacta con el comando docker compose logs caddy.
Superset muestra 500 Internal Server Error después del inicio. ¿Qué comprobar?
Empiece por los logs: docker compose logs --tail=200 superset. Las causas frecuentes son un POSTGRES_PASSWORD incorrecto, migraciones no aplicadas, ausencia de SUPERSET_SECRET_KEY o un error de sintaxis en superset_config.py. Compruebe la disponibilidad de la base de datos mediante docker compose exec db pg_isready -U superset -d superset, luego repita docker compose exec superset superset db upgrade y docker compose exec superset superset init. No cambie SECRET_KEY en una instalación que ya está funcionando.
¿Por qué el contenedor worker se reinicia constantemente?
Revise los logs de worker y Redis: docker compose logs --tail=200 worker redis. Normalmente el problema se debe a una URL de Redis incorrecta, falta de un módulo de Python, un error en la configuración de Celery o falta de memoria. Compruebe docker stats --no-stream y el registro del sistema dmesg -T | grep -i oom. Si el kernel finalizó el proceso mediante OOM killer, reduzca la concurrencia de worker a -c 1, añada RAM o traslade worker a un servidor independiente.
La conexión a una fuente PostgreSQL no funciona, aunque el URI parece correcto. ¿Cómo diagnosticarlo?
Compruebe la accesibilidad de red desde el contenedor de Superset, no desde el equipo local: docker compose exec superset python -c "import socket; print(socket.gethostbyname('db-host'))". Asegúrese de que el firewall de la fuente permite la IP del VPS o la subred privada, y de que existe una regla adecuada en pg_hba.conf. Después, pruebe el usuario directamente mediante psql. Para PostgreSQL externo se necesita un usuario independiente de solo lectura y permisos CONNECT, USAGE y SELECT.
¿Por qué el dashboard funciona lentamente, aunque el VPS apenas tiene carga?
Superset suele esperar una respuesta de una base de datos externa, por lo que una baja carga del VPS no significa un rendimiento normal. Abra SQL Lab, copie la consulta generada y ejecute EXPLAIN ANALYZE en la fuente. Añada índices, cree una vista agregada, materialized view o una tabla con cálculos previos. Reduzca el número de gráficos en una página, configure cache timeout y no muestre cientos de miles de filas en las tablas del navegador.
¿Qué configuración mínima de VPS es adecuada?
Para pruebas bastan 2 vCPU, 4 GB de RAM y 40–60 GB de NVMe, pero es un compromiso: al ejecutar PostgreSQL, Redis, Superset y Celery, la memoria se agota rápidamente. Para un equipo pequeño real, use como mínimo 4 vCPU, 8 GB de RAM y 80–120 GB de NVMe. Si las fuentes de datos son externas y las consultas son moderadas, esto es suficiente para 5–30 usuarios activos. Para informes periódicos y varios worker, planifique 16 GB de RAM.
¿Qué elegir: VPS o dedicated para esta tarea?
Un VPS es adecuado para casi todas las instalaciones pequeñas y medianas de Superset, especialmente cuando los datos analíticos se encuentran en una base de datos independiente, warehouse o servicio managed. Dedicated es necesario cuando hay requisitos altos de CPU, RAM, IOPS y aislamiento: por ejemplo, si Superset, ClickHouse y PostgreSQL con grandes conjuntos de datos se ejecutan en el mismo host. No traslade una base de datos analítica pesada a dedicated solo porque Superset se volvió lento: primero perfile las consultas SQL reales.
¿Se puede abrir Superset directamente en el puerto 8088?
Técnicamente sí, pero es una mala práctica para production. El acceso directo le priva de TLS automático, encabezados HTTP centralizados, gestión adecuada de certificados y una limitación cómoda del tráfico en el reverse proxy. En el archivo Compose, el puerto 8088 no se publica intencionadamente. Mantenga el acceso solo dentro de la red Docker y dirija el tráfico externo a través de Caddy. Si necesita una prueba local temporal, use SSH port forwarding en lugar de abrir el puerto a todo Internet.
Conclusiones y próximos pasos
Ahora Apache Superset funciona en un VPS dentro de un stack Docker aislado con PostgreSQL, Redis, Celery y HTTPS mediante Caddy. Los metadatos están separados de las fuentes analíticas, el acceso está protegido por TLS y las copias de seguridad de PostgreSQL pueden realizarse automáticamente.
- Cree usuarios técnicos de solo lectura para cada base de datos conectada y limite su acceso únicamente a los esquemas y views necesarios.
- Configure los roles de Superset, desactive los permisos innecesarios de SQL Lab y pruebe el acceso de un usuario normal, no solo del administrador.
- Cuando aumente la carga, traslade la metadata database de PostgreSQL a managed PostgreSQL, añada Celery worker independientes y configure la monitorización mediante Prometheus, Grafana o un uptime-check externo.
Antes de una actualización importante de versión, compruebe siempre las migraciones y la restauración de la copia de seguridad en un servidor de prueba. Para una analítica estable, los cambios controlados y los permisos de acceso a los datos son más importantes que el número máximo de componentes instalados.