Por qué autoalojar Trigger.dev en un VPS
Trigger.dev sustituye las colas caseras (BullMQ, cron frágiles, Lambda que expiran) por una plataforma unificada: tareas duraderas, reintentos automáticos, gestión de la concurrencia y panel en tiempo real. La versión cloud factura por número de ejecuciones y limita la duración de los jobs, algo que enseguida resulta restrictivo para procesos ETL, envíos masivos de correo o llamadas lentas a API.
En self-hosted sobre un VPS, mantiene sus workers en casa: sus claves API de terceros (OpenAI, Stripe, Resend) nunca pasan por un intermediario, y sus jobs pueden durar 10 minutos o varias horas sin ser interrumpidos. El stack se apoya en PostgreSQL, Redis y Docker, lo que lo hace reproducible y fácil de respaldar. La instalación es totalmente gratuita: sin licencia, sin suscripción — solo el coste del VPS.
Lo que gana al autoalojarlo
- Ningún límite en la duración ni en el número de ejecuciones de sus tareas en segundo plano.
- Sus secretos (claves API, tokens) permanecen en su infraestructura, nunca en un SaaS de terceros.
- Coste fijo previsible: un solo VPS en lugar de una factura que crece con el volumen.
- Ningún salto por la red pública si sus workers se ejecutan junto a su base de datos y su aplicación.
- Control total sobre las versiones, las variables de entorno y la retención de los logs.
- Posibilidad de lanzar jobs desde sus webhooks internos sin exponer ningún servicio externo.
- Actualización a su ritmo: usted decide cuándo migrar a una nueva versión de Trigger.dev.
Trigger.dev self-hosted vs cloud: lo que cambia realmente
Desplace la tabla
| Criterio | Cloud (SaaS) | VPS self-hosted |
|---|---|---|
| Duración máxima de un job | Limitada (pocos minutos) | Ilimitada |
| Coste por volumen | Crece con las ejecuciones | Fijo (VPS mensual) |
| Secretos / claves API | Pasan por la nube | Se quedan en su infra |
| Actualizaciones | Automáticas, impuestas | A su ritmo |
| Acceso a red interna | Imposible sin túnel | Directo, sin latencia pública |
| Retención de logs | Limitada por el plan | Controlada por usted |
| Configuración inicial | Cero configuración | ~30 minutos (esta guía) |
Requisitos de hardware y software
Trigger.dev es un stack relativamente exigente porque combina la aplicación web, workers, PostgreSQL y Redis. Prevea un VPS con al menos 4 GB de RAM y 2 vCPU para un uso de producción ligero; apunte a 8 GB de RAM y 4 vCPU si ejecuta muchos jobs concurrentes o procesos pesados. Cuente con 40 GB de disco SSD para la base de datos, los logs y las imágenes Docker.
En el plano del software: Docker Engine 24+ y el plugin Docker Compose v2 (compruébelo con docker compose version), un nombre de dominio que apunte a la IP del VPS (por ejemplo trigger.mondomaine.com), y el puerto 443 abierto para HTTPS. Dos secretos son imprescindibles: MAGIC_LINK_SECRET (autenticación sin contraseña) y ENCRYPTION_KEY (32 caracteres hexadecimales, cifra las variables de entorno de los proyectos). Genérelos antes de comenzar — no pueden regenerarse sin romper los datos existentes.
Instalar Trigger.dev con Docker en 6 pasos
Preparar el VPS e instalar Docker
Conéctese por SSH con un usuario sudo, actualice el sistema (
apt update && apt upgrade -y) e instale Docker en un solo comando:curl -fsSL https://get.docker.com | sh. Añada su usuario al grupo docker (usermod -aG docker $USER) para no tener que usarsudosiempre. Cree una carpeta dedicada:mkdir -p /opt/trigger && cd /opt/trigger. Verifique que Compose v2 está disponible condocker compose version— la salida debe mostrar al menosv2.x.x.Obtener el stack oficial de self-hosting
Clone el repositorio oficial:
git clone https://github.com/triggerdotdev/trigger.dev /opt/trigger/src. Navegue a la subcarpeta de despliegue:cd /opt/trigger/src/docker. Este directorio contiene eldocker-compose.ymlque orquesta la aplicación web (webapp), los workers, PostgreSQL y Redis. Copie el fichero de ejemplo a su configuración:cp .env.example .env. No lance nada antes de configurar el.env— el stack se negará a arrancar con los valores por defecto.Generar los secretos y configurar el dominio
Abra
.enven su editor y rellene como mínimo estas variables:-
ENCRYPTION_KEY:openssl rand -hex 16(16 bytes = 32 chars hex)
-MAGIC_LINK_SECRET:openssl rand -hex 16(igual)
-LOGIN_ORIGIN:https://trigger.mondomaine.com
-APP_ORIGIN:https://trigger.mondomaine.com
-POSTGRES_PASSWORD: una contraseña fuerte (openssl rand -base64 24)
-REDIS_PASSWORD: igualDeje
DATABASE_URLyREDIS_URLtal cual si usa los servicios internos de Compose — hacen referencia a los nombres de servicio de Docker. También definaSESSION_SECRETconopenssl rand -hex 32.Arrancar el stack y crear la primera cuenta
Inicie el conjunto en segundo plano:
docker compose up -d. Siga las migraciones de base de datos en tiempo real:docker compose logs -f webapp. Espere el mensajeListening on port 3030antes de continuar — las migraciones pueden tardar 30 a 60 segundos en el primer arranque. Una vez iniciada la aplicación, el magic link de registro aparece en los logs: cópielo y ábralo en su navegador para crear la primera cuenta de administrador. Si se perdió el enlace:docker compose logs webapp | grep magic.Exponer la aplicación mediante un proxy inverso HTTPS
Ponga Caddy delante de la aplicación para gestionar el TLS automáticamente. Cree
/etc/caddy/Caddyfilecon este contenido mínimo:trigger.mondomaine.com { reverse_proxy localhost:3030 }Recargue Caddy (
systemctl reload caddy): Let's Encrypt emite el certificado en segundos. Con nginx, cree un vhost que haga proxy ahttp://127.0.0.1:3030y active un certificado concertbot --nginx. Verifique quehttps://trigger.mondomaine.comresponde correctamente antes de continuar.Conectar su primer proyecto TypeScript
En su proyecto Node.js, instale el SDK:
npm install @trigger.dev/sdk. Autentique el CLI contra su instancia:npx trigger.dev@latest login --api-url https://trigger.mondomaine.com. Luego cree su primer proyecto en el panel, recupere la clave secreta del proyecto (sk_...) y añádala a su.envlocal:TRIGGER_SECRET_KEY=sk_.... Inicialice la configuración connpx trigger.dev@latest inity despliegue su primer job connpx trigger.dev@latest deploy.
Solución de errores: problemas frecuentes y sus soluciones
Estos son los cinco errores más comunes al instalar Trigger.dev en self-hosted.
Error: ENCRYPTION_KEY must be 32 characters — Ha usado openssl rand -base64 16 en lugar de openssl rand -hex 16. La forma base64 produce caracteres fuera del juego hexadecimal. Regénere con -hex 16 (exactamente 32 chars).
webapp exited with code 1 al arrancar — Compruebe los logs completos con docker compose logs webapp. La causa más frecuente: DATABASE_URL incorrecta o PostgreSQL no listo todavía. Espere 10 segundos y reinicie con docker compose restart webapp.
El magic link de creación de cuenta no aparece — La aplicación puede haber arrancado antes de que terminaran las migraciones. Ejecute docker compose restart webapp y observe los logs desde el principio. Si el enlace sigue ausente, compruebe que LOGIN_ORIGIN coincide exactamente con su dominio (sin barra final).
Failed to connect en el CLI durante login — El proxy inverso no está aún activo o el DNS no ha propagado todavía hacia su VPS. Pruebe localmente con curl http://127.0.0.1:3030/healthcheck desde el VPS: si responde, el problema está en el proxy o el DNS.
El job se despliega pero no se ejecuta — Compruebe que los workers están en marcha: docker compose ps debe mostrar el servicio worker en estado running. Si el worker está detenido, docker compose up -d worker lo reinicia. Verifique también que TRIGGER_SECRET_KEY en su proyecto coincide con la clave del proyecto correcto en el panel.
Proteger y mantener su instancia
Una instancia de Trigger.dev expone el panel y la API en el mismo dominio. Algunas precauciones reducen la superficie de ataque sin complicar la operación.
Firewall: bloquee todos los puertos salvo el 22 (SSH), 80 y 443. El puerto 3030 no debe ser accesible directamente desde el exterior — está reservado para el proxy inverso local.
Rotación de secretos: MAGIC_LINK_SECRET puede rotarse sin romper datos. ENCRYPTION_KEY, en cambio, cifra las variables de entorno de los proyectos — su rotación exige una migración de datos. Guárdelos en un gestor de secretos (Bitwarden, 1Password o HashiCorp Vault).
Actualizaciones: Trigger.dev publica sus releases en GitHub. Para actualizar, tire de la nueva versión (git pull en /opt/trigger/src), reconstruya las imágenes (docker compose pull) y reinicie (docker compose up -d). Las migraciones de base de datos se aplican automáticamente al arrancar webapp.
Copias de seguridad: programe un volcado diario de PostgreSQL hacia almacenamiento externo. Un cron mínimo: 0 3 * * * docker exec trigger-postgres-1 pg_dump -U postgres trigger | gzip > /opt/backups/trigger-$(date +%F).sql.gz.
Escalabilidad horizontal de los workers
Aísle los workers de la aplicación web en contenedores separados y limite su concurrencia con la variable WORKER_CONCURRENCY (por defecto: 10). Para los jobs muy exigentes en CPU, añada un segundo VPS dedicado a los workers que apunte al mismo PostgreSQL y Redis: escala horizontalmente sin tocar el panel. Los workers no tienen estado — solo necesitan DATABASE_URL, REDIS_URL y ENCRYPTION_KEY para unirse a la flota. En un VPS pequeño, comience con WORKER_CONCURRENCY=3 para evitar la saturación de memoria durante picos de jobs.
Escribir y desplegar su primer job de Trigger.dev
Un job de Trigger.dev es una función TypeScript exportada desde un fichero trigger/ de su proyecto. Un ejemplo mínimo de envío de correo diferido:
import { task } from "@trigger.dev/sdk/v3";
export const sendWelcomeEmail = task({
id: "send-welcome-email",
run: async (payload: { userId: string; email: string }) => {
// su lógica de envío aquí
await sendEmail(payload.email, "¡Bienvenido!");
return { sent: true };
},
});Despliegue con npx trigger.dev@latest deploy. El panel muestra entonces su job bajo la pestaña Tasks. Ejecute un test desde el panel o desde su código: await sendWelcomeEmail.trigger({ userId: "u1", email: "[email protected]" }). Los reintentos automáticos se aplican en caso de error — configurables con la opción retry en task().
Para jobs largos (importación de CSV, procesamiento de imágenes), use wait.for() para suspender la ejecución y no bloquear un worker durante pausas de red: Trigger.dev reanuda el job donde lo dejó, incluso tras un reinicio del contenedor.
Casos de uso más adecuados para el self-hosting
- Procesamiento ETL: importar, transformar y cargar grandes volúmenes de datos sin timeouts.
- Envíos transaccionales masivos: campañas de email o notificaciones con throttling controlado.
- Pipelines de IA: llamadas encadenadas a OpenAI, Anthropic o Hugging Face con gestión de reintentos en rate-limit.
- Sincronización de integraciones de terceros: webhooks de Stripe, Shopify, HubSpot — sin depender de un SaaS intermediario.
- Tareas programadas críticas: reemplazar cron frágiles por jobs con historial de ejecución y alertas.
- Generación de informes PDF o exportaciones pesadas: jobs de varios minutos sin límite de duración.
Trigger.dev es totalmente gratuito en self-hosted: no se requiere ninguna licencia comercial para uso privado o profesional en su propia infraestructura. La licencia MIT cubre el código open-source. Solo el código propietario de la versión Enterprise (SSO SAML, audit logs avanzados) está excluido — para la gran mayoría de los equipos, la versión comunitaria autoalojada es más que suficiente.