Skip to content

Conversation

@GABRIEL-PI
Copy link

@GABRIEL-PI GABRIEL-PI commented Dec 22, 2025

🚀 Evolution API - Multi-Device Fix

📋 Resumo da Alteração

Problema: A Evolution API estava caindo/desconectando quando o WhatsApp Android estava ativo, porque se identificava como "WebClient" (WhatsApp Web), ocupando o slot de sessão web.

Solução: Remover a identificação de browser para usar o modo Multi-Device nativo do Baileys 7.x, que não conflita com outras sessões.


🔧 Alteração no Código

Arquivo: src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts

ANTES (WebClient - CAI):

const session = this.configService.get<ConfigSessionPhone>('CONFIG_SESSION_PHONE');

let browserOptions = {};

if (number || this.phoneNumber) {
  this.phoneNumber = number;
  this.logger.info(`Phone number: ${number}`);
} else {
  const browser: WABrowserDescription = [session.CLIENT, session.NAME, release()];
  browserOptions = { browser };
  this.logger.info(`Browser: ${browser}`);
}

// ... no socketConfig:
...browserOptions,

DEPOIS (Multi-Device nativo - NÃO CAI):

if (number || this.phoneNumber) {
  this.phoneNumber = number;
  this.logger.info(`Phone number: ${number}`);
}

// Multi-Device mode: não definimos browser para evitar ser tratado como WebClient
// Isso faz o Baileys usar o modo MD nativo, que não conflita com outras sessões
this.logger.info('Using Multi-Device native mode (no browser identification)');

// ... no socketConfig:
// Removido browserOptions para usar Multi-Device nativo (não WebClient)

Imports removidos:

  • ConfigSessionPhone do @config/env.config
  • WABrowserDescription do baileys
  • release do os

📦 Repositório Fork

URL: https://github.com/joinads/evolution-api

Commit: 5dbf3e93 - "fix: usar Multi-Device nativo para evitar desconexões"


🐳 Deploy na VPS com Docker Compose

Pré-requisitos

  • Docker e Docker Compose instalados
  • Acesso SSH à VPS
  • Volumes existentes com dados (PostgreSQL, Redis, Instances)

Volumes Utilizados (externos)

evolution-clean_evolution_instances  # Dados das instâncias WhatsApp
evolution-clean_evolution_redis      # Cache Redis
evolution-clean_postgres_data        # Banco de dados PostgreSQL

📝 Comandos de Deploy

1. Clone o repositório

cd ~
git clone https://github.com/joinads/evolution-api.git evolution-api-custom
cd evolution-api-custom

2. Copie o .env existente

cp ~/evolution-clean/.env .

3. Crie o docker-compose.prod.yaml

cat > docker-compose.prod.yaml << 'EOF'
services:
  api:
    container_name: evolution_api
    build:
      context: .
      dockerfile: Dockerfile
    image: evolution-api:v2.3.4-multidevice
    restart: always
    depends_on:
      - redis
      - postgres
    ports:
      - 8080:8080
    volumes:
      - evolution-clean_evolution_instances:/evolution/instances
    networks:
      - evolution-net
    env_file:
      - .env
    expose:
      - 8080

  redis:
    image: redis:latest
    networks:
      - evolution-net
    container_name: redis
    command: >
      redis-server --port 6379 --appendonly yes
    volumes:
      - evolution-clean_evolution_redis:/data
    ports:
      - 6379:6379

  postgres:
    container_name: postgres
    image: postgres:15
    networks:
      - evolution-net
    command: ["postgres", "-c", "max_connections=1000", "-c", "listen_addresses=*"]
    restart: always
    ports:
      - 5432:5432
    environment:
      - POSTGRES_USER=caio
      - POSTGRES_PASSWORD=caio123
      - POSTGRES_DB=evolution
      - POSTGRES_HOST_AUTH_METHOD=trust
    volumes:
      - evolution-clean_postgres_data:/var/lib/postgresql/data
    expose:
      - 5432

volumes:
  evolution-clean_evolution_instances:
    external: true
  evolution-clean_evolution_redis:
    external: true
  evolution-clean_postgres_data:
    external: true

networks:
  evolution-net:
    name: evolution-net
    driver: bridge
EOF

4. Pare a Evolution antiga (se estiver rodando)

cd ~/evolution-clean
docker-compose down

5. Build da nova imagem

cd ~/evolution-api-custom
docker-compose -f docker-compose.prod.yaml build --no-cache

6. Suba os containers

docker-compose -f docker-compose.prod.yaml up -d

7. Verifique os logs

docker-compose -f docker-compose.prod.yaml logs -f api

🔄 Comandos Úteis

Ver status dos containers

docker-compose -f docker-compose.prod.yaml ps

Reiniciar a API

docker-compose -f docker-compose.prod.yaml restart api

Ver logs em tempo real

docker-compose -f docker-compose.prod.yaml logs -f api

Parar todos os containers

docker-compose -f docker-compose.prod.yaml down

Rebuild após alterações no código

git pull origin main
docker-compose -f docker-compose.prod.yaml build --no-cache
docker-compose -f docker-compose.prod.yaml up -d

🔍 Verificar se o Fix está Funcionando

Nos logs da API, você deve ver:

Using Multi-Device native mode (no browser identification)

NÃO deve mais aparecer:

Browser: ['Evolution API', 'Chrome', ...]

⚠️ Notas Importantes

  1. Instâncias existentes: Continuam funcionando normalmente. As credenciais salvas não dependem do parâmetro browser.

  2. Novas conexões: Usarão o modo Multi-Device nativo automaticamente.

  3. Se uma sessão expirar: Ao reconectar via QR Code, já usará o novo modo.

  4. Volumes externos: O docker-compose usa external: true para apontar para os volumes existentes, preservando todos os dados.


📊 Comparação: Antes vs Depois

Aspecto Antes (v2.3.4 oficial) Depois (com fix)
Identificação ['Evolution API', 'Chrome', OS] Nenhuma (MD nativo)
Tipo de sessão WebClient Multi-Device
Aparece como "WhatsApp Web" Dispositivo vinculado
Conflita com Android ✅ SIM ❌ NÃO
Cai quando Android ativo ✅ SIM ❌ NÃO

🆘 Rollback (Voltar para versão oficial)

Se precisar voltar para a versão oficial:

cd ~/evolution-api-custom
docker-compose -f docker-compose.prod.yaml down

cd ~/evolution-clean
docker-compose up -d

🔗 Links

Summary by Sourcery

Enable WhatsApp multi-device native mode in the Baileys integration and add deployment tooling and docs for running the customized Evolution API setup.

New Features:

  • Add Docker Compose configuration for local development with Postgres and Redis.
  • Add Docker Compose configuration and a helper shell script for deploying the API with the multi-device fix on a VPS.

Bug Fixes:

  • Stop identifying the WhatsApp client as a web browser so connections use Baileys multi-device mode and no longer conflict with active Android sessions.

Enhancements:

  • Log explicit usage of Baileys multi-device native mode in the WhatsApp integration service.

Documentation:

  • Add a detailed deployment guide describing how to build and run the Evolution API with the multi-device fix.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Dec 22, 2025

Reviewer's Guide

This PR changes the WhatsApp Baileys client initialization to rely on Baileys’ native multi‑device mode instead of identifying as a WebClient, and adds deployment/configuration artifacts (compose files, deployment script, and documentation) tailored for running this multi‑device build locally and on a VPS.

Sequence diagram for Baileys multi_device client initialization

sequenceDiagram
  participant BaileysStartupService
  participant ConfigService
  participant BaileysSocketFactory
  participant WhatsAppServer

  BaileysStartupService->>BaileysStartupService: defineAuthState
  BaileysStartupService->>BaileysStartupService: set phoneNumber if provided
  BaileysStartupService->>BaileysStartupService: log Using Multi_Device native mode

  BaileysStartupService->>BaileysSocketFactory: fetchLatestWaWebVersion
  BaileysSocketFactory-->>BaileysStartupService: version

  BaileysStartupService->>BaileysSocketFactory: makeWASocket(authState, socketConfig without browser)
  BaileysSocketFactory-->>BaileysStartupService: WASocket (multi_device)

  BaileysSocketFactory->>WhatsAppServer: open MD session as linked_device
  WhatsAppServer-->>BaileysSocketFactory: connection established (no WebClient slot used)

  rect rgb(230,230,230)
    BaileysStartupService-x ConfigService: ConfigSessionPhone and browserOptions no longer used
  end
Loading

Flow diagram for deploy_vps.sh multi_device deployment script

flowchart TD
  start([Start deploy_vps.sh]) --> check_file{docker_compose_prod_yaml exists?}

  check_file -- No --> error_missing_file["Print error and exit"] --> end_node
  check_file -- Yes --> backup_check{docker_compose_yaml exists?}

  backup_check -- Yes --> backup_file["Backup docker_compose_yaml to timestamped file"] --> stop_containers
  backup_check -- No --> stop_containers["Stop existing containers with docker compose down"]

  stop_containers --> build_image["Build API image with Multi_Device fix (no cache)"]
  build_image --> up_containers["Start containers with docker compose up -d"]
  up_containers --> wait_api["Sleep 10 seconds for API to start"]
  wait_api --> show_status["Show docker compose ps and last API logs"]
  show_status --> end_node([Deploy finished])
Loading

File-Level Changes

Change Details Files
Use Baileys native multi-device mode by removing explicit WebClient browser identification from the WhatsApp client startup logic.
  • Remove retrieval of CONFIG_SESSION_PHONE and construction of a WABrowserDescription array used as the browser parameter.
  • Stop passing browserOptions into the Baileys socket configuration so Baileys defaults to MD mode.
  • Log a clear informational message indicating that multi-device native mode is in use without browser identification.
  • Clean up now-unused imports related to browser identification and OS info.
src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
Document the multi-device fix and provide opinionated deployment instructions for Docker-based environments.
  • Add a markdown guide describing the multi-device issue, the fix, and detailed Docker/VPS deployment and rollback steps.
  • Highlight expected log messages to verify that the multi-device mode is active and that WebClient identification is no longer used.
DEPLOY-MULTIDEVICE-FIX.md
Introduce Docker Compose configurations and a helper script to simplify local development and VPS deployment of the multi-device build.
  • Add a local docker-compose file wiring API, Postgres, and Redis with sensible default environment variables for development.
  • Add a production docker-compose file that builds the customized image and defines API, Redis, and Postgres services for server deployment.
  • Add a deploy shell script that orchestrates building and bringing up the production stack, with basic safety checks, logging, and status output.
docker-compose.local.yaml
docker-compose.prod.yaml
deploy-vps.sh

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 4 issues, and left some high level feedback:

  • Consider moving the new deployment artifacts (docker-compose.prod.yaml, docker-compose.local.yaml, deploy-vps.sh, DEPLOY-MULTIDEVICE-FIX.md) into an examples/ or deploy/ subdirectory or a separate ops repo so that environment-specific setup does not live at the project root and is clearly separated from application code.
  • Avoid committing real or example-specific credentials in the compose files (e.g. POSTGRES_USER=caio, POSTGRES_PASSWORD=caio123, fixed AUTHENTICATION_API_KEY); instead, read these from an .env file or document them as variables so they are not hard-coded in version control.
  • The new log message Using Multi-Device native mode (no browser identification) is in English while some comments and other messages appear to be in Portuguese; it may be worth aligning the language with the existing logging/locale convention for consistency.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider moving the new deployment artifacts (`docker-compose.prod.yaml`, `docker-compose.local.yaml`, `deploy-vps.sh`, `DEPLOY-MULTIDEVICE-FIX.md`) into an `examples/` or `deploy/` subdirectory or a separate ops repo so that environment-specific setup does not live at the project root and is clearly separated from application code.
- Avoid committing real or example-specific credentials in the compose files (e.g. `POSTGRES_USER=caio`, `POSTGRES_PASSWORD=caio123`, fixed `AUTHENTICATION_API_KEY`); instead, read these from an `.env` file or document them as variables so they are not hard-coded in version control.
- The new log message `Using Multi-Device native mode (no browser identification)` is in English while some comments and other messages appear to be in Portuguese; it may be worth aligning the language with the existing logging/locale convention for consistency.

## Individual Comments

### Comment 1
<location> `src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts:558` </location>
<code_context>
+
+// Multi-Device mode: não definimos browser para evitar ser tratado como WebClient
+// Isso faz o Baileys usar o modo MD nativo, que não conflita com outras sessões
+this.logger.info('Using Multi-Device native mode (no browser identification)');
+
+// ... no socketConfig:
</code_context>

<issue_to_address>
**issue (bug_risk):** Avoid resetting `this.phoneNumber` to `undefined` when `number` is not provided.

With `if (number || this.phoneNumber)`, when `this.phoneNumber` is already set and `number` is omitted, the branch still runs and assigns `undefined` to `this.phoneNumber`, also logging `Phone number: undefined`. Consider only assigning when `number` is truthy, or split the logic so that you use `number` when provided and otherwise keep the existing `this.phoneNumber` unchanged.
</issue_to_address>

### Comment 2
<location> `deploy-vps.sh:35-44` </location>
<code_context>
+
+# Build da nova imagem
+echo -e "${YELLOW}🔨 Buildando imagem com Multi-Device fix...${NC}"
+docker compose -f docker-compose.prod.yaml build --no-cache api
+
+# Subir containers
+echo -e "${YELLOW}🚀 Iniciando containers...${NC}"
+docker compose -f docker-compose.prod.yaml up -d
+
+# Aguardar API iniciar
+echo -e "${YELLOW}⏳ Aguardando API iniciar...${NC}"
+sleep 10
+
+# Verificar status
+echo -e "${GREEN}✅ Deploy concluído!${NC}"
+echo ""
+echo "📊 Status dos containers:"
+docker compose -f docker-compose.prod.yaml ps
+
+echo ""
+echo "📋 Últimos logs da API:"
+docker compose -f docker-compose.prod.yaml logs api --tail 20
+
+echo ""
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Use a consistent `docker compose` vs `docker-compose` strategy throughout the script.

The `down` step already falls back to `docker-compose` if `docker compose` is unavailable, but `build`, `up`, `ps`, and `logs` use only `docker compose`. On hosts with only legacy `docker-compose` installed, the script will fail partway through. Consider detecting the available CLI once (e.g., a helper variable/function) and reusing it for all commands.

Suggested implementation:

```
# Detectar comando Docker Compose disponível (v2 `docker compose` ou v1 `docker-compose`)
if command -v docker &>/dev/null && docker compose version &>/dev/null; then
  DOCKER_COMPOSE="docker compose"
elif command -v docker-compose &>/dev/null; then
  DOCKER_COMPOSE="docker-compose"
else
  echo -e "${RED:-}❌ Docker Compose não encontrado (nem v2 'docker compose' nem v1 'docker-compose').${NC:-}"
  exit 1
fi

# Parar containers existentes (mantém volumes)
echo -e "${YELLOW}⏹️  Parando containers existentes...${NC}"
$DOCKER_COMPOSE -f docker-compose.prod.yaml down 2>/dev/null || true

# Build da nova imagem
echo -e "${YELLOW}🔨 Buildando imagem com Multi-Device fix...${NC}"
$DOCKER_COMPOSE -f docker-compose.prod.yaml build --no-cache api

# Subir containers
echo -e "${YELLOW}🚀 Iniciando containers...${NC}"
$DOCKER_COMPOSE -f docker-compose.prod.yaml up -d

```

```
echo ""
echo "📊 Status dos containers:"
$DOCKER_COMPOSE -f docker-compose.prod.yaml ps

echo ""
echo "📋 Últimos logs da API:"
$DOCKER_COMPOSE -f docker-compose.prod.yaml logs api --tail 20

```

If there are other `docker compose` or `docker-compose` usages earlier or later in `deploy-vps.sh` (outside the snippet shown), they should also be updated to use `$DOCKER_COMPOSE` to keep the behavior consistent across the entire script.
</issue_to_address>

### Comment 3
<location> `docker-compose.prod.yaml:49` </location>
<code_context>
+      - POSTGRES_USER=caio
+      - POSTGRES_PASSWORD=caio123
+      - POSTGRES_DB=evolution
+      - POSTGRES_HOST_AUTH_METHOD=trust
+    volumes:
+      - evolution-clean_postgres_data:/var/lib/postgresql/data
</code_context>

<issue_to_address>
**🚨 issue (security):** Using `POSTGRES_HOST_AUTH_METHOD=trust` with an exposed Postgres port is risky for a VPS deployment.

With `trust` auth enabled, any matching client can connect without a password, which combined with exposing port 5432 is a serious security risk in a VPS. Prefer using the configured `POSTGRES_USER`/`POSTGRES_PASSWORD`, avoid exposing Postgres directly (or tightly restrict it via firewall), and remove `POSTGRES_HOST_AUTH_METHOD=trust` unless you have a very tightly controlled, documented use case.
</issue_to_address>

### Comment 4
<location> `docker-compose.prod.yaml:45-49` </location>
<code_context>
+    restart: always
+    ports:
+      - 5432:5432
+    environment:
+      - POSTGRES_USER=caio
+      - POSTGRES_PASSWORD=caio123
+      - POSTGRES_DB=evolution
+      - POSTGRES_HOST_AUTH_METHOD=trust
+    volumes:
+      - evolution-clean_postgres_data:/var/lib/postgresql/data
</code_context>

<issue_to_address>
**🚨 suggestion (security):** Evitar credenciais em claro e `POSTGRES_HOST_AUTH_METHOD=trust` em exemplo de configuração de produção.

Como o arquivo se chama `docker-compose.prod.yaml`, é provável que seja usado como referência de produção. Sugiro trocar `POSTGRES_USER=caio` / `POSTGRES_PASSWORD=caio123` por placeholders (por ex.: `POSTGRES_USER=<usuario>` e `POSTGRES_PASSWORD=<senha_segura>`) e remover `POSTGRES_HOST_AUTH_METHOD=trust` ou marcar explicitamente que é apenas para ambiente de desenvolvimento/teste, para evitar que essa configuração insegura seja copiada para produção.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.


// Multi-Device mode: não definimos browser para evitar ser tratado como WebClient
// Isso faz o Baileys usar o modo MD nativo, que não conflita com outras sessões
this.logger.info('Using Multi-Device native mode (no browser identification)');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Avoid resetting this.phoneNumber to undefined when number is not provided.

With if (number || this.phoneNumber), when this.phoneNumber is already set and number is omitted, the branch still runs and assigns undefined to this.phoneNumber, also logging Phone number: undefined. Consider only assigning when number is truthy, or split the logic so that you use number when provided and otherwise keep the existing this.phoneNumber unchanged.

- POSTGRES_USER=caio
- POSTGRES_PASSWORD=caio123
- POSTGRES_DB=evolution
- POSTGRES_HOST_AUTH_METHOD=trust
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 issue (security): Using POSTGRES_HOST_AUTH_METHOD=trust with an exposed Postgres port is risky for a VPS deployment.

With trust auth enabled, any matching client can connect without a password, which combined with exposing port 5432 is a serious security risk in a VPS. Prefer using the configured POSTGRES_USER/POSTGRES_PASSWORD, avoid exposing Postgres directly (or tightly restrict it via firewall), and remove POSTGRES_HOST_AUTH_METHOD=trust unless you have a very tightly controlled, documented use case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant