Saltar al contenido principal

Despliegue de la aplicación

Patrón general del VPS: cada pieza es una aplicación Compose de Dokploy desplegada desde Git, unida a la red externa dokploy-network (Traefik enruta por dominio), con volúmenes con nombre, secretos solo en las variables de entorno de Dokploy y restart: unless-stopped. La imagen se construye en el servidor al desplegar; no se compila nada en local.

Orden recomendado​

  1. Base de datos: un servicio Database → PostgreSQL en Dokploy. No requiere SQL manual (ver Despliegue con Dokploy).
  2. API (ganadero-api): migraciones y API en un mismo Compose, conectados a esa base con DATABASE_URL. Ver abajo.
  3. Aplicación web (ganadero-web), apuntando a la URL de la API.
  4. Manual (manual-ganadero), opcionalmente con Basic Auth. Ver Despliegue con Dokploy.

Servicios de la API​

PostgreSQL es externo (servicio de Dokploy) y el docker-compose.yml de ganadero-api define dos servicios, ambos en la red dokploy-network y con la misma DATABASE_URL:

ServicioFunción
migrateOne-shot: crea (si falta) el rol sin privilegios ganadero_app y aplica las migraciones. Termina y sale.
apiArranca solo si migrate terminó con éxito; verifica que puede ejecutar cada transacción como ganadero_app (si no, se niega a arrancar); healthcheck a /health/ready.

migrate es un servicio aparte (y no un paso de arranque de la API) porque un fallo de migración detiene el despliegue antes de arrancar la API y, con varias réplicas, no corren migraciones concurrentes.

Pasos (API)​

  1. Cree el PostgreSQL en Dokploy y copie su conexión interna: usuario, clave, Internal Host y base. Esa es su DATABASE_URL; no hay que ejecutar SQL.
  2. En Dokploy: Create Service → Compose, fuente Git, ruta ./docker-compose.yml. La red dokploy-network debe existir.
  3. En Environment cargue las variables de la sección PRODUCCIÓN del .env.example de la API. Son obligatorias DATABASE_URL, JWT_ACCESS_SECRET y WEB_ORIGIN (sin ellas el Compose falla a propósito). Si el usuario o la clave de la base tienen caracteres especiales, codifíquelos en la DATABASE_URL (@ → %40, : → %3A, / → %2F). Ver Variables de entorno.
  4. En Domains asigne el dominio de la API (HTTPS con Let's Encrypt) al servicio api, puerto 3000. Traefik es el único punto público.
  5. Despliegue y verifique https://<api>/health/ready. El primer despliegue aplica el esquema solo.
  6. Correo: por defecto MAIL_DRIVER=console; la API arranca igual y registra el aviso correos deshabilitados (MAIL_DRIVER=console), pero nadie recibe invitaciones ni enlaces de restablecimiento. Para activarlo defina MAIL_DRIVER=smtp, SMTP_HOST, MAIL_FROM y, si aplica, SMTP_USER/SMTP_PASSWORD.
  7. Para rotar la clave de la base, cámbiela en el servicio PostgreSQL de Dokploy, actualice DATABASE_URL y redespliegue.
  8. Primer usuario y organización: desde la aplicación web, Registrarse (/authentication/signup). Los datos de demostración de desarrollo (db:seed) no corren en producción.

Para validar la sintaxis sin desplegar:

DATABASE_URL=postgres://admin:x@db:5432/ganadero JWT_ACCESS_SECRET=<32+ caracteres> WEB_ORIGIN=https://a.co docker compose --env-file /dev/null config -q

Pasos (aplicación web)​

  1. Create Service → Docker Compose apuntando al repositorio ganadero-web (docker-compose.yml). El Dockerfile compila Angular dentro de Docker (node:24-alpine) y lo sirve con nginx.
  2. Defina las variables (ver Variables de entorno): como mínimo API_URL.
  3. Asigne el dominio al servicio web, puerto 80 (Traefik termina el HTTPS). No se publica ningún puerto en el host.
  4. Despliegue. Al arrancar, el contenedor genera /env.js y las cabeceras de seguridad (CSP) con esas variables: cambiar API_URL o la CSP no requiere reconstruir, basta editar la variable y reiniciar.

Cookies y CORS entre dominios​

La sesión usa una cookie de refresco HttpOnly; Secure; SameSite=Strict. Verifique que WEB_ORIGIN de la API sea exactamente el origen de la aplicación web. Si la web y la API están en dominios hermanos (app.x.com y api.x.com) la cookie debe poder compartirse entre ambos; en caso de duda, revise COOKIE_SAMESITE y el dominio de la cookie.

Salud y proxy​

  • GET /health y GET /health/ready (API); GET /healthz (manual).
  • Detrás de Traefik se necesita TRUST_PROXY_HOPS=1 (es el valor por defecto del Compose) para que el límite de intentos de /auth/* use la IP real del cliente y no la del proxy.

Respaldos​

Los respaldos se hacen sobre el servicio PostgreSQL de Dokploy (pestaña Backups de su ficha); la política está pendiente de definir, ver Respaldos y restauración.