# Caso: open-seo vuelve a gestión completa de Coolify (imagen precompilada) **Fecha:** 2026-09-04/05 · **App:** `open-seo:main-0fgs5kwaab9esytaxkddsvts` (uuid `kj0kccsb4d46tm0d6qe6docy`, id DB 57) · **FQDN:** `https://kj0kccsb4d46tm0d6qe6docy.urieljareth.org` ## Contexto El sitio público estaba sirviéndose por una **cadena manual improvisada** tras la caída del 2026-08-27 22:14: ``` Traefik → open-seo-sidecar (nginx:alpine manual, montado 22:25 ese día) → proxy_pass → test-openseo (docker run manual de ghcr.io/every-app/open-seo:latest) ``` La aplicación en Coolify quedó `exited:unhealthy` sin contenedor. El usuario fijó como objetivo: **todo gestionable desde Coolify**. ## Qué se hizo (en orden) 1. **Limpieza de filas huérfanas de env vars** (ids 1152-1156, app 52 `insta-portal`): eran duplicados invisibles de un INSERT SQL manual con el morph type mal escapado (`App\\Models\\Application`). Las variables reales ya existían cifradas (ids 1161-1170) → se **borraron** los duplicados, no se activaron. Backup: `/root/backups/envvar-orphans-1152-1156-20260904-212119.tsv`. Tras esto: 0 valores sin cifrar en `environment_variables` de toda la instancia. 2. **Deploy git+railpack (intento 1):** `POST /deploy` contra el origen. El build tardó ~23 min y terminó, pero la app servía **404**: el repo (`github.com/every-app/open-seo`, público, actualizado ese mismo día) ahora compila un monorepo (`dist/client|server|open_seo_audit`, sin `index.html` en raíz) y railpack eligió un plan "estático con Caddy" que no corresponde. 3. **Conversión a imagen precompilada** (doctrina del caso firecrawl): - API: `docker_registry_image_name=ghcr.io/every-app/open-seo`, `docker_registry_image_tag=latest` (la API acepta estos campos). - DB: `UPDATE applications SET build_pack='dockerimage' WHERE id=57` — la API **rechaza** `build_pack=dockerimage` en PATCH (enum de validación sin ese valor, 422 "The selected build pack is invalid"), aunque el pipeline de deploy lo soporta de forma nativa (`deploy_dockerimage_buildpack` usa `docker_registry_image_name`, no `static_image`). Backup previo: `/root/backups/app57-pre-dockerimage-20260904-215456.tsv`. - Deploy 2: pull de `:latest` + rolling update. El contenedor **crash-loopeaba (exit 1)**: el preflight de la nueva imagen exige configurar auth. 4. **Env vars nuevas vía API** (`POST /applications/{uuid}/envs` — cifra por modelo, sin riesgo del bug de texto plano): - `AUTH_MODE=local_noauth` — replica el estado previo (el sitio ya corría público sin auth vía sidecar). Para Cloudflare Access: `AUTH_MODE=cloudflare_access` + `TEAM_DOMAIN` + `POLICY_AUD`. - `ALLOWED_HOST=kj0kccsb4d46tm0d6qe6docy.urieljareth.org` — allowlist de Vite detrás de proxy. - Deploy 3: contenedor **healthy** (la imagen GHCR trae healthcheck con `start_period=300s`, a diferencia de los servicios del §1.5 del índice). 5. **Retiro de los contenedores manuales** (con snapshots previos en `/root/backups/*-inspect-20260904-212317.json`): - `open-seo-sidecar` (nginx) — además sus labels duplicaban los routers de Traefik del FQDN y provocaban 503 mientras coexistía con el contenedor nuevo. - `test-openseo` (backend manual) — ya sin referencias. ## Resultado ``` status=running:healthy build_pack=dockerimage image=ghcr.io/every-app/open-seo:latest FQDN → HTTP 200