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), proyectoAI AGENCY/production. Resultado:https://evo.urieljareth.org/server/ok→ HTTP 200 ({"status":"ok"}), Manager UI operativo, contenedoreshealthy. 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)cuandoPOSTGRES_AUTH_DB == "": sin error.main.go:408pasa ese nil asetupRouter.pkg/poll/service/poll_service.go:39—autoMigratedereferencia 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)
-
Si el magic link del portal dice "ya usado o expiró":
GET /license/registercachea en memoria la primera sesión de registro (rc._v8enpkg/core/c0.go:710) y devuelve siempre la mismaregister_urlaunque el portal ya la haya invalidado (link consumido por preview del cliente de correo, doble click, o expirado). Fix verificado:docker restartdel contenedor app → siguiente/license/registerpide 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 uncodeque se canjea conGET /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 usedal canjear). La activación se completó así:docker restart(limpia la sesión cacheada) → iniciar el registro desde el Manager (para que mande suredirect_uriy la vuelta sea automática) → en el portal, botón Entrar com Google → redirección de vuelta al Manager →/license/status=active. -
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 laGLOBAL_API_KEY— visible en Coolify: proyecto AI AGENCY → servicio evolution-go → pestaña Environment. Hasta entonces toda la API responde 503LICENSE_REQUIRED(el Manager sí funciona). Alternativa por API:GET /license/registerdevuelve la URL de registro. -
Conectar WhatsApp: desde el Manager crear una instancia → escanear el QR (
POST /instance/create,GET /instance/qrcon headerapikey). Las sesiones persisten en el volumenevolution-data(/app/dbdata). -
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 Nodeevoapicloud/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 llamaapi-q6tn..., noevolution-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 deGet-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, repasarpkg/config/env/env.godel nuevo tag (los nombres de variables cambian entre versiones) y PATCH + start de nuevo.