Files
Proxmox-Coolify-Manager/docs/casos/evolution-go-stack.md
T

9.0 KiB

Caso: evolution-go (API WhatsApp en Go) desplegado junto a Chatwoot

Resuelto el 2026-09-02 contra el host real. Target: LXC 102 (coolify), proyecto AI AGENCY / production. Resultado: https://evo.urieljareth.org/server/ok → HTTP 200 ({"status":"ok"}), Manager UI operativo, contenedores healthy. Licencia ACTIVA desde el 2026-09-02 (vía OAuth Google del portal; ver §3.0).


0. Resumen ejecutivo

El usuario pidió clonar evolution-foundation/evolution-go (rewritten en Go de Evolution API, motor WhatsApp sobre whatsmeow) e "implementar la funcionalidad" en el servicio Chatwoot (/project/cho4d488omzjm4noyz98mwq7/environment/xhcy6urwmtk0onnxoeec24hq/service/c11xzy2tx2cdapm32f5b89vy).

Decisión: el stack se desplegó como servicio hermano (evolution-go, uuid j0jkacsfcgypm2jmpillls01) en el mismo proyecto y entorno que Chatwoot, no dentro del compose de Chatwoot. Motivos:

  • Editar el compose del stack Chatwoot fuerza un redeploy completo de Chatwoot (riesgo sobre un stack parcheado a mano — ver chatwoot-enterprise-patch.md).
  • Evolution-go necesita su propio PostgreSQL; meterle una DB ajena al stack de Chatwoot complica el rollback.
  • La integración WhatsApp→Chatwoot se hace por webhook/API hacia el FQDN público de Chatwoot — no requiere red compartida.

El clon local vive en projects/evolution-go (tag 0.7.2). El compose de despliegue vive versionado en stacks/evolution-go/docker-compose.coolify.yml.

Pieza Valor
Servicio Coolify evolution-go (j0jkacsfcgypm2jmpillls01)
Proyecto / entorno AI AGENCY / production (mismo que Chatwoot)
Imagen app evoapicloud/evolution-go:0.7.2 (pinada, Docker Hub)
Imagen DB postgres:16-alpine (hermana, evolution-postgres)
FQDN https://evo.urieljareth.org (wildcard del túnel, sin cambios CF)
Healthcheck wget http://127.0.0.1:8080/server/ok (200 sin licencia)
Secretos GLOBAL_API_KEY (40 car.) y POSTGRES_PASSWORD (24 car.) como envs del servicio, generados en memoria

1. Bugs y trampas encontrados (lo que costó tiempo)

1.1 POSTGRES_AUTH_DB vacía = panic (bug upstream 0.7.2)

El primer arranque crash-loopeaba (exit 2). Stack trace: NewPollService → autoMigrate sobre un *sql.DB nil.

Cadena exacta en el código:

  • cmd/evolution-go/main.go:300 — initPostgresAuthDB() devuelve (nil, nil) cuando POSTGRES_AUTH_DB == "": sin error.
  • main.go:408 pasa ese nil a setupRouter.
  • pkg/poll/service/poll_service.go:39 — autoMigrate dereferencia el nil → panic.

Es decir: la variable parece opcional (README no la marca obligatoria) pero sin ella el binario muere en loop. El fix fue setearla como URI completa: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@evolution-postgres:5432/evogo_auth?sslmode=disable (interpolada por Coolify al deploy, el secreto no vive en el compose).

1.2 Los nombres de env del README están desactualizados

docker/examples/docker-compose.yml y el README usan WADEBUG/LOGTYPE, pero el código 0.7.2 (pkg/config/env/env.go) lee DEBUG_ENABLED y LOG_TYPE. Además DATABASE_SAVE_MESSAGES es obligatoria no-vacía (panicIfEmpty) aunque parezca opcional. La fuente de verdad es env.go.

1.3 PATCH /services/{uuid} rechaza campos de creación

New-CoolifyService.ps1 en su flujo de actualización (-ServiceUuid) enviaba project_uuid/environment_name/server_uuid y la API responde 422 "This field is not allowed" para los tres. Solo acepta name, docker_compose_raw y urls. Corregido en el script el 2026-09-02 (el caso firecrawl solo ejercitó la creación, no la actualización).

1.4 La licencia bloquea la API — pero no al Manager

GateMiddleware (pkg/core/c0.go:638) devuelve 503 LICENSE_REQUIRED en todo hasta activar licencia, con excepciones: /server/ok, /health, /manager*, /assets*, /license/*, /swagger*, /ws. Esto es crítico para el healthcheck: como Traefik solo enruta contenedores healthy (ver el caso del 503), un healthcheck contra cualquier endpoint bloqueado habría dejado al Manager inalcanzable — deadlock imposible de activar. /server/ok responde 200 siempre.

1.5 No se puede montar init-db.sql por ruta

El compose de upstream monta ./init-db.sql en el postgres. En Coolify el compose se guarda como docker_compose_raw en la DB — no hay árbol de archivos. No hace falta: ensureDBExists() (pkg/config/config.go:79) crea las DBs del DSN al arrancar (evogo_auth, evogo_users).


2. Cómo se reproduce

. .\.env.local.ps1

# 1. Crear (sin arrancar)
.\deploy_skill\scripts\New-CoolifyService.ps1 `
  -AppPath .\stacks\evolution-go `
  -AppName evolution-go `
  -Fqdn https://evo.urieljareth.org `
  -PrimaryService evolution-go `
  -ProjectName "AI AGENCY" -EnvironmentName production -NoDeploy -Force

# 2. Secretos (POST /envs da 409 con vars ya sembradas: usar bulk PATCH;
#    generados en memoria, nunca en disco)
#    PATCH /services/j0jkacsfcgypm2jmpillls01/envs/bulk
#    data: [{POSTGRES_PASSWORD}, {GLOBAL_API_KEY}] con is_literal

# 3. Arrancar y esperar (primer boot: minutos)
Invoke-CoolifyApi.ps1 -Method POST -Path "/services/j0jkacsfcgypm2jmpillls01/start"
.\coolify_skill\scripts\Test-CoolifyServiceReady.ps1 -Uuid j0jkacsfcgypm2jmpillls01 -WaitSeconds 600

# 4. Verificación funcional
curl.exe -sS https://evo.urieljareth.org/server/ok      # {"status":"ok"}
curl.exe -sSI https://evo.urieljareth.org/manager/login  # 200

3. Qué queda pendiente del lado del usuario (manual)

  1. Si el magic link del portal dice "ya usado o expiró": GET /license/register cachea en memoria la primera sesión de registro (rc._v8 en pkg/core/c0.go:710) y devuelve siempre la misma register_url aunque el portal ya la haya invalidado (link consumido por preview del cliente de correo, doble click, o expirado). Fix verificado: docker restart del contenedor app → siguiente /license/register pide sesión nueva al portal. Después: abrir el magic link una sola vez y directamente (los previews de Outlook/Gmail consumen links single-use sin que los abras). Mejor aún: la página del portal ofrece OAuth con Google/GitHub, que evita el magic link por completo (verificado 2026-09-02: la sesión sobrevive aunque el magic link muera; tras el OAuth queda un code que se canjea con GET /license/activate?code=...).

    Resultado final: el magic link falló 3/3 (el cliente de correo del usuario consumía el link single-use antes que el navegador — el portal respondía authorization code expired or already used al canjear). La activación se completó así: docker restart (limpia la sesión cacheada) → iniciar el registro desde el Manager (para que mande su redirect_uri y la vuelta sea automática) → en el portal, botón Entrar com Google → redirección de vuelta al Manager → /license/status = active.

  2. Activar la licencia (requiere cuenta en Evolution Foundation): abrir https://evo.urieljareth.org/manager/login, entrar con la API URL (https://evo.urieljareth.org) y la GLOBAL_API_KEY — visible en Coolify: proyecto AI AGENCY → servicio evolution-go → pestaña Environment. Hasta entonces toda la API responde 503 LICENSE_REQUIRED (el Manager sí funciona). Alternativa por API: GET /license/register devuelve la URL de registro.

  3. Conectar WhatsApp: desde el Manager crear una instancia → escanear el QR (POST /instance/create, GET /instance/qr con header apikey). Las sesiones persisten en el volumen evolution-data (/app/dbdata).

  4. Enlazar con Chatwoot: evolution-go no trae integración Chatwoot nativa (cero menciones en el código, a diferencia de evolution-api Node). El puente sería por webhook (WEBHOOK_URL) hacia un inbox tipo API de Chatwoot, o usar el servicio evolution-api Node viejo que sí la tiene.

4. Notas de estado

  • El servicio viejo evolution-api (q6tnsvkvrjw4g0ab532l3r1s, imagen Node evoapicloud/evolution-api:v2.3.7, mismo entorno) está en producción en https://evoapi.urieljareth.org (api/postgres/redis, 13+ días healthy; el contenedor app se llama api-q6tn..., no evolution-api-... — cuidado con los greps). Tiene 4 instancias WhatsApp (Personal, JM, INSTA, Asesoria Personal) sin integración Chatwoot configurada. NOTA 2026-09-02: este repo documentó erróneamente "app detenida" por un filtro truncado de Get-CoolifyDockerStatus; corregido tras verificación directa.
  • El compose normalizado por Coolify borra los comentarios; la versión documentada es la del repo (stacks/evolution-go/).
  • Imagen pinada a 0.7.2 (tag del repo clonado). Para subir de versión: cambiar el tag, repasar pkg/config/env/env.go del nuevo tag (los nombres de variables cambian entre versiones) y PATCH + start de nuevo.