Ir al contenido

Dónde desplegar Pitangus

Pitangus tiene tres piezas, y cada una puede vivir donde más te convenga:

Pieza Qué necesita Imagen
API y panel HTTP y la base de datos. Sin disco propio: todo el estado está en PostgreSQL. ghcr.io/pitangus-dev/pitangus
Worker Un proceso permanente que ejecuta los motores de análisis. ghcr.io/pitangus-dev/pitangus-worker (motores dentro), o la imagen de la API con el socket de Docker
PostgreSQL Versión 16 o superior, gestionada o en un contenedor. —

Cada etiqueta de versión publica las imágenes, firmadas y multiarquitectura. También puedes construirlas desde el repositorio (make build, o docker build --target worker-standalone -f docker/app/Dockerfile . para el worker).

Destino API y panel Worker PostgreSQL Guía Probado
Tu servidor, con el repositorio Compose Compose, motores dentro (socket de Docker con SOCKET=1) Contenedor despliegue-vps.md Sí
Tu servidor, un solo archivo (Coolify, Dokploy, Portainer, gestor de Docker de Hostinger) Compose Compose, motores dentro Contenedor abajo En local, de principio a fin
Render Web service Background worker Render Postgres abajo Todavía no
Railway, Fly.io Servicio Servicio Su PostgreSQL abajo Todavía no
Vercel Función de Python En otro sitio (cualquier fila de arriba) Neon, Supabase… abajo La entrada ASGI, en local
Kubernetes Deployment Deployment Tu operador abajo Todavía no

Sea cual sea el destino, importan los mismos cuatro valores:

Ventana de terminal
PITANGUS_DATABASE_URL=postgresql://usuario:contraseña@host:5432/pitangus # valen postgres:// y postgresql://
PITANGUS_MASTER_KEY=<openssl rand -base64 32> # la misma en la API y en cada worker
PITANGUS_PUBLIC_URL=https://pitangus.example.com
PITANGUS_ALLOWED_ORIGINS=https://pitangus.example.com # cada dirección con la que se abre

La clave maestra descifra todos los secretos guardados: GitHub App, Jira, canales de avisos, semillas TOTP y la clave de firma de sesiones. Guárdala en el gestor de secretos de la plataforma, con una copia fuera de las copias de la base. pitangus check-config revisa toda la configuración y dice qué está mal.

Un solo archivo: cualquier servidor o panel de Docker

Sección titulada «Un solo archivo: cualquier servidor o panel de Docker»

deploy/compose.yaml no necesita nada más: imágenes publicadas, volúmenes con nombre, sin construir, sin el repositorio y sin el socket de Docker (el worker ejecuta los motores dentro de su propia imagen).

Ventana de terminal
curl -fsSLO https://raw.githubusercontent.com/Pitangus-Dev/pitangus/main/deploy/compose.yaml
printf 'PITANGUS_DB_PASSWORD=%s\nPITANGUS_MASTER_KEY=%s\nPITANGUS_PUBLIC_URL=%s\n' \
"$(openssl rand -hex 24)" "$(openssl rand -base64 32)" "https://pitangus.example.com" > .env
docker compose --profile https up -d # --profile https: Caddy obtiene el certificado (sin él, detrás de tu proxy)
docker compose exec api python -m pitangus setup-code
  • Coolify y Dokploy: crea un recurso Docker Compose, pega el archivo, define las tres variables en la pantalla de entorno y apunta tu dominio al servicio api, puerto 8766. Deja apagado el perfil https: el proxy de la plataforma se encarga del TLS.
  • Hostinger: en el panel del VPS, abre el gestor de Docker, crea un proyecto desde Compose y pega el archivo y las variables. Si no hay otro proxy en el servidor, añade COMPOSE_PROFILES=https.
  • Portainer: Stacks → Add stack, pega el archivo y añade las variables.
  • Redes: PostgreSQL solo está en db, una red interna sin salida que comparte con la api, el worker y las copias. Caddy solo está en edge, con la api.
  • Copias de seguridad: --profile backup guarda copias con pg_dump en ./backups cada 24 h (cámbialo con PITANGUS_BACKUP_INTERVAL_HOURS). La clave maestra no va en ellas: guárdala aparte.

Dimensionado: con 2 vCPU y 4 GB de memoria corre un análisis a la vez; con 8 GB va holgado. La imagen del worker ocupa unos 1,8 GB.

render.yaml es un Blueprint con la API (web service), el worker (background worker) y PostgreSQL. New → Blueprint, elige el repositorio y escribe PITANGUS_PUBLIC_URL cuando te lo pida (https://<servicio>.onrender.com o tu dominio). Render genera la clave maestra (32 bytes aleatorios en base64, justo su formato) y la comparte con el worker. Léela una vez del entorno de la API y guarda una copia.

Railway, Fly.io y otras plataformas de contenedores

Sección titulada «Railway, Fly.io y otras plataformas de contenedores»

Dos servicios con las imágenes publicadas, más el PostgreSQL de la plataforma:

Servicio Imagen Variables, además de las cuatro de arriba
api ghcr.io/pitangus-dev/pitangus:<versión> PITANGUS_BIND=0.0.0.0, PITANGUS_EMBEDDED_WORKER=0, PITANGUS_FORWARDED_ALLOW_IPS=*, puerto 8766
worker ghcr.io/pitangus-dev/pitangus-worker:<versión> ninguna

En Railway, referencia la base como PITANGUS_DATABASE_URL=${{Postgres.DATABASE_URL}}. Dale al worker al menos 2 GB de memoria. Sus cachés (las bases de datos de los motores) pueden ir en disco efímero: se vuelven a descargar tras un redespliegue.

Vercel ejecuta la API y el panel como una función de Python (vercel.json, entrada api/index.py, que importa pitangus.app.asgi). El worker no cabe ahí: un análisis puede durar más de lo que dura una función, y no hay proceso permanente. Ejecuta el worker en cualquier otra fila de la tabla, contra la misma base y con la misma clave maestra.

  1. Crea una base PostgreSQL (Neon, Supabase u otra) a la que lleguen los dos.
  2. Importa el repositorio en Vercel y define las cuatro variables. En PITANGUS_ALLOWED_ORIGINS pon cada dirección con la que lo abras: el dominio de producción, y las URL de vista previa si las usas.
  3. Arranca el worker en otro sitio con los mismos PITANGUS_DATABASE_URL y PITANGUS_MASTER_KEY.
  4. El código de configuración aparece en los registros de la función con la primera petición; pitangus setup-code, ejecutado en cualquier sitio con las mismas variables, también lo muestra.

Si el worker no puede estar siempre encendido (escala a cero), define PITANGUS_PERIODIC=external en los dos y deja que un programador dispare las tareas periódicas: añade "crons": [{"path": "/api/cron", "schedule": "*/5 * * * *"}] a vercel.json y un CRON_SECRET de al menos 32 caracteres (Vercel lo envía como token bearer). El plan Hobby de Vercel solo permite una ejecución al día.

Todavía no hay manifiestos. Las piezas encajan directamente: un Deployment para la API (puerto 8766, /api/health como sonda), otro para la imagen del worker (no necesita el socket de Docker), las cuatro variables desde un Secret y el PostgreSQL que prefieras. Con PITANGUS_PERIODIC=external, un CronJob que ejecute python -m pitangus periodic sustituye al reloj del worker líder. Cuántas réplicas del worker y qué mirar para escalarlas: escalar.md.

Entregar los avisos, sondear los pull requests, sincronizar NVD y revisar a diario si hay avisos nuevos van con reloj:

  • PITANGUS_PERIODIC=leader (por defecto): las ejecuta un worker, elegido con un cerrojo de PostgreSQL. No hay nada que configurar.
  • PITANGUS_PERIODIC=external: nada se ejecuta solo. Un programador llama a pitangus periodic (cron, un CronJob) o a GET /api/cron con Authorization: Bearer <PITANGUS_CRON_TOKEN o CRON_SECRET>. Cada llamada ejecuta lo que toca; la API encola para un worker la sincronización de NVD y la revisión de avisos, porque necesitan los motores o tardan.