CRM de WhatsApp Open Source

Notibuzz es software libre pensado para desplegarse en tu propia infraestructura con Docker. Sin planes comerciales: levantas el stack en un VPS, conectas WhatsApp y operas con el CRM completo.

100% Open Source

Código libre. Sin suscripciones ni planes de pago. El software es tuyo.

Docker & contenedores

Despliega con Docker Compose en minutos: servicios aislados, reproducibles y escalables.

Self-hosted

Tu VPS, tu cloud o tu red local. Tus datos nunca salen de tu infraestructura.

API REST + SDKs

Integra WhatsApp con tu stack. Documentación y ejemplos incluidos.

Contenedores listos

Cada componente del stack corre en su propio contenedor. Actualiza, reinicia o escala sin tocar el host.

Infraestructura tuya

Sin vendor lock-in. Migras de proveedor cuando quieras llevando volúmenes y configuración.

Privacidad total

Mensajes, contactos y credenciales permanecen en tu entorno. Ideal para equipos con datos sensibles.

Extensible

Modifica el código, añade módulos o conecta webhooks a tu ERP, e-commerce o BI.

Todo incluido

Un solo despliegue: CRM, API, IA, workers y bandeja. Sin módulos de pago ni feature flags comerciales.

Escala con tu hardware

Más sesiones, más agentes, más volumen — limitado solo por los recursos que asignes a los contenedores.

Todo el producto, sin restricciones

  • Bandeja unificada y multi-sesión WhatsApp
  • Chats, contactos, plantillas y campañas
  • Dashboard, workers y monitor de eventos
  • RBAC: usuarios, roles y permisos
  • Chatbot y Copilot (IA)
  • API REST ilimitada y webhooks
  • SDKs JavaScript y Python

Guía de despliegue Docker

Elige producción en VPS o prueba en local con Traefik + HTTPS (mkcert).

Stack productivo con Docker Compose: Traefik termina HTTPS, enruta por path y orquesta MongoDB, Redis, WAHA, Hub, Auth, Bridge, Media, IA y el frontend del CRM.

Mínimo recomendado

  • 2 vCPU · 4 GB RAM
  • 40 GB SSD
  • Ubuntu 22.04 LTS (o similar con Docker)
  • 80 y 443 abiertos (HTTPS vía Traefik)

Producción con IA y varias sesiones

  • 4 vCPU · 8 GB RAM
  • 80 GB SSD
  • Ubuntu 22.04 LTS
  • 80 y 443 + registro DNS apuntando al VPS

Arquitectura del stack

ServicioFunción
TraefikReverse proxy, HTTPS (Let's Encrypt) y enrutamiento por path
noti-sender-webFrontend CRM (Nuxt)
noti-sender-hubAPI REST y WebSocket en tiempo real
noti-sender-wahaBridge WhatsApp / WAHA (sesiones y mensajes)
noti-sender-authAutenticación JWT y dispositivos vinculados
noti-sender-bridgeCola de envío, rate limiting y bulk
noti-sender-mediaArchivos multimedia de conversaciones
noti-sender-iaChatbot, Copilot y RAG (opcional)
MongoDBBase de datos principal (sesiones, contactos, config)
RedisCache, colas y pub/sub entre servicios

Red Docker compartida

Todos los contenedores se conectan a la red bridge externa notibuzz-network. Créala una vez con docker network create notibuzz-network antes de docker compose up. Traefik descubre servicios por labels en esa misma red (--providers.docker.network=notibuzz-network).

Planes comerciales (opcional)

Si despliegas para vender o comercializar el CRM, asigna un plan por cliente con setupPlansAndSubscription.js. Self-hosted sin venta: crea admin y asigna BUSINESS o PRO a tu propio client-id.

Los precios mensual/anual son estándar preconfigurados al ejecutar setupPlansAndSubscription.js --init-plans-only. Si deseas cambiar el precio u otros valores (sesiones, tokens IA, agentes…), revisa la colección plans en MongoDB y edita el plan correspondiente. La columna de tokens IA es el cupo mensual de consumo vía DeepSeek (Chatbot/Copilot en noti-sender-ia); requiere DEEPSEEK_API_KEY en el compose y se renueva automáticamente cada mes según la fecha de inicio de la suscripción.

PlanSesiones
DEVELOPERAPI / developers — sin dashboard CRM completo8
STARTEREquipos pequeños — CRM + IA + campañas básicas8
PROEmpresas en crecimiento — incluye Copilot15
BUSINESSMáxima capacidad — multi-agente y bulk avanzado20

Pasos en producción

  1. 1

    Prepara el VPS

    Instala Docker Engine y Docker Compose v2. Asegura firewall con 80/443 abiertos y SSH restringido.

    Proveedores habituales: Hetzner, DigitalOcean, AWS Lightsail, OVH, etc.

    Reserva RAM extra si activas el servicio de IA (embeddings en CPU).

    curl -fsSL https://get.docker.com | sh
    sudo usermod -aG docker $USER
    docker compose version
  2. 2

    Configura DNS

    Apunta un registro A (o AAAA) de tu dominio a la IP pública del VPS. Espera propagación antes de solicitar certificados.

    Ejemplo: crm.tuempresa.com → 203.0.113.10

    Opcional: registro www con redirect al dominio principal.

  3. 3

    Crea la red Docker (bridge externa)

    Todos los servicios se conectan a una red bridge compartida. Debe existir antes de levantar el stack porque el compose la referencia como external.

    Driver bridge: los contenedores se resuelven por nombre (redis, mongodb, noti-sender-hub…).

    Traefik usa --providers.docker.network=notibuzz-network — debe coincidir con el nombre real de la red.

    Si la red ya existe, omite create (no falla: docker network create || true).

    MongoDB y Redis solo están en esta red; no se publican puertos al host.

    docker network create notibuzz-network
    docker network inspect notibuzz-network --format '{{.Name}} · {{.Driver}} · {{.Scope}}'

    Bloque networks en docker-compose.yaml

    networks:
      notibuzz-network:
        external: true
        name: notibuzz-network
  4. 4

    Crea docker-compose.yaml

    En tu VPS crea un directorio (por ejemplo ~/notibuzz), guarda el archivo docker-compose.yaml con el contenido siguiente y reemplaza cada placeholder TU_* y el dominio de ejemplo.

    Busca y reemplaza crm.tu-dominio.com por tu dominio real en todas las labels Traefik.

    Imagen WAHA: revisa https://waha.devlike.pro/docs/overview/quick-start/ y coloca la imagen correcta (devlikeapro/waha o :arm en Apple Silicon).

    Usa la misma TU_WAHA_API_KEY en waha, hub y bridge.

    TU_REDIS_PASSWORD debe coincidir en redis, waha, hub, auth, bridge, ia y media (REDIS_HOST=redis).

    noti-sender-media: MEDIA_PUBLIC_BASE_URL=https://TU_DOMINIO/media para que WAHA descargue archivos.

    mkdir -p ~/notibuzz && cd ~/notibuzz
    nano docker-compose.yaml

    Reemplaza estos placeholders en el YAML:

    • crm.tu-dominio.comTu dominio público (DNS → IP del VPS)
    • TU_MONGO_PASSWORDContraseña root de MongoDB
    • TU_REDIS_PASSWORDContraseña Redis (misma en todos los servicios)
    • TU_WAHA_API_KEYClave API WAHA — openssl rand -hex 16
    • TU_WAHA_DASHBOARD_PASSWORDPanel WAHA y Swagger
    • TU_JWT_SECRETJWT access — openssl rand -hex 32
    • TU_JWT_REFRESH_SECRETJWT refresh — openssl rand -hex 32
    • TU_DEEPSEEK_API_KEYOpcional, solo si usas IA
    • tu-email@ejemplo.comEmail Let's Encrypt (Traefik)
    • devlikeapro/wahaImagen WAHA — revisa https://waha.devlike.pro/docs/overview/quick-start/
    • MEDIA_PUBLIC_BASE_URLURL pública de media — https://TU_DOMINIO/media (WAHA descarga archivos desde ahí)
    • notibuzz-networkRed Docker bridge externa — créala antes de docker compose up

    docker-compose.local.yaml

    # Notibuzz — docker-compose.yaml (producción / VPS)
    # Copia este archivo en tu servidor y reemplaza los valores TU_* y tu-dominio.com
    #
    # Antes del primer up: docker network create notibuzz-network
    
    
    version: '3.8'
    
    services:
      # MongoDB - Base de datos principal
      mongodb:
        image: mongo:7.0
        container_name: notibuzz-mongodb
        restart: unless-stopped
        expose:
          - "27017"
        environment:
          MONGO_INITDB_ROOT_USERNAME: root
          MONGO_INITDB_ROOT_PASSWORD: TU_MONGO_PASSWORD
          MONGO_INITDB_DATABASE: notibuzz
        volumes:
          - mongodb_data:/data/db
          - mongodb_config:/data/configdb
        networks:
          - notibuzz-network
        healthcheck:
          test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
          interval: 10s
          timeout: 5s
          retries: 5
          start_period: 10s
    
      # Redis - Cache y colas
      redis:
        image: redis:7-alpine
        container_name: notibuzz-redis
        restart: unless-stopped
        expose:
          - "6379"
        command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-TU_REDIS_PASSWORD}
        volumes:
          - redis_data:/data
        networks:
          - notibuzz-network
        healthcheck:
          test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
          interval: 10s
          timeout: 3s
          retries: 5
          start_period: 10s
    
      # noti-sender-waha - API principal de WhatsApp (WAHA)
      noti-sender-waha:
        # Imagen WAHA: revisa https://waha.devlike.pro/docs/overview/quick-start/
        # y coloca la imagen correcta (ej. devlikeapro/waha; en ARM: devlikeapro/waha:arm).
        image: devlikeapro/waha
        container_name: noti-sender-waha
        restart: unless-stopped
        expose:
          - "3000"
        #env_file:
        #  - noti-sender-waha/.env
        environment:
          # ==================
          # ===== COMMON =====
          # ==================
          WAHA_BASE_URL: http://noti-sender-waha:3000
    
          # ====================
          # ===== SECURITY =====
          # ====================
          WAHA_API_KEY: TU_WAHA_API_KEY
          WAHA_DASHBOARD_USERNAME: admin
          WAHA_DASHBOARD_PASSWORD: TU_WAHA_DASHBOARD_PASSWORD
          WHATSAPP_SWAGGER_USERNAME: admin
          WHATSAPP_SWAGGER_PASSWORD: TU_WAHA_DASHBOARD_PASSWORD
          WHATSAPP_DEFAULT_ENGINE: NOWEB
    
          # ===================
          # ===== LOGGING =====
          # ===================
          WAHA_LOG_FORMAT: JSON
          WAHA_LOG_LEVEL: info
          WAHA_PRINT_QR: "false"
    
          # =========================
          # ===== MEDIA STORAGE =====
          # =========================
          WAHA_MEDIA_STORAGE: LOCAL
          WHATSAPP_FILES_LIFETIME: 0
          WHATSAPP_FILES_FOLDER: /tmp/whatsapp-files
          WHATSAPP_DOWNLOAD_MEDIA: "true"
          WHATSAPP_FILES_MIMETYPES: "image/jpeg,image/png,image/webp,video/mp4,image/gif,application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation,audio/mpeg,audio/ogg,audio/opus,text/csv"
    
          # ===========================
          # ===== SESSION STORAGE =====
          # ===========================
          WHATSAPP_SESSIONS_MONGO_URL: mongodb://root:TU_MONGO_PASSWORD@mongodb:27017?authSource=admin
    
          # =================
          # ===== APPS ======
          # =================
          REDIS_URL: redis://:TU_REDIS_PASSWORD@redis:6379
    
          # ==================================
          # ===== ADVANCED CONFIGURATION =====
          # ==================================
          TZ: America/Lima
    
        volumes:
          - waha_sessions:/app/sessions
          # Guardar archivos multimedia en /tmp/whatsapp-files para compartir con noti-sender-media
          - waha_files:/tmp/whatsapp-files
        labels:
          - "traefik.enable=true"
          - "traefik.http.routers.waha.rule=Host(`crm.tu-dominio.com`) && PathPrefix(`/waha`)"
          - "traefik.http.routers.waha.entrypoints=websecure"
          - "traefik.http.routers.waha.tls.certresolver=letsencrypt"
          - "traefik.http.routers.waha.service=waha"
          - "traefik.http.routers.waha.middlewares=waha-stripprefix"
          - "traefik.http.services.waha.loadbalancer.server.port=3000"
          - "traefik.http.middlewares.waha-stripprefix.stripprefix.prefixes=/waha"
        networks:
          - notibuzz-network
    
      # noti-sender-hub - Hub de WebSocket y API REST
      noti-sender-hub:
        image: hilosdf/noti-sender-hub:60f414f #142bb5a
        container_name: noti-sender-hub
        restart: unless-stopped
        expose:
          - "3001"  # WebSocket
          - "3002"  # API REST
        #env_file:
        #  - noti-sender-hub/.env
        environment:
          # ==========================
          # PUERTOS
          # ==========================
          HUB_PORT: 3001
          HTTP_PORT: 3002
    
          # ==========================
          # BASE DE DATOS (MongoDB)
          # ==========================
          MONGODB_URI: mongodb://root:TU_MONGO_PASSWORD@mongodb:27017/notibuzz?authSource=admin
    
          # ==========================
          # REDIS
          # ==========================
          REDIS_ENABLED: "true"
          REDIS_URL: redis://:TU_REDIS_PASSWORD@redis:6379
          REDIS_HOST: redis
          REDIS_PORT: 6379
          REDIS_PASSWORD: TU_REDIS_PASSWORD
          REDIS_DB: 0
          REDIS_CONNECT_TIMEOUT_MS: 5000
          REDIS_RECONNECT_BASE_MS: 1000
          REDIS_RECONNECT_MAX_MS: 10000
          PARTICIPANT_CACHE_TTL_MS: 900000
          PARTICIPANT_CACHE_MAX: 5000
          PARTICIPANT_REQUEST_TIMEOUT_MS: 4000
          PARTICIPANT_CACHE_SWR_THRESHOLD_MS: 120000
          REDIS_PREFIX: "hub:"
          # Pub/Sub compartido con noti-sender-auth (user.devices.changed); no usar REDIS_PREFIX aquí en código.
          REDIS_USER_DEVICES_CHANNEL: "notibuzz:pub:userDevices"
    
          # ==========================
          # API DE WAHA
          # ==========================
          API_WS_URL: ws://noti-sender-waha:3000/ws
          API_KEY: TU_WAHA_API_KEY
          API_BASE_URL: http://noti-sender-waha:3000
    
          # ==========================
          # SESIONES Y EVENTOS
          # ==========================
          SESSION: "*"
          EVENTS: message.any,message.reaction,message.edited,message.revoked,message.waiting
    
          # ==========================
          # BRIDGE
          # ==========================
          BRIDGE_API_KEY: TU_WAHA_API_KEY
          BRIDGE_BASE_URL: http://noti-sender-bridge:3003
    
          # ==========================
          # FRONTEND (CORS)
          # ==========================
          WEB_FRONTEND_HOST: https://crm.tu-dominio.com
    
          # ==========================
          # SERVICIO MULTIMEDIA
          # ==========================
          MEDIA_SERVICE_URL: https://crm.tu-dominio.com/media
    
          # ==========================
          # SERVICIO DE AUTENTICACIÓN
          # ==========================
          # Dentro de Docker Compose, usar HTTP (no HTTPS) y el nombre del servicio
          AUTH_SERVICE_URL: http://noti-sender-auth:3005
    
          # ==========================
          # SERVICIO DE IA
          # ==========================
          # Dentro de Docker Compose, usar HTTP (no HTTPS) y el nombre del servicio
          IA_SERVICE_URL: http://noti-sender-ia:3006
          IA_ENABLED: "true"
          IA_SERVICE_TIMEOUT: 60000
    
          # ==========================
          # LÍMITES DE BODY / MULTIMEDIA (Express + Traefik buffering)
          # ==========================
          # MB: mismo valor en noti-sender-media / bridge. Traefik large-upload en bytes = MB * 1024².
          BODY_LIMIT_MB: 1024
          # Multer /api/media/upload: explícito en bytes (= 1 GiB); si se omite, uploadLimits deriva de BODY_LIMIT_MB.
          MEDIA_UPLOAD_MAX_BYTES: 1073741824
    
          PUSH_AUDIT: 0
          LOG_TO_CONSOLE: 0
    
          PUSH_NON_TEXT_BODY: icon
          PUSH_TEXT_PREVIEW_MAX: 280
    
        volumes:
          - hub_uploads:/app/uploads
          - hub_logs:/app/logs
        labels:
          # API REST Router - /api
          - "traefik.enable=true"
          - "traefik.http.routers.hub-api.rule=Host(`crm.tu-dominio.com`) && PathPrefix(`/api`)"
          - "traefik.http.routers.hub-api.entrypoints=websecure"
          - "traefik.http.routers.hub-api.tls.certresolver=letsencrypt"
          - "traefik.http.routers.hub-api.service=hub-api"
          - "traefik.http.routers.hub-api.middlewares=hub-api-stripprefix,large-upload"
          - "traefik.http.services.hub-api.loadbalancer.server.port=3002"
          - "traefik.http.middlewares.hub-api-stripprefix.stripprefix.prefixes=/api"
          # Buffering: 1 GiB (1024 MiB) = 1073741824 bytes
          - "traefik.http.middlewares.large-upload.buffering.maxRequestBodyBytes=1073741824"
          - "traefik.http.middlewares.large-upload.buffering.memRequestBodyBytes=2097152"
          # API REST Router - /notibuzz (proxy desde frontend, reescribe a /api)
          # Usa un servicio separado sin stripprefix para que Express reciba /api/sessions
          - "traefik.http.routers.hub-notibuzz.rule=Host(`crm.tu-dominio.com`) && PathPrefix(`/notibuzz`)"
          - "traefik.http.routers.hub-notibuzz.priority=5"
          - "traefik.http.routers.hub-notibuzz.entrypoints=websecure"
          - "traefik.http.routers.hub-notibuzz.tls.certresolver=letsencrypt"
          - "traefik.http.routers.hub-notibuzz.service=hub-notibuzz-api"
          - "traefik.http.routers.hub-notibuzz.middlewares=hub-notibuzz-rewrite,large-upload"
          - "traefik.http.services.hub-notibuzz-api.loadbalancer.server.port=3002"
          - "traefik.http.services.hub-notibuzz-api.loadbalancer.passHostHeader=true"
          - "traefik.http.middlewares.hub-notibuzz-rewrite.replacepathregex.regex=^/notibuzz/(.*)"
          - "traefik.http.middlewares.hub-notibuzz-rewrite.replacepathregex.replacement=/api/$$1"
          # Router específico para /notibuzz/web -> /web (sin /api)
          - "traefik.http.routers.hub-notibuzz-web.rule=Host(`crm.tu-dominio.com`) && PathPrefix(`/notibuzz/web`)"
          - "traefik.http.routers.hub-notibuzz-web.priority=10"
          - "traefik.http.routers.hub-notibuzz-web.entrypoints=websecure"
          - "traefik.http.routers.hub-notibuzz-web.tls.certresolver=letsencrypt"
          - "traefik.http.routers.hub-notibuzz-web.service=hub-notibuzz-web"
          - "traefik.http.routers.hub-notibuzz-web.middlewares=hub-notibuzz-web-rewrite,large-upload"
          - "traefik.http.services.hub-notibuzz-web.loadbalancer.server.port=3002"
          - "traefik.http.services.hub-notibuzz-web.loadbalancer.passHostHeader=true"
          - "traefik.http.middlewares.hub-notibuzz-web-rewrite.replacepathregex.regex=^/notibuzz/web/?(.*)"
          - "traefik.http.middlewares.hub-notibuzz-web-rewrite.replacepathregex.replacement=/web/$$1"
          # WebSocket Router - Similar a nginx proxy_pass para WebSocket
          - "traefik.http.routers.hub-ws.rule=Host(`crm.tu-dominio.com`) && PathPrefix(`/ws`)"
          - "traefik.http.routers.hub-ws.entrypoints=websecure"
          - "traefik.http.routers.hub-ws.tls.certresolver=letsencrypt"
          - "traefik.http.routers.hub-ws.service=hub-ws"
          - "traefik.http.routers.hub-ws.middlewares=hub-ws-stripprefix"
          - "traefik.http.services.hub-ws.loadbalancer.server.port=3001"
          - "traefik.http.services.hub-ws.loadbalancer.passHostHeader=true"
          # Middleware para remover el prefijo /ws antes de enviar al backend
          # /ws/?session=*&events=... -> /?session=*&events=...
          - "traefik.http.middlewares.hub-ws-stripprefix.stripprefix.prefixes=/ws"
        networks:
          - notibuzz-network
    
      # noti-sender-auth - Servicio de autenticación con JWT
      noti-sender-auth:
        image: hilosdf/noti-sender-auth:21e7595 #68bd411
        container_name: noti-sender-auth
        restart: unless-stopped
        expose:
          - "3005"
        #env_file:
        #  - ../noti-sender-auth/.env
        environment:
          # ============================================
          # PUERTO
          # ============================================
          PORT: 3005
    
          # ============================================
          # BASE DE DATOS (MongoDB)
          # ============================================
          MONGODB_URI: mongodb://root:TU_MONGO_PASSWORD@mongodb:27017/notibuzz?authSource=admin
    
          # ============================================
          # JWT SECRETS
          # ============================================
          # ⚠️ IMPORTANTE: Cambiar estos valores en producción
          # Generar con: openssl rand -hex 32
          JWT_SECRET: TU_JWT_SECRET
          JWT_REFRESH_SECRET: TU_JWT_REFRESH_SECRET
    
          # ============================================
          # TOKEN EXPIRY
          # ============================================
          ACCESS_TOKEN_EXPIRY: 15m
          REFRESH_TOKEN_EXPIRY: 7d
    
          # ============================================
          # CORS
          # ============================================
          CORS_ORIGIN: https://crm.tu-dominio.com,http://localhost:8080,http://localhost:3002
    
          # ============================================
          # TRUST PROXY
          # ============================================
          # Configurar trust proxy para que Express confíe en Traefik (1 proxy)
          # Esto permite que req.ip obtenga la IP real del cliente desde X-Forwarded-For
          TRUST_PROXY: "1"
    
          # ============================================
          # REDIS (para almacenamiento compartido de challenges)
          # ============================================
          REDIS_ENABLED: "true"
          REDIS_URL: redis://:TU_REDIS_PASSWORD@redis:6379
          REDIS_HOST: redis
          REDIS_PORT: 6379
          REDIS_PASSWORD: TU_REDIS_PASSWORD
          REDIS_DB: 0
          REDIS_CONNECT_TIMEOUT_MS: 5000
          REDIS_RECONNECT_BASE_MS: 1000
          REDIS_RECONNECT_MAX_MS: 10000
          REDIS_PREFIX: "auth:"
          REDIS_USER_DEVICES_CHANNEL: "notibuzz:pub:userDevices"
    
          # ============================================
          # LOGGING
          # ============================================
          LOG_LEVEL: info
          NODE_ENV: production
    
          LINK_DEVICE_MAX_DEVICES_GLOBAL: "5"
          LINK_DEVICE_MAX_DEVICES: "5"
    
    
    
        volumes:
          - auth_logs:/app/logs
        labels:
          - "traefik.enable=true"
          # Router de autenticación - Prioridad alta para asegurar que se evalúe antes que otros routers
          - "traefik.http.routers.auth.rule=Host(`crm.tu-dominio.com`) && PathPrefix(`/auth`)"
          - "traefik.http.routers.auth.priority=20"
          - "traefik.http.routers.auth.entrypoints=websecure"
          - "traefik.http.routers.auth.tls.certresolver=letsencrypt"
          - "traefik.http.routers.auth.service=auth"
          - "traefik.http.services.auth.loadbalancer.server.port=3005"
          - "traefik.http.services.auth.loadbalancer.passHostHeader=true"
        networks:
          - notibuzz-network
        depends_on:
          mongodb:
            condition: service_healthy
    
      # noti-sender-bridge - Bridge para envío de mensajes
      noti-sender-bridge:
        image: hilosdf/noti-sender-bridge:09dcd34
        container_name: noti-sender-bridge
        restart: unless-stopped
        expose:
          - "3003"
        #env_file:
        #  - noti-sender-bridge/.env
        environment:
          # Bridge Configuration
          BRIDGE_PORT: 3003
          BRIDGE_CLUSTER_WORKERS: 0
    
          # API Configuration
          SENDER_API_URL: http://noti-sender-waha:3000
    
          # Hub Configuration
          HUB_BASE_URL: http://noti-sender-hub:3002
    
          # Mongo Configuration
          MONGODB_URI: mongodb://root:TU_MONGO_PASSWORD@mongodb:27017/notibuzz?authSource=admin
    
          # Redis Configuration
          REDIS_URL: redis://:TU_REDIS_PASSWORD@redis:6379
    
          # Queue Configuration
          QUEUE_NAME: noti-send
          QUEUE_CONCURRENCY: 20
    
          # Rate Limit Configuration
          RATE_LIMIT_MAX: 200
          RATE_LIMIT_WINDOW_MS: 1000
    
          # Queue Behavior
          FORCE_QUEUE: "false"
    
          # Bulk Message Configuration
          BULK_MAX_MESSAGES: 500
          BULK_MIN_INTERVAL_MS: 2500
          BULK_JITTER_MS: 250
          BULK_SESSION_MAX_PARALLEL: 2
    
          # Bulk Logging Configuration
          BULK_LOG_BATCH_SIZE: 50
          BULK_CALLBACKS_FLUSH_MS: 1500
          BULK_PROGRESS_EVERY_MESSAGES: 1
          BULK_PROGRESS_FLUSH_MS: 600
          BULK_CANCEL_TTL_SEC: 120
    
          # Body Limit Configuration (alineado con hub / Traefik large-upload)
          BODY_LIMIT_MB: 1024
    
          # Node Environment
          NODE_ENV: development
    
          # Máximo por sesión
          SINGLE_MESSAGE_MAX_QUEUE_PER_SESSION: 50
          # Máximo total
          SINGLE_MESSAGE_MAX_QUEUE_TOTAL: 1000
          # Intervalo mínimo
          SINGLE_MESSAGE_MIN_INTERVAL_MS: 2000
    
          USE_WAHA_DISPATCHER: "true"
    
          USE_DISPATCHER_FOR_BULK: "false"
    
          PUSH_NON_TEXT_BODY: icon
          PUSH_TEXT_PREVIEW_MAX: "280"
    
        labels:
          - "traefik.enable=true"
          - "traefik.http.routers.bridge.rule=Host(`crm.tu-dominio.com`) && PathPrefix(`/bridge`)"
          - "traefik.http.routers.bridge.entrypoints=websecure"
          - "traefik.http.routers.bridge.tls.certresolver=letsencrypt"
          - "traefik.http.routers.bridge.service=bridge"
          - "traefik.http.routers.bridge.middlewares=bridge-stripprefix,large-upload"
          - "traefik.http.services.bridge.loadbalancer.server.port=3003"
          - "traefik.http.middlewares.bridge-stripprefix.stripprefix.prefixes=/bridge"
        networks:
          - notibuzz-network
    
      # noti-sender-media - Servicio de archivos multimedia
      noti-sender-media:
        image: hilosdf/noti-sender-media:dbad5a4
        container_name: noti-sender-media
        restart: unless-stopped
        expose:
          - "3004"
        #env_file:
        #  - noti-sender-media/.env
        environment:
          # Puerto del servidor
          PORT: 3004
    
          # Ruta base donde se almacenan los archivos multimedia
          FILES_BASE_PATH: /tmp/whatsapp-files
    
          # Sesiones autorizadas (separadas por comas)
          ALLOWED_SESSIONS: ""
    
          # CORS: Orígenes permitidos (separados por comas)
          CORS_ORIGINS: ""
    
          # Entorno: development | production
          NODE_ENV: development
    
          # Permitir listado de archivos (opcional)
          ALLOW_LISTING: "true"
    
          # Mismo tope MB que sender-hub (express + multer /process)
          BODY_LIMIT_MB: 1024
    
          # Redis (BullMQ) — obligatorio para /process y workers
          REDIS_HOST: redis
          REDIS_PORT: 6379
          REDIS_PASSWORD: ${REDIS_PASSWORD:-TU_REDIS_PASSWORD}
          REDIS_DB: 0
    
          # URL pública para que WAHA descargue archivos al enviar medios
          MEDIA_PUBLIC_BASE_URL: https://crm.tu-dominio.com/media
    
        volumes:
          # Leer archivos multimedia desde noti-sender-waha
          - waha_files:/tmp/whatsapp-files:ro
        labels:
          # Media Router - /media -> /files
          - "traefik.enable=true"
          - "traefik.http.routers.media.rule=Host(`crm.tu-dominio.com`) && PathPrefix(`/media`)"
          - "traefik.http.routers.media.entrypoints=websecure"
          - "traefik.http.routers.media.tls.certresolver=letsencrypt"
          - "traefik.http.routers.media.service=media"
          - "traefik.http.routers.media.middlewares=media-replacepath,large-upload"
          - "traefik.http.services.media.loadbalancer.server.port=3004"
          - "traefik.http.middlewares.media-replacepath.replacepathregex.regex=^/media/(.*)"
          - "traefik.http.middlewares.media-replacepath.replacepathregex.replacement=/files/$$1"
          # Files Router - /files
          - "traefik.http.routers.files.rule=Host(`crm.tu-dominio.com`) && PathPrefix(`/files`)"
          - "traefik.http.routers.files.entrypoints=websecure"
          - "traefik.http.routers.files.tls.certresolver=letsencrypt"
          - "traefik.http.routers.files.service=files"
          - "traefik.http.routers.files.middlewares=large-upload"
          - "traefik.http.services.files.loadbalancer.server.port=3004"
        networks:
          - notibuzz-network
        depends_on:
          redis:
            condition: service_healthy
          noti-sender-waha:
            condition: service_started
    
      # noti-sender-ia - Servicio de IA con RAG
      noti-sender-ia:
        image: hilosdf/noti-sender-ia:1d0de8e
        container_name: noti-sender-ia
        restart: unless-stopped
        expose:
          - "3006"
        environment:
          # ============================================
          # PUERTO
          # ============================================
          PORT: 3006
          NODE_ENV: production
    
          # ============================================
          # BASE DE DATOS (MongoDB)
          # ============================================
          MONGODB_URI: mongodb://root:TU_MONGO_PASSWORD@mongodb:27017/notibuzz?authSource=admin
          MONGODB_DB_NAME: notibuzz
    
          # ============================================
          # REDIS
          # ============================================
          REDIS_URL: redis://:TU_REDIS_PASSWORD@redis:6379/0
          REDIS_PREFIX: "ia:"
    
          # ============================================
          # DEEPSEEK API CONFIGURATION
          # ============================================
          DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY:-TU_DEEPSEEK_API_KEY}
          DEEPSEEK_API_URL: https://api.deepseek.com/v1/chat/completions
          DEEPSEEK_MODEL: deepseek-chat
    
          # ============================================
          # TOKEN LIMITS
          # ============================================
          DEFAULT_MAX_TOKENS_PER_REQUEST: 1000
    
          # ============================================
          # CONTEXT MANAGEMENT
          # ============================================
          MAX_CONTEXT_MESSAGES: 6
    
          # ============================================
          # CACHE CONFIGURATION
          # ============================================
          CACHE_TTL_SECONDS: 60
          ENABLE_CACHE: "true"
          CACHE_MAX_ENTRIES_PER_CONVERSATION: 10
    
          # ============================================
          # RAG CONFIGURATION
          # ============================================
          MAX_RETRIEVAL_CHUNKS: 3
          SIMILARITY_THRESHOLD: 0.7
          CHUNK_SIZE: 800
          CHUNK_OVERLAP: 160
    
          # ============================================
          # EMBEDDING CONFIGURATION
          # ============================================
          EMBEDDING_MODEL: paraphrase-multilingual-MiniLM-L12-v2
          EMBEDDING_DIMENSION: 384
    
          # ============================================
          # LOGGING
          # ============================================
          LOG_LEVEL: info
    
          # ============================================
          # SERVICIO DE AUTENTICACIÓN
          # ============================================
          # URL del servicio de autenticación para validar límites de tokens por plan
          # Dentro de Docker Compose, usar HTTP (no HTTPS) y el nombre del servicio
          AUTH_SERVICE_URL: http://noti-sender-auth:3005
    
          # ============================================
          # TOKENIZERS CONFIGURATION
          # ============================================
          TOKENIZERS_PARALLELISM: "false"
          # PRODUCTION: Shared VPS with multiple services (MongoDB, Redis, Waha, Hub, Auth, Bridge, Media, Web, Traefik)
          # Use 2 threads per worker (conservative to share resources with other services)
          # This prevents resource contention while maintaining good performance
          OMP_NUM_THREADS: 2
          MKL_NUM_THREADS: 2
          NUMEXPR_NUM_THREADS: 2
    
          # ============================================
          # KNOWLEDGE BASE LIMITS & VALIDATION
          # ============================================
          KB_MAX_TEXT_SIZE_BYTES: 5242880
          KB_MAX_NAME_LENGTH: 200
          KB_MAX_DESCRIPTION_LENGTH: 1000
          KB_MAX_CHUNKS_PER_KB: 10000
          KB_MAX_TAGS: 20
          KB_MAX_TAG_LENGTH: 50
    
        volumes:
          - ia_logs:/app/logs
        labels:
          - "traefik.enable=true"
          - "traefik.http.routers.ia.rule=Host(`crm.tu-dominio.com`) && PathPrefix(`/ia`)"
          - "traefik.http.routers.ia.entrypoints=websecure"
          - "traefik.http.routers.ia.tls.certresolver=letsencrypt"
          - "traefik.http.routers.ia.service=ia"
          - "traefik.http.routers.ia.middlewares=ia-stripprefix"
          - "traefik.http.services.ia.loadbalancer.server.port=3006"
          - "traefik.http.services.ia.loadbalancer.passHostHeader=true"
          - "traefik.http.middlewares.ia-stripprefix.stripprefix.prefixes=/ia"
        networks:
          - notibuzz-network
        depends_on:
          mongodb:
            condition: service_healthy
          redis:
            condition: service_healthy
    
      # noti-sender-web - Aplicación web frontend (Nuxt)
      noti-sender-web:
        image: hilosdf/noti-sender-web:bf03d0f #c91c491
        container_name: noti-sender-web
        restart: unless-stopped
        expose:
          - "8080"
        #env_file:
        #  - noti-sender-web/.env
        environment:
          # ============================================
          # CONFIGURACIÓN PARA DOCKER COMPOSE + TRAEFIK
          # ============================================
    
          # ============================================
          # API Configuration
          # ============================================
          NUXT_PUBLIC_API_URL: https://crm.tu-dominio.com/api
          API_BASE_URL: https://crm.tu-dominio.com/api
    
          # ============================================
          # Hub Configuration
          # ============================================
          NUXT_PUBLIC_HUB_URL: https://crm.tu-dominio.com/api
          HUB_BASE_URL: https://crm.tu-dominio.com/api
    
          # ============================================
          # WebSocket Configuration
          # ============================================
          NUXT_PUBLIC_WS_URL: wss://crm.tu-dominio.com/ws
    
          # ============================================
          # Media Service Configuration
          # ============================================
          NUXT_PUBLIC_MEDIA_SERVICE_URL: https://crm.tu-dominio.com/media
    
          # ============================================
          # Bridge API Configuration
          # ============================================
          NUXT_PUBLIC_BRIDGE_BASE_URL: https://crm.tu-dominio.com/bridge
    
          # ============================================
          # WAHA API Configuration
          # ============================================
          NUXT_PUBLIC_WAHA_BASE_URL: https://crm.tu-dominio.com/waha
    
          # ============================================
          # API Key
          # ============================================
          NUXT_PUBLIC_API_KEY: ""
          WAHA_API_KEY: ""
    
          # ============================================
          # Server Configuration
          # ============================================
          PORT: 8080
          NODE_ENV: production
    
          # ============================================
          # AUTH API Configuration
          # ============================================
          AUTH_SERVICE_URL: https://crm.tu-dominio.com/auth
    
          # ============================================
          # LOGIN TUTORIAL URL
          # ============================================
          NUXT_PUBLIC_LOGIN_TUTORIAL_URL: https://notibuzz.com/help/iniciar-sesion-qr
    
          # ============================================
          # APP ENV
          # ============================================
          NUXT_PUBLIC_APP_ENV: PROD
    
          NUXT_PUBLIC_SHOW_DEVELOPERS: "true"
          NUXT_PUBLIC_SHOW_BULK_WHATSAPP: "false"
    
          NUXT_PUBLIC_LINK_DEVICE_MAX_DEVICES: "5"
    
        labels:
          - "traefik.enable=true"
          # Router para redirigir / a /dashboard/ (solo cuando el path es exactamente /) - Mayor prioridad
          - "traefik.http.routers.web-root.rule=(Host(`crm.tu-dominio.com`) || Host(`www.crm.tu-dominio.com`)) && Path(`/`)"
          - "traefik.http.routers.web-root.entrypoints=websecure"
          - "traefik.http.routers.web-root.tls.certresolver=letsencrypt"
          - "traefik.http.routers.web-root.priority=10"
          - "traefik.http.routers.web-root.middlewares=redirect-to-dashboard"
          - "traefik.http.middlewares.redirect-to-dashboard.redirectregex.regex=^(https?://[^/]+)/?$$"
          - "traefik.http.middlewares.redirect-to-dashboard.redirectregex.replacement=$$1/dashboard/"
          - "traefik.http.middlewares.redirect-to-dashboard.redirectregex.permanent=true"
          # Router principal - maneja /dashboard y todas las rutas de la app (excluyendo API, WS, etc.)
          - "traefik.http.routers.web.rule=(Host(`crm.tu-dominio.com`) || Host(`www.crm.tu-dominio.com`)) && (!PathPrefix(`/api`) && !PathPrefix(`/notibuzz`) && !PathPrefix(`/ws`) && !PathPrefix(`/media`) && !PathPrefix(`/files`) && !PathPrefix(`/bridge`) && !PathPrefix(`/waha`) && !PathPrefix(`/auth`) && !PathPrefix(`/ia`) && !PathPrefix(`/containers`) && !PathPrefix(`/node-exporter`))"
          - "traefik.http.routers.web.entrypoints=websecure"
          - "traefik.http.routers.web.tls.certresolver=letsencrypt"
          - "traefik.http.routers.web.service=web"
          - "traefik.http.routers.web.priority=1"
          - "traefik.http.services.web.loadbalancer.server.port=8080"
          - "traefik.http.services.web.loadbalancer.passHostHeader=true"
          # Router para redirección HTTP -> HTTPS
          - "traefik.http.routers.web-redirect.rule=Host(`crm.tu-dominio.com`) || Host(`www.crm.tu-dominio.com`)"
          - "traefik.http.routers.web-redirect.entrypoints=web"
          - "traefik.http.routers.web-redirect.middlewares=redirect-to-https"
          - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
          - "traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true"
        networks:
          - notibuzz-network
    
      # 🌐 Traefik - Reverse Proxy y Load Balancer
      traefik:
        image: traefik:v3.6.1
        container_name: notibuzz-traefik
        restart: unless-stopped
        command:
          # API Dashboard (solo para desarrollo, deshabilitar en producción)
          - "--api.insecure=true"
          - "--api.dashboard=true"
          
          # Docker Provider
          - "--providers.docker=true"
          - "--providers.docker.exposedbydefault=false"
          - "--providers.docker.network=notibuzz-network"
          
          # Entrypoints
          - "--entrypoints.web.address=:80"
          - "--entrypoints.websecure.address=:443"
          
          # Let's Encrypt Configuration (HTTP Challenge - más confiable)
          - "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
          - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
          - "--certificatesresolvers.letsencrypt.acme.email=tu-email@ejemplo.com"
          - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
          - "--certificatesresolvers.letsencrypt.acme.caserver=https://acme-v02.api.letsencrypt.org/directory"
          
          # SSL/TLS Configuration
          - "--entrypoints.websecure.http.tls=true"
          - "--entrypoints.websecure.http.tls.certresolver=letsencrypt"
          
          # Logging
          - "--log.level=INFO"
          - "--accesslog=true"
          - "--accesslog.format=json"
          
          # Global Options
          - "--global.sendAnonymousUsage=false"
          # Plugin para reescribir Location en redirects (cAdvisor bajo /containers)
          - "--experimental.plugins.redirectlocation.modulename=github.com/SchmitzDan/traefik-plugin-redirect-location"
          - "--experimental.plugins.redirectlocation.version=v0.0.2"
        ports:
          - "80:80"
          - "443:443"
          - "8080:8080"  # Dashboard de Traefik (solo acceso local)
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock:ro
          - traefik_letsencrypt:/letsencrypt
        networks:
          - notibuzz-network
        depends_on:
          - noti-sender-web
          - noti-sender-media
          - noti-sender-hub
          - noti-sender-ia
        labels:
          # Habilitar Traefik para que pueda definir middlewares
          - "traefik.enable=true"
          # Redirigir www -> apex para evitar URLs con www
          - "traefik.http.routers.www-redirect.rule=Host(`www.crm.tu-dominio.com`) && PathPrefix(`/`)"
          - "traefik.http.routers.www-redirect.entrypoints=web,websecure"
          - "traefik.http.routers.www-redirect.priority=100"
          - "traefik.http.routers.www-redirect.tls=true"
          - "traefik.http.routers.www-redirect.tls.certresolver=letsencrypt"
          - "traefik.http.routers.www-redirect.middlewares=redirect-to-apex"
          - "traefik.http.middlewares.redirect-to-apex.redirectregex.regex=^https?://www\\.(.+)"
          - "traefik.http.middlewares.redirect-to-apex.redirectregex.replacement=https://$${1}"
          - "traefik.http.middlewares.redirect-to-apex.redirectregex.permanent=true"
          # Middleware de seguridad global
          - "traefik.http.middlewares.security-headers.headers.sslredirect=true"
          - "traefik.http.middlewares.security-headers.headers.stsSeconds=31536000"
          - "traefik.http.middlewares.security-headers.headers.stsIncludeSubdomains=true"
          - "traefik.http.middlewares.security-headers.headers.stsPreload=true"
          - "traefik.http.middlewares.security-headers.headers.forceSTSHeader=true"
          - "traefik.http.middlewares.security-headers.headers.frameDeny=true"
          - "traefik.http.middlewares.security-headers.headers.browserXssFilter=true"
          - "traefik.http.middlewares.security-headers.headers.contentTypeNosniff=true"
          - "traefik.http.middlewares.security-headers.headers.referrerPolicy=strict-origin-when-cross-origin"
    
    volumes:
      mongodb_data:
        driver: local
      mongodb_config:
        driver: local
      redis_data:
        driver: local
      waha_sessions:
        driver: local
      waha_files:
        driver: local
      hub_uploads:
        driver: local
      hub_logs:
        driver: local
      auth_logs:
        driver: local
      ia_logs:
        driver: local
      media_files:
        driver: local
      traefik_letsencrypt:
        driver: local
    
    networks:
      notibuzz-network:
        external: true
        name: notibuzz-network
    
    
  5. 5

    Levanta el stack

    Traefik enruta /api, /ws, /auth, /waha, /bridge, /media e /ia. El frontend responde en /dashboard.

    Si falla «network notibuzz-network not found», ejecuta el paso 3.

    Verifica que todos los contenedores aparezcan en docker network inspect notibuzz-network.

    docker compose pull
    docker compose up -d
    docker compose ps
    docker network inspect notibuzz-network --format '{{range .Containers}}{{.Name}} {{end}}'
  6. 6

    Verifica, crea admin y conecta WhatsApp

    Tras levantar el stack: crea el usuario administrador en noti-sender-auth, inicializa planes (opcional si comercializas) y asigna una suscripción. Luego inicia sesión en el CRM y vincula WhatsApp.

    createUser.js: argumentos → USERNAME PASSWORD EMAIL (admin es Super Admin por defecto).

    El sistema fuerza cambio de contraseña en el primer login (mustChangePassword).

    setupPlansAndSubscription.js: planes DEVELOPER, STARTER, PRO, BUSINESS — útil si vendes el CRM como servicio.

    Precios mensual/anual de la tabla son estándar preconfigurados con --init-plans-only; para cambiar precio u otros valores, edita la colección plans en MongoDB.

    Los tokens IA son cupo mensual vía DeepSeek (DEEPSEEK_API_KEY en noti-sender-ia) y se renuevan automáticamente cada mes.

    Self-hosted sin venta: crea admin + --init-plans-only + asigna BUSINESS o PRO a tu client-id.

    El usuario admin debe existir antes de asignar suscripción (--username admin).

    billing-period: monthly (mensual) o annual (anual, precio con descuento).

    URL típica: https://TU_DOMINIO/dashboard/

    Certificado HTTPS: unos minutos tras DNS correcto.

    Revisa healthchecks de MongoDB y Redis antes de escalar tráfico.

    # 1 — Crear usuario administrador (Super Admin si username=admin)
    docker exec -it noti-sender-auth node scripts/createUser.js admin TU_PASSWORD admin@tu-dominio.com
    # 2 — Inicializar planes en MongoDB (siempre recomendado)
    docker exec -it noti-sender-auth node scripts/setupPlansAndSubscription.js --init-plans-only
    # 3 — Asignar plan y suscripción (comercial o self-hosted con límites)
    docker exec -it noti-sender-auth node scripts/setupPlansAndSubscription.js \
      --plan STARTER \
      --client-id client-001 \
      --client-name "Mi Empresa" \
      --username admin \
      --billing-period monthly
    # Otros planes: --plan DEVELOPER | PRO | BUSINESS
    # Facturación anual: --billing-period annual
    # 4 — Verificar logs y conectar WhatsApp en el CRM
    docker compose logs -f noti-sender-waha
    docker compose logs -f noti-sender-hub
    # Accede al CRM y escanea QR de WhatsApp
    # Producción: https://TU_DOMINIO/dashboard/

    createUser.js — argumentos

    # node scripts/createUser.js USERNAME PASSWORD EMAIL [super-admin]
    
    USERNAME   Nombre de login (admin → Super Admin automático)
    PASSWORD   Contraseña inicial (cambio obligatorio en 1er login)
    EMAIL      Email del administrador
    super-admin  Opcional: true o --super-admin para otros usuarios
    
    Ejemplo:
      node scripts/createUser.js admin MiClaveSegura admin@tu-dominio.com

    setupPlansAndSubscription.js — parámetros y ejemplos

    # setupPlansAndSubscription.js — parámetros
    
    Opciones:
      --plan PLAN_NAME          DEVELOPER | STARTER | PRO | BUSINESS
      --client-id CLIENT_ID     ID único del cliente (ej. client-001)
      --client-name NAME        Nombre comercial del cliente
      --username USERNAME       Usuario admin ya creado (ej. admin)
      --billing-period PERIOD   monthly | annual
      --init-plans-only         Solo crea/actualiza planes en MongoDB (sin suscripción)
    
    Orden: createUser.js → --init-plans-only → asignar plan con --plan
    
    Ejemplo DEVELOPER (API / dev):
      --plan DEVELOPER --client-id dev-001 --client-name "Dev API" --username admin --billing-period monthly
    
    Ejemplo STARTER (equipo pequeño):
      --plan STARTER --client-id client-001 --client-name "Mi Empresa" --username admin --billing-period monthly
    
    Ejemplo PRO (Copilot + más capacidad):
      --plan PRO --client-id client-002 --client-name "Acme Corp" --username admin --billing-period annual
    
    Ejemplo BUSINESS (máxima capacidad):
      --plan BUSINESS --client-id client-003 --client-name "Enterprise SA" --username admin --billing-period annual
    
    Self-hosted sin venta: asigna BUSINESS o PRO a tu propio client-id.
    Comercial / SaaS: un client-id distinto por cada cliente.
    
    Nota: los precios en MongoDB son estándar preconfigurados. Para cambiar precio u otros límites, edita el documento en la colección plans. Los tokens IA limitan el consumo de DeepSeek en Chatbot/Copilot y se renuevan automáticamente cada mes.

Checklist antes de go-live

  • Red Docker notibuzz-network creada (bridge externa)
  • Contraseñas TU_* y JWT generados con openssl — nunca valores de ejemplo
  • Usuario admin creado con createUser.js (Super Admin)
  • Planes inicializados (--init-plans-only) y suscripción asignada si comercializas
  • MongoDB y Redis no expuestos a internet (solo red interna Docker)
  • noti-sender-media: REDIS_HOST=redis y MEDIA_PUBLIC_BASE_URL=https://TU_DOMINIO/media
  • Traefik: --providers.docker.network=notibuzz-network alineado con la red creada
  • Backups periódicos del volumen mongodb_data
  • Actualización de imágenes con docker compose pull && docker compose up -d
  • Monitoreo de disco (archivos multimedia en volumen compartido WAHA/media)
  • DEEPSEEK_API_KEY solo si usas IA; rotar claves periódicamente
  • Firewall: solo 22 (SSH), 80 y 443 públicos

Solución de problemas frecuentes

  • network notibuzz-network not foundCrea la red antes del compose: docker network create notibuzz-network
  • Traefik no enruta servicios / 404 en rutasVerifica --providers.docker.network=notibuzz-network coincide con docker network ls. Todos los contenedores deben estar en esa red.
  • noti-sender-media: ECONNREFUSED 127.0.0.1:6379REDIS_HOST=redis en noti-sender-media; misma REDIS_PASSWORD que el servicio redis.
  • WAHA falla al enviar imagen (file.url localhost)MEDIA_PUBLIC_BASE_URL=https://TU_DOMINIO/media en noti-sender-media.
  • Usuario admin no encontrado al asignar planEjecuta createUser.js antes de setupPlansAndSubscription.js. El --username debe coincidir.
  • Plan inválido en setupPlansAndSubscriptionUsa --plan DEVELOPER, STARTER, PRO o BUSINESS (mayúsculas). Ejecuta --init-plans-only primero.
Diego Quiroz Ramirez — creador de Notibuzz

Creador del Software

Diego Quiroz Ramirez