bolt Valebyte VPS desde $4/mes — NVMe, despliegue en 60s.

Obtener VPS arrow_forward
eco Principiante Tutorial/Cómo hacer

Instalación de Kestra en un VPS: orquestación de tareas, Docker, PostgreSQL, SSL y programación de tareas

calendar_month Oct 26, 2026 schedule 18 min de lectura visibility 106 vistas
Установка Kestra на VPS: оркестрация задач, Docker, PostgreSQL, SSL и расписания
info

¿Necesitas un servidor para esta guía? Ofrecemos servidores dedicados y VPS en más de 50 países con configuración instantánea.

¿Necesitas un VPS para esta guía?

Explore otras opciones de servidores dedicados en

Instalación de Kestra en un VPS: orquestación de tareas, Docker, PostgreSQL, SSL y programaciones

Resumen

Kestra es una plataforma self-hosted para la orquestación de tareas, pipelines ETL, automatización de API y programaciones. En esta guía desplegará Kestra en un VPS con Ubuntu mediante Docker Compose, conectará PostgreSQL, protegerá la interfaz con el proxy HTTPS Caddy, creará su primer workflow con una programación cron y configurará copias de seguridad.

  • Para una instancia pequeña de production basta con un VPS con 2 vCPU, 4 GB de RAM y 40–60 GB de NVMe.
  • Kestra y PostgreSQL se ejecutarán en contenedores Docker independientes.
  • Caddy emitirá y renovará automáticamente el certificado TLS de Let’s Encrypt.
  • Todas las contraseñas se almacenarán en el archivo .env, no en Docker Compose ni en el workflow.
  • El primer workflow se ejecutará manualmente y según una programación cron.
  • Las copias de seguridad de PostgreSQL y la configuración se ejecutarán mediante cron y se enviarán a un almacenamiento externo.

Qué configuramos y por qué

Esquema: Qué configuramos y por qué
Esquema: Qué configuramos y por qué

Kestra es una plataforma de orquestación en la que las tareas se describen mediante archivos YAML declarativos. Es adecuada para ejecutar procesos ETL, procesar archivos, sincronizar servicios SaaS, realizar llamadas a API, generar informes periódicos, mantener la infraestructura, ejecutar scripts de Python, consultas SQL y jobs en contenedores.

A diferencia de un simple cron, Kestra almacena el historial de ejecuciones, los parámetros, los logs, los estados de las tareas, los errores y los reintentos. La interfaz web permite ejecutar workflows manualmente, transmitir datos de entrada, revisar la ejecución paso a paso y volver a ejecutar procesos fallidos.

Después de completar las instrucciones, en el servidor funcionarán los siguientes componentes:

  • Kestra Server con interfaz web y API;
  • PostgreSQL 16 como base de datos fiable para workflows, colas, execution history y metadatos;
  • Docker Compose para gestionar los servicios;
  • Caddy como reverse proxy con HTTPS automático;
  • Firewall UFW, claves SSH y Fail2ban para la protección básica del VPS;
  • backup periódico de PostgreSQL, la configuración y los datos persistentes de Kestra;
  • un ejemplo de workflow con ejecución manual y programación cron.

Qué se puede automatizar mediante Kestra

Escenario Ejemplo de workflow Frecuencia de ejecución
ETL y analítica Obtener un CSV de S3, limpiar los datos y cargarlos en PostgreSQL Cada hora o diariamente
Automatización DevOps Comprobar las copias de seguridad, recopilar métricas y enviar una notificación Cada 15 minutos
Integraciones SaaS Obtener leads de un formulario y crear un registro en el CRM Mediante webhook o cada 5 minutos
Procesamiento de archivos Convertir los PDF cargados, extraer el texto y guardar el resultado Por evento
Informes Ejecutar SQL, generar un informe y enviarlo a Telegram o por email Los días laborables a las 09:00

Kestra cloud-managed o self-hosted

La versión Managed libera al equipo de las tareas de actualización, almacenamiento de datos y escalado, pero añade un pago periódico y dependencia de una plataforma externa. Kestra self-hosted en un VPS requiere una configuración inicial, pero permite controlar la ubicación de almacenamiento de datos, los límites, las reglas de red, los plugins, las direcciones IP salientes y los costes.

La opción self-hosted resulta especialmente conveniente si los workflows trabajan con bases de datos internas, API privadas, repositorios Git cerrados o documentos sensibles. El servidor puede ubicarse en la jurisdicción necesaria, conectarse a una red VPN y restringir el acceso al panel por IP o mediante autenticación HTTP adicional.

No utilice la base de datos H2 integrada de Kestra para un despliegue en production. Es adecuada para el desarrollo local y las pruebas, pero para un VPS con programaciones reales, registros y varios workflows utilice PostgreSQL.

Qué configuración de VPS se necesita para esta tarea

Esquema: Qué configuración de VPS se necesita para esta tarea
Esquema: Qué configuración de VPS se necesita para esta tarea

La carga de Kestra depende no tanto del número de archivos YAML como de la naturaleza de las tareas ejecutadas. Si los workflows solo llaman a API y ejecutan consultas SQL, los requisitos son moderados. Si ejecutan procesamiento de archivos con Python, contenedores Docker, automatización de navegador o transformaciones de tablas grandes, se necesitan CPU, RAM y un disco rápido adicionales.

Perfil CPU RAM Disco Adecuado para
Pruebas 1 vCPU 2 GB 25 GB NVMe Familiarización con la interfaz, 1–3 workflows ligeros
Production mínimo 2 vCPU 4 GB 40–60 GB NVMe Hasta decenas de tareas de API, SQL y cron al día
Operativo 4 vCPU 8 GB 100 GB NVMe Un equipo, workflows paralelos, logs grandes
Cálculos intensivos 8 vCPU+ 16–32 GB+ 200 GB NVMe+ Python, jobs Docker, archivos grandes, ML y ETL

Una opción práctica para comenzar es 2 vCPU, 4 GB de RAM, 60 GB de NVMe y un canal de al menos 100 Mbit/s. Este servidor normalmente soporta Kestra, PostgreSQL, Caddy, los servicios básicos del sistema y un número moderado de tareas ejecutándose simultáneamente. Si planea ejecutar workflows con contenedores Docker, comience con 4 vCPU y 8 GB de RAM.

Para este escenario puede contratar un VPS con las características indicadas, instalar Ubuntu Server 24.04 LTS y configurar de inmediato el registro DNS para el futuro dominio de Kestra.

Cuándo se necesita un servidor dedicated

Un servidor dedicado no se necesita por la propia interfaz de Kestra, sino para cargas de trabajo pesadas. Cambie a un dedicated si procesa regularmente decenas de gigabytes de archivos, ejecuta muchos contenedores en paralelo, necesita recursos de CPU garantizados, un IOPS alto o almacena localmente un gran volumen de logs de ejecución.

Un dedicated también tiene sentido si Kestra ejecuta procesos CI internos, navegadores Playwright, conversión de vídeo, modelos de machine learning o tareas Spark a gran escala. Para la automatización habitual de API, SQL y copias de seguridad, un VPS es más sencillo, económico y fácil de escalar verticalmente.

Cómo elegir la ubicación

La ubicación influye en la latencia hasta la base de datos, las API externas y los usuarios de la interfaz web. Si Kestra se conecta a una base de datos en un centro de datos europeo, elija un VPS cercano. Si las tareas trabajan con API locales o una red corporativa, es más importante la proximidad a la puerta de enlace VPN y un enrutamiento estable.

Para el certificado TLS y los webhook públicos, hay otro aspecto más importante: el nombre de dominio debe apuntar a la IP pública del servidor, y los puertos 80 y 443 deben estar accesibles desde Internet. Antes de instalar Caddy, cree un registro A, por ejemplo kestra.example.com, que apunte a la IP del VPS.

Preparación del servidor

A continuación se presupone un servidor limpio con Ubuntu Server 24.04 LTS y acceso SSH con el usuario root. Ejecute las acciones iniciales desde el terminal local. Sustituya SERVER_IP por la dirección externa de su VPS.

Creación del administrador y configuración de la clave SSH

Primero cree un usuario independiente. No ejecute Docker Compose ni trabaje con Kestra como root si no es necesario. El nombre de usuario del ejemplo es ops.

ssh root@SERVER_IP
adduser ops
usermod -aG sudo ops

Añada una clave SSH pública para el nuevo usuario. El comando siguiente se ejecuta en el equipo local donde ya existe la clave ~/.ssh/id_ed25519.pub.

ssh-copy-id ops@SERVER_IP
ssh ops@SERVER_IP

Compruebe que el acceso con el nuevo usuario funciona y solo después desactive el acceso de root y la autenticación mediante contraseña. Abra una segunda sesión SSH para no perder el acceso en caso de error de configuración.

sudo nano /etc/ssh/sshd_config.d/99-hardening.conf
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no
X11Forwarding no
AllowUsers ops

Compruebe la sintaxis de la configuración y reinicie el servicio SSH.

sudo sshd -t && sudo systemctl restart ssh

Actualización del sistema y utilidades básicas

Actualice los paquetes a su estado más reciente. En un servidor de production es útil activar las actualizaciones automáticas de seguridad, pero las actualizaciones de Docker y Kestra deben realizarse por separado en una ventana controlada.

sudo apt update && sudo apt full-upgrade -y
sudo apt install -y ca-certificates curl gnupg lsb-release \
  ufw fail2ban unattended-upgrades jq htop vim cron

Compruebe la versión del kernel y si es necesario reiniciar. Si existe el archivo /var/run/reboot-required, reinicie el VPS en una ventana adecuada.

test -f /var/run/reboot-required && cat /var/run/reboot-required
sudo reboot

Firewall UFW y Fail2ban

En el servidor solo deben estar abiertos SSH, HTTP y HTTPS. PostgreSQL no se publica externamente en el puerto 5432: Kestra accede a él mediante 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

Fail2ban bloqueará las direcciones IP después de varios intentos fallidos de acceso por SSH. Cree una configuración local mínima del jail.

sudo tee /etc/fail2ban/jail.d/sshd.local > /dev/null <<'EOF'
[sshd]
enabled = true
maxretry = 5
findtime = 10m
bantime = 1h
EOF
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

Si utiliza un puerto SSH no estándar, permítalo primero en UFW y compruebe el nuevo acceso; después cierre el puerto antiguo. No cambie el puerto SSH como única medida de seguridad: las claves, la desactivación del root-login y Fail2ban son más importantes.

Instalación del software — paso a paso

Diagrama: Instalación del software — paso a paso
Diagrama: Instalación del software — paso a paso

Para el despliegue utilizaremos Docker Engine 27+ y Docker Compose Plugin v2. Kestra quedará fijada en una etiqueta concreta de la imagen, no en latest. Esto protege contra actualizaciones accidentales al reiniciar los contenedores.

Instalación de Docker Engine y Docker Compose

Añada la clave oficial y el repositorio de Docker para Ubuntu. Los comandos se ejecutan con el usuario ops mediante sudo.

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

Añada el repositorio, actualice el índice de paquetes e instale Docker Engine, CLI y Compose Plugin.

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
sudo apt install -y docker-ce docker-ce-cli containerd.io \
  docker-buildx-plugin docker-compose-plugin

Añada el usuario al grupo Docker. Después del comando, salga de la sesión SSH y vuelva a conectarse: la pertenencia al grupo se aplica únicamente a las nuevas sesiones.

sudo usermod -aG docker ops
exit

Después de volver a iniciar sesión, compruebe Docker. El contenedor hello-world debe finalizar sin errores.

docker --version
docker compose version
docker run --rm hello-world

El grupo docker otorga de facto al usuario permisos comparables a los de root. Añada únicamente administradores de confianza. Para una instalación pequeña, resulta más cómodo que ejecutar cada comando mediante sudo.

Instalación de Caddy

Caddy recibirá el tráfico en los puertos 80 y 443, obtendrá automáticamente un certificado de Let’s Encrypt y reenviará las solicitudes a Kestra en localhost. Instale Caddy mediante el paquete del repositorio oficial.

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | \
  sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | \
  sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install -y caddy

Compruebe que Caddy está en ejecución. Mientras no se modifique la configuración, no hará proxy de Kestra.

sudo systemctl enable --now caddy
sudo systemctl status caddy --no-pager

Creación de la estructura de directorios

Almacene la configuración del proyecto en un solo directorio. En el ejemplo se utiliza /opt/kestra. Los datos persistentes estarán en Docker named volumes, mientras que los archivos de configuración, las exportaciones de workflows y las copias de seguridad estarán en el host.

sudo mkdir -p /opt/kestra/{config,backups,flows}
sudo chown -R ops:ops /opt/kestra
cd /opt/kestra
pwd

En 2026, antes de una instalación en producción, compruebe obligatoriamente la etiqueta estable actual en el registro de imágenes de Kestra y el changelog del proyecto. En el ejemplo se utiliza la etiqueta fijada v0.24.0 como plantilla. No sustituya la etiqueta por latest; actualícela conscientemente después de realizar una copia de seguridad y revisar las release notes.

Configuración de Kestra, PostgreSQL y SSL

Preparación de secretos

Genere contraseñas largas independientes para PostgreSQL y la autenticación HTTP básica de Caddy. No añada el archivo .env a Git ni lo envíe por mensajería. Los permisos 600 impiden que otros usuarios del servidor lean el archivo.

cd /opt/kestra
POSTGRES_PASSWORD=$(openssl rand -base64 32 | tr -d '\n')
CADDY_PASSWORD=$(openssl rand -base64 24 | tr -d '\n')

cat > .env <<EOF
POSTGRES_DB=kestra
POSTGRES_USER=kestra
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
KESTRA_DOMAIN=kestra.example.com
CADDY_USER=admin
CADDY_PASSWORD=${CADDY_PASSWORD}
EOF

chmod 600 .env

Sustituya kestra.example.com por su propio dominio. Antes de iniciar Caddy, compruebe el DNS: el comando debe devolver la IP pública de su VPS.

source /opt/kestra/.env
getent ahostsv4 "$KESTRA_DOMAIN"
curl -4 ifconfig.me ; echo

Configuración de Kestra

Cree el archivo config/application.yml. En él, Kestra utiliza PostgreSQL como repository y queue backend. El almacenamiento local es adecuado para un solo nodo de Kestra. Al pasar a varios servidores, el almacenamiento debe trasladarse a un almacenamiento de objetos compatible con S3.

cat > /opt/kestra/config/application.yml <<'EOF'
datasources:
  postgres:
    url: jdbc:postgresql://postgres:5432/${POSTGRES_DB}
    driverClassName: org.postgresql.Driver
    username: ${POSTGRES_USER}
    password: ${POSTGRES_PASSWORD}

kestra:
  repository:
    type: postgres
  queue:
    type: postgres
  storage:
    type: local
    local:
      base-path: /app/storage
  tasks:
    tmp-dir:
      path: /tmp/kestra-wd/tmp
  url: https://${KESTRA_DOMAIN}/
  server:
    basic-auth:
      enabled: false

logger:
  levels:
    io.kestra: INFO
EOF

La autenticación básica de Kestra está desactivada porque Caddy protegerá el acceso externo. Esto simplifica el trabajo con el navegador y la API, pero significa que Caddy debe seguir siendo el único punto de entrada. El puerto de Kestra no se publica externamente.

Docker Compose para Kestra y PostgreSQL

Cree compose.yml. PostgreSQL no tiene una sección ports; por tanto, solo está disponible para los contenedores de la red interna de Docker. Kestra se publica en 127.0.0.1:8080, por lo que Caddy en el mismo servidor puede acceder a ella, pero Internet no.

cat > /opt/kestra/compose.yml <<'EOF'
services:
  postgres:
    image: postgres:16.6-alpine
    container_name: kestra-postgres
    restart: unless-stopped
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    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:
      - kestra_internal

  kestra:
    image: kestra/kestra:v0.24.0
    container_name: kestra
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      KESTRA_DOMAIN: ${KESTRA_DOMAIN}
      JAVA_OPTS: "-Xms512m -Xmx1536m"
    command: server standalone --config /etc/kestra/application.yml
    ports:
      - "127.0.0.1:8080:8080"
    volumes:
      - ./config/application.yml:/etc/kestra/application.yml:ro
      - kestra_storage:/app/storage
      - kestra_workdir:/tmp/kestra-wd
    healthcheck:
      test: ["CMD-SHELL", "wget -qO- http://localhost:8080/health | grep -q UP"]
      interval: 30s
      timeout: 10s
      retries: 10
      start_period: 60s
    networks:
      - kestra_internal

networks:
  kestra_internal:
    name: kestra_internal

volumes:
  postgres_data:
  kestra_storage:
  kestra_workdir:
EOF

El parámetro JAVA_OPTS limita el heap de Java a 1,5 GB. En un VPS con 4 GB de RAM, es un punto de partida razonable: el resto de la memoria queda para PostgreSQL, el sistema operativo y la caché de archivos. En un servidor con 8 GB de RAM, puede aumentar -Xmx a 3–4 GB después de observar el consumo de memoria real.

Inicie los servicios en segundo plano y compruebe su estado. El primer inicio puede tardar varios minutos: Kestra crea las tablas y aplica las migraciones en PostgreSQL.

cd /opt/kestra
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 kestra

Compruebe el endpoint local antes de configurar el proxy. La respuesta puede ser JSON o una redirección HTTP, según la versión de Kestra, pero el código no debe ser 502 ni Connection refused.

curl -I http://127.0.0.1:8080/
docker inspect --format='{{.State.Health.Status}}' kestra
docker inspect --format='{{.State.Health.Status}}' kestra-postgres

Configuración de Caddy y HTTPS

Primero, cree un hash bcrypt de la contraseña para Caddy. El comando solicitará la contraseña que guardó en .env. No introduzca la contraseña en la línea de comandos: quedará en el historial del shell.

source /opt/kestra/.env
read -rsp "Password for Caddy user ${CADDY_USER}: " INPUT_PASSWORD; echo
CADDY_HASH=$(printf '%s' "$INPUT_PASSWORD" | caddy hash-password --stdin)
unset INPUT_PASSWORD
printf '%s\n' "$CADDY_HASH"

Cree el Caddyfile. En lugar de la variable de la configuración, introduzca manualmente el hash mostrado en PASTE_BCRYPT_HASH_HERE. Es más seguro que dejar la contraseña en texto plano.

sudo tee /etc/caddy/Caddyfile > /dev/null <<'EOF'
kestra.example.com {
    encode zstd gzip

    basic_auth {
        admin PASTE_BCRYPT_HASH_HERE
    }

    reverse_proxy 127.0.0.1:8080 {
        header_up Host {host}
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-For {remote_host}
        header_up X-Forwarded-Proto {scheme}
    }

    log {
        output file /var/log/caddy/kestra-access.log
        format json
    }
}
EOF

Sustituya el dominio y el hash en el archivo, cree el directorio de registros y compruebe la sintaxis. Caddy obtiene el certificado automáticamente después de cargar correctamente la configuración, si el DNS ya apunta al servidor y el puerto 80 está accesible desde el exterior.

sudo mkdir -p /var/log/caddy
sudo chown caddy:caddy /var/log/caddy
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
sudo systemctl status caddy --no-pager

Abra https://kestra.example.com en el navegador. El navegador solicitará el nombre de usuario y la contraseña de Caddy, tras lo cual se abrirá la interfaz de Kestra. Compruebe también TLS desde la consola.

curl -I https://kestra.example.com
sudo journalctl -u caddy -n 100 --no-pager

Primer workflow y programación cron

Abra Kestra en el navegador, cree un namespace, por ejemplo company.ops, vaya a la sección Flows y cree un flow. Para la primera comprobación, inserte el siguiente YAML. Registra un mensaje en los logs y se ejecuta cada 15 minutos.

id: health_report
namespace: company.ops
description: Проверочный workflow с cron-расписанием

triggers:
  - id: every_15_minutes
    type: io.kestra.plugin.core.trigger.Schedule
    cron: "/15    "
    timezone: "Europe/Moscow"

tasks:
  - id: write_log
    type: io.kestra.plugin.core.log.Log
    message: "Kestra работает. Время запуска: {{ execution.startDate }}"

  - id: shell_check
    type: io.kestra.plugin.scripts.shell.Commands
    commands:
      - "date -u"
      - "echo Workflow finished successfully"

Guarde el workflow, pulse Execute y abra la pestaña Executions. Debe aparecer el estado SUCCESS. Después, espere a una hora múltiplo de 15 minutos o sustituya temporalmente cron por para probarlo cada minuto. Después de la comprobación, restaure la programación normal.

No almacene tokens de API, claves de S3, contraseñas de bases de datos ni secretos de webhooks directamente en YAML. Utilice los secretos de Kestra, variables de entorno o un secret manager externo. Para empezar, puede crear secretos mediante la interfaz en el namespace y, más adelante, conectar Vault, SOPS o un secrets manager en la nube.

Copias de seguridad y mantenimiento

Esquema: Copias de seguridad y mantenimiento
Esquema: Copias de seguridad y mantenimiento

Para restaurar Kestra no solo se necesitan los datos de PostgreSQL. Es necesario conservar los archivos de configuración, el archivo Compose, Caddyfile, el archivo de secretos .env y el persistent storage. PostgreSQL contiene metadatos, execution history, configuraciones y datos de las colas; storage contiene archivos creados por las tareas y los plugins.

Qué respaldar Por qué Con qué frecuencia
PostgreSQL dump Workflow metadata, executions, queues, configuraciones Diariamente, antes de actualizar
Docker volume Kestra storage Archivos de tareas, adjuntos y artefactos locales Diariamente
/opt/kestra Compose, configuraciones YAML, secretos, scripts Después de cada cambio y diariamente
/etc/caddy/Caddyfile Proxy HTTPS y acceso al panel Después de cada cambio

Script de backup local

El siguiente script crea un volcado comprimido de PostgreSQL y archiva el directorio de configuración. Conserva localmente los últimos 14 días. El backup local no protege contra la eliminación del VPS, por lo que después debe enviarse a un almacenamiento compatible con S3 o a un servidor independiente.

cat > /opt/kestra/backup-kestra.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

BASE="/opt/kestra"
DATE=$(date +%F_%H-%M-%S)
DEST="${BASE}/backups/${DATE}"

mkdir -p "${DEST}"

cd "${BASE}"
docker compose exec -T postgres pg_dump \
  -U "${POSTGRES_USER}" \
  -d "${POSTGRES_DB}" \
  --format=custom \
  --file="/tmp/kestra_${DATE}.dump"

docker cp kestra-postgres:"/tmp/kestra_${DATE}.dump" \
  "${DEST}/postgres.dump"

docker compose exec -T postgres rm -f "/tmp/kestra_${DATE}.dump"

tar --exclude='backups' \
  --exclude='.git' \
  -czf "${DEST}/kestra-config.tar.gz" \
  -C /opt kestra

docker run --rm \
  -v kestra_kestra_storage:/source:ro \
  -v "${DEST}":/backup \
  alpine:3.20 \
  tar -czf /backup/kestra-storage.tar.gz -C /source .

find "${BASE}/backups" -mindepth 1 -maxdepth 1 -type d -mtime +14 -exec rm -rf {} \;
EOF

chmod 700 /opt/kestra/backup-kestra.sh
cd /opt/kestra && ./backup-kestra.sh
ls -lah /opt/kestra/backups

El nombre del Docker volume normalmente se forma a partir del nombre del directorio y del nombre del volume. En este caso, el proyecto se ejecuta desde /opt/kestra, por lo que el volume se llama kestra_kestra_storage. Si el comando devuelve un error indicando que el volume no existe, consulte el nombre exacto mediante docker volume ls y corrija el script.

Envío del backup a un almacenamiento externo

Para una protección real, conserve las copias fuera del VPS principal. Opciones prácticas: almacenamiento de objetos compatible con S3, un VPS de backup independiente mediante SSH, un Borg repository o un Restic repository. A continuación se muestra un ejemplo con Restic y un backend compatible con S3. Coloque las variables de acceso en un archivo independiente con permisos 600.

sudo apt install -y restic
sudo tee /etc/kestra-restic.env > /dev/null <<'EOF'
export RESTIC_REPOSITORY="s3:s3.example.net/kestra-backups"
export RESTIC_PASSWORD="CHANGE_TO_A_LONG_UNIQUE_RESTIC_PASSWORD"
export AWS_ACCESS_KEY_ID="CHANGE_ME"
export AWS_SECRET_ACCESS_KEY="CHANGE_ME"
EOF
sudo chmod 600 /etc/kestra-restic.env

Inicialice el repositorio una vez y después añada la carga de datos al final del script de backup. Antes de utilizarlo, compruebe los parámetros de endpoint y bucket del proveedor S3 elegido.

source /etc/kestra-restic.env
restic init
restic backup /opt/kestra/backups
restic snapshots

Añada una ejecución diaria. Cron se ejecuta con el usuario ops, por lo que debe tener acceso a Docker y a los archivos del proyecto.

crontab -e
15 2    /opt/kestra/backup-kestra.sh >> /opt/kestra/backups/backup.log 2>&1
30 2    . /etc/kestra-restic.env && restic backup /opt/kestra/backups && restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune >> /opt/kestra/backups/restic.log 2>&1

Actualización de Kestra sin pérdida de datos

Para un VPS, la actualización es una breve maintenance window, no un rolling deployment real. Primero haga un backup, lea las release notes de la versión elegida, actualice la etiqueta de la imagen en compose.yml, descargue la imagen y reinicie solo el contenedor de Kestra.

cd /opt/kestra
./backup-kestra.sh
docker compose pull kestra
docker compose up -d --no-deps kestra
docker compose logs -f --tail=100 kestra

Después de la actualización, compruebe la interfaz, la ejecución de un workflow de prueba, la programación y las migraciones de la base de datos. No elimine inmediatamente la imagen antigua: puede ser útil para revertir los cambios si la nueva versión es incompatible con el plugin utilizado. Antes de actualizar la major-version de PostgreSQL, realice un backup independiente y verificado y siga el procedimiento de upgrade de PostgreSQL, en lugar de limitarse a cambiar la etiqueta del contenedor.

Solución de problemas + FAQ

¿Por qué Caddy no obtiene el certificado TLS y aparece un error ACME en los logs?

Primero compruebe el registro A del dominio con el comando getent ahostsv4 kestra.example.com: debe devolver la IP del VPS. Después asegúrese de que UFW permite los puertos TCP 80 y 443 y de que el proveedor no tiene un cloud firewall adicional. Compruebe que otro servidor web no haya ocupado el puerto 80: sudo ss -ltnp | grep ':80\|:443'. Después de corregir el DNS y los puertos, ejecute sudo systemctl reload caddy y revise journalctl -u caddy.

¿Por qué aparece 502 Bad Gateway en el navegador?

El código 502 significa que Caddy está disponible, pero no puede conectarse a Kestra. Ejecute docker compose ps en el directorio /opt/kestra: el contenedor de Kestra debe estar en estado running o healthy. Después compruebe localmente curl -I http://127.0.0.1:8080/. Si no hay respuesta, revise docker compose logs kestra y docker compose logs postgres. Una causa frecuente es que PostgreSQL aún no haya superado el healthcheck o que se hayan indicado variables de base de datos incorrectas.

Kestra se reinicia constantemente. ¿Qué hay que comprobar?

Comience con docker compose logs --tail=200 kestra. Los errores de conexión a PostgreSQL suelen indicar una contraseña, un nombre de base de datos o una configuración JDBC incorrectos. Los errores OutOfMemoryError significan que al VPS le falta RAM o que el parámetro -Xmx es demasiado grande. Compruebe la memoria mediante free -h y docker stats. En un VPS con 2 GB de RAM es mejor no ejecutar PostgreSQL y Kestra con workflows pesados simultáneamente.

¿Por qué no se inicia el workflow mediante cron?

Compruebe que el flow esté guardado, habilitado y no contenga errores en YAML. En cron, en una expresión de cinco campos, /15 * significa cada 15 minutos. Asegúrese de que la timezone esté indicada explícitamente: sin ella, la hora puede interpretarse en UTC. Abra la sección Executions y busque errores del trigger. Consulte también los logs: docker compose logs kestra | grep -i schedule. Para realizar una prueba, establezca temporalmente una programación cada minuto.

¿Qué configuración de VPS es mínimamente adecuada?

Para familiarizarse con Kestra puede utilizar 1 vCPU, 2 GB de RAM y 25 GB de NVMe, pero no es una opción de production cómoda. El mínimo práctico para Kestra, PostgreSQL, Caddy y varios workflows pequeños es 2 vCPU, 4 GB de RAM y 40–60 GB de NVMe. Si los workflows ejecutan Python, Chromium, Docker-containers o procesan archivos, elija como mínimo 4 vCPU y 8 GB de RAM.

¿Qué elegir: VPS o dedicated para esta tarea?

Un VPS es suficiente para la automatización de API, tareas SQL, informes periódicos, webhook y la mayoría de los procesos ETL pequeños. Se necesita un dedicated con una carga de CPU pesada constante, decenas de container jobs paralelos, grandes volúmenes de datos locales o un requisito estricto de recursos dedicados. Normalmente es más razonable comenzar con un VPS y observar docker stats, la carga de CPU, los IOPS y el tiempo de ejecución de los workflows.

¿Se puede abrir PostgreSQL al exterior para conectarse desde DBeaver?

Técnicamente es posible, pero normalmente no es necesario ni seguro para Kestra. PostgreSQL debe permanecer dentro de la red de Docker. Para el acceso administrativo, utilice un túnel SSH: ssh -L 5432:127.0.0.1:5432 ops@SERVER_IP, aunque para ello será necesario reenviar temporalmente PostgreSQL solo a localhost. Una opción más segura es ejecutar los comandos SQL mediante docker compose exec postgres psql directamente en el servidor.

¿Por qué el backup no encuentra el Docker volume de Kestra?

Primero ejecute docker volume ls y busque el volume asociado con storage. Docker Compose forma el nombre a partir del project name y del nombre del volume, por lo que puede diferir del ejemplo si el proyecto se inició desde otro directorio o con el parámetro -p. Corrija el nombre del volume en el script de backup. Compruebe también los permisos del directorio /opt/kestra/backups y asegúrese de que cron se ejecute con un usuario perteneciente al grupo docker.

Conclusiones y próximos pasos

Esquema: Conclusiones y próximos pasos
Esquema: Conclusiones y próximos pasos

Ahora Kestra funciona en el VPS con PostgreSQL, Docker Compose, HTTPS mediante Caddy, protección básica del servidor, programaciones de cron y copias de seguridad. La instancia está lista para ejecutar production-workflows si comprueba periódicamente los logs, el espacio libre en el disco y el éxito del backup.

  1. Cree namespaces independientes para desarrollo y production, y traslade los secretos a Kestra Secrets o a un secret manager externo.
  2. Configure notificaciones en Telegram, Slack o email para las executions con estado FAILED.
  3. Cuando aumente la carga, traslade storage a un almacenamiento compatible con S3, PostgreSQL a un servidor independiente o a una base de datos gestionada, y aísle la carga de los workers en contenedores independientes.

Antes de cualquier actualización de Kestra, realice un backup verificable y pruebe manualmente los workflows críticos. Esto es más importante que la actualización automática de imágenes y permite revertir rápidamente los cambios si hay incompatibilidades de plugins o cambios en la configuración.

¿Te fue útil esta guía?

Tus comentarios nos ayudan a mejorar nuestras guías.

Compartir esta publicación:

Envía esta guía a alguien a quien pueda resultarle útil.

Telegram VKVK WhatsApp Facebook LinkedIn XX

instalación de Kestra en VPS: orquestación de tareas, Docker, PostgreSQL, SSL y programaciones
support_agent
Valebyte Support
Usually replies within minutes
Hi there!
Send us a message and we'll reply as soon as possible.