# Evolution Go (API WhatsApp en Go) — stack para el host casero. # # Fuente: https://github.com/evolution-foundation/evolution-go (clon local en # projects/evolution-go, tag 0.7.2). Imagen publicada: evoapicloud/evolution-go. # # Por qué este compose y no el de upstream (docker/examples/docker-compose.yml): # - publica `ports:` 4000 y 5432 al host; aquí el 80/443 y el resto de puertos # los gestiona Traefik/Coolify y no hay que publicar nada (§2.3 del contrato). # - monta ./init-db.sql por ruta local: imposible 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) crea la DB del DSN al arrancar. # - usa vars que el código de 0.7.2 ya no lee (WADEBUG/LOGTYPE); las reales son # DEBUG_ENABLED/LOG_TYPE (pkg/config/env/env.go). # # Detalles verificados contra el código 0.7.2: # - GateMiddleware (pkg/core/c0.go) devuelve 503 en TODO hasta activar licencia, # EXCEPTO /server/ok, /manager, /assets, /license/*, /swagger, /ws. El # healthcheck usa /server/ok (200 siempre) para no dejar al contenedor sin # ruta en Traefik antes de activar la licencia desde el Manager. # - whatsmeow guarda las sesiones SQLite en /app/dbdata (exPath = /app): # SIEMPRE volumen con nombre o cada redeploy desvincula los teléfonos. # - POSTGRES_AUTH_DB (URI completa) es OBLIGATORIA aunque parezca opcional: # con string vacío initPostgresAuthDB() devuelve (nil, nil) —sin error— y # NewPollService() hace panic por nil deref sobre el *sql.DB (bug upstream # 0.7.2, cmd/evolution-go/main.go:300 + pkg/poll/service/poll_service.go:39). # La URI interpola ${POSTGRES_PASSWORD}: Coolify sustituye al deployear, # el secreto vive solo en la env del servicio. # - POSTGRES_USERS_DB en URI para seguir el contrato upstream (con las vars # discretas también funciona; la DB evogo_users se auto-crea igual). # - DATABASE_SAVE_MESSAGES y GLOBAL_API_KEY son obligatorias (panicIfEmpty). # - SERVER_PORT no tiene default en el código: fijarlo siempre. # # Contrato: docs/AGENTS-coolify-apps.md # - sin publicar 80/443: solo `expose`, Traefik enruta (§2.3) # - DB hermana por nombre de servicio, nunca localhost (§2.1) # - secretos (${VAR} sin default) llegan como env de Coolify, jamás aquí (§2.5) # - healthchecks con start_period holgado: el primer arranque aquí tarda # minutos (docs/casos/coolify-servicio-nuevo-503-no-available-server.md) services: evolution-go: image: 'evoapicloud/evolution-go:0.7.2' environment: SERVER_PORT: '8080' CLIENT_NAME: '${CLIENT_NAME:-evolution}' # Obligatoria (panicIfEmpty). Secreto: inyectada por Coolify. GLOBAL_API_KEY: '${GLOBAL_API_KEY}' # Obligatoria y no vacía (panicIfEmpty). DATABASE_SAVE_MESSAGES: '${DATABASE_SAVE_MESSAGES:-false}' # OBLIGATORIA en URI (ver cabecera: vacía = panic nil deref en 0.7.2). # Coolify interpola ${POSTGRES_PASSWORD} del env del servicio al deploy. POSTGRES_AUTH_DB: 'postgresql://${POSTGRES_USER:-evolution}:${POSTGRES_PASSWORD}@evolution-postgres:5432/evogo_auth?sslmode=disable' POSTGRES_USERS_DB: 'postgresql://${POSTGRES_USER:-evolution}:${POSTGRES_PASSWORD}@evolution-postgres:5432/evogo_users?sslmode=disable' POSTGRES_HOST: evolution-postgres POSTGRES_PORT: '5432' POSTGRES_USER: '${POSTGRES_USER:-evolution}' POSTGRES_PASSWORD: '${POSTGRES_PASSWORD}' POSTGRES_DB: '${POSTGRES_DB:-evogo_users}' # Nombres reales en 0.7.2 (env.go): DEBUG_ENABLED / LOG_TYPE. DEBUG_ENABLED: '${DEBUG_ENABLED:-INFO}' LOG_TYPE: '${LOG_TYPE:-console}' WEBHOOK_FILES: 'true' CONNECT_ON_STARTUP: 'false' OS_NAME: 'Linux' EVENT_IGNORE_GROUP: 'false' EVENT_IGNORE_STATUS: 'true' QRCODE_MAX_COUNT: '5' # AMQP/NATS/MinIO/WEBHOOK_URL apagados a propósito: nada de colas ni # objeto-storage extra en este host; el Manager funciona igual. AMQP_GLOBAL_ENABLED: 'false' NATS_GLOBAL_ENABLED: 'false' MINIO_ENABLED: 'false' # Sin bloque `ports:` — Traefik llega al 8080 interno (§2.3). FQDN sin # puerto + único `expose`: el mismo patrón verificado del stack firecrawl. expose: - '8080' volumes: # Sesiones whatsmeow (SQLite): perder esto = re-escanear QR de todos los # teléfonos en cada redeploy (§5). - 'evolution-data:/app/dbdata' - 'evolution-logs:/app/logs' depends_on: evolution-postgres: condition: service_healthy # Imagen alpine: wget es el de busybox (curl no viene instalado en 0.7.2). # /server/ok responde 200 sin licencia activa — ver comentario de cabecera. healthcheck: test: ['CMD', 'wget', '-q', '-O', '/dev/null', 'http://127.0.0.1:8080/server/ok'] interval: 15s timeout: 10s retries: 20 start_period: 300s mem_limit: 1g memswap_limit: 1g cpus: 1.5 restart: unless-stopped logging: driver: json-file options: max-size: 10m max-file: '3' evolution-postgres: image: 'postgres:16-alpine' environment: POSTGRES_USER: '${POSTGRES_USER:-evolution}' POSTGRES_PASSWORD: '${POSTGRES_PASSWORD}' POSTGRES_DB: '${POSTGRES_DB:-evogo_users}' expose: - '5432' healthcheck: test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-evolution} -d ${POSTGRES_DB:-evogo_users}'] interval: 15s timeout: 10s retries: 20 start_period: 180s volumes: - 'evolution-postgres:/var/lib/postgresql/data' mem_limit: 1g memswap_limit: 1g restart: unless-stopped logging: driver: json-file options: max-size: 5m max-file: '2' volumes: evolution-data: {} evolution-logs: {} evolution-postgres: {}