Como instalar a Evolution API em uma VPS

Atualizado em 21/09/2026 25 min Intermediário

A Evolution API expõe o WhatsApp como uma API REST: você envia mensagem por requisição HTTP e recebe as respostas em webhooks. É o que costuma ligar um fluxo do n8n, um bot do Typebot ou um sistema próprio à conversa do cliente.

Este guia sobe a API com PostgreSQL e Redis, atrás de HTTPS, e conecta a primeira instância pelo QR Code.

Antes de começar

  • VPS com Ubuntu 22.04 ou 24.04, Docker instalado (veja o guia de Docker).
  • Subdomínio apontado para o IP da VPS, por exemplo api.seudominio.com.br.
  • 2 GB de RAM para poucas instâncias. Cada instância conectada mantém uma sessão ativa em memória, então planeje 4 GB a partir de três ou quatro números.

Entenda o que você está subindo

A Evolution API é um projeto de código aberto que conversa com o WhatsApp Web. Ela não é um produto oficial da Meta: o uso está sujeito às regras da plataforma, e automação agressiva pode levar ao bloqueio do número.

Para comunicação transacional em volume com garantia de entrega, o caminho oficial é a API Cloud da Meta. Para atendimento, automações internas e integrações de pequeno e médio porte, a Evolution resolve bem.

Use um número dedicado, não o seu pessoal. Se houver bloqueio, você perde aquele número — e recuperar conversa antiga não é possível.

Prepare a pasta e as senhas

A chave da API é o que protege tudo: quem a tiver envia mensagens em seu nome. Gere uma longa e guarde num gerenciador.

terminal
mkdir -p /opt/evolution && cd /opt/evolution

cat > .env <<EOF
DOMINIO=api.seudominio.com.br
[email protected]

AUTHENTICATION_API_KEY=$(openssl rand -hex 32)
POSTGRES_PASSWORD=$(openssl rand -hex 24)
EOF

chmod 600 .env
cat .env

Escreva o docker-compose.yml

Quatro serviços: a API, o PostgreSQL que guarda instâncias e mensagens, o Redis para cache de sessão e o Caddy como proxy com certificado automático.

terminal
cat > /opt/evolution/docker-compose.yml <<'EOF'
services:
  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: evolution
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: evolution
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U evolution"]
      interval: 10s
      retries: 5

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    command: redis-server --appendonly yes
    volumes:
      - redis_data:/data

  evolution:
    image: atendai/evolution-api:v2.1.1
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      SERVER_URL: https://${DOMINIO}
      AUTHENTICATION_API_KEY: ${AUTHENTICATION_API_KEY}
      DATABASE_ENABLED: "true"
      DATABASE_PROVIDER: postgresql
      DATABASE_CONNECTION_URI: postgresql://evolution:${POSTGRES_PASSWORD}@postgres:5432/evolution
      DATABASE_SAVE_DATA_INSTANCE: "true"
      DATABASE_SAVE_DATA_NEW_MESSAGE: "true"
      DATABASE_SAVE_MESSAGE_UPDATE: "true"
      DATABASE_SAVE_DATA_CONTACTS: "true"
      DATABASE_SAVE_DATA_CHATS: "true"
      CACHE_REDIS_ENABLED: "true"
      CACHE_REDIS_URI: redis://redis:6379/6
      CACHE_REDIS_PREFIX_KEY: evolution
      CACHE_LOCAL_ENABLED: "false"
      LOG_LEVEL: ERROR
      TZ: America/Sao_Paulo
    volumes:
      - evolution_instances:/evolution/instances

  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    environment:
      DOMINIO: ${DOMINIO}
      EMAIL: ${EMAIL}
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config

volumes:
  postgres_data:
  redis_data:
  evolution_instances:
  caddy_data:
  caddy_config:
EOF

cat > /opt/evolution/Caddyfile <<'EOF'
{$DOMINIO} {
	tls {$EMAIL}
	reverse_proxy evolution:8080
}
EOF

A imagem está presa a uma versão (v2.1.1) de propósito. Com latest, uma atualização automática pode trocar a versão maior e quebrar integrações em produção sem aviso.

Suba e confirme que a API responde

terminal
cd /opt/evolution
docker compose up -d
docker compose ps

# a API deve responder com a versão
curl -s https://api.seudominio.com.br | head -20

A resposta é um JSON com o nome e a versão da API. Se vier erro de certificado, espere um minuto — o Caddy emite na primeira requisição.

Crie a primeira instância e leia o QR Code

Cada número de WhatsApp é uma "instância". A criação devolve o QR Code que você lê no aparelho, em Dispositivos conectados.

terminal
source /opt/evolution/.env

curl -s -X POST "https://$DOMINIO/instance/create" \
  -H "apikey: $AUTHENTICATION_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "instanceName": "principal",
    "qrcode": true,
    "integration": "WHATSAPP-BAILEYS"
  }'

A resposta traz o QR em base64. Mais prático é abrir o gerenciador no navegador: https://api.seudominio.com.br/manager, entrar com a sua chave de API e ler o código pela tela.

Envie a primeira mensagem

Com a instância conectada, o envio é uma requisição. Use o número no formato internacional, sem sinais.

terminal
curl -s -X POST "https://$DOMINIO/message/sendText/principal" \
  -H "apikey: $AUTHENTICATION_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "number": "5571999999999",
    "text": "Funcionou."
  }'

Aponte o webhook para o seu fluxo

Para receber mensagens, configure um webhook. É assim que o n8n ou o seu sistema ficam sabendo que alguém respondeu.

terminal
curl -s -X POST "https://$DOMINIO/webhook/set/principal" \
  -H "apikey: $AUTHENTICATION_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "webhook": {
      "enabled": true,
      "url": "https://n8n.seudominio.com.br/webhook/whatsapp",
      "events": ["MESSAGES_UPSERT"]
    }
  }'

Assine só os eventos que você vai tratar. MESSAGES_UPSERT cobre mensagens recebidas; assinar tudo gera um volume de chamadas que não serve para nada e ainda pesa no seu fluxo.

Se algo não funcionar

O QR Code expira antes de eu conseguir ler

O código tem validade curta. Peça um novo pelo endpoint de conexão e leia em seguida:

terminal
curl -s "https://$DOMINIO/instance/connect/principal" -H "apikey: $AUTHENTICATION_API_KEY"

A instância desconecta sozinha depois de um tempo

Normalmente é o aparelho: o WhatsApp encerra a sessão se o celular ficar muito tempo sem internet. Confirme também que o Redis está de pé — sem cache, a sessão se perde com mais facilidade.

terminal
docker compose ps
docker compose logs --tail 50 evolution

Erro 401 em todas as chamadas

O cabeçalho é apikey, em minúsculas, e o valor precisa ser idêntico ao do .env. Confira com grep AUTHENTICATION /opt/evolution/.env.

VPS no Brasil para sua automação de WhatsApp

Rota nacional direta, importante quando cada segundo de latência aparece na conversa do cliente.

Ver planos de VPS

Perguntas frequentes

A Evolution API é oficial do WhatsApp?

Não. É um projeto de código aberto que usa a interface do WhatsApp Web. Funciona bem, mas o uso está sujeito às regras da plataforma e existe risco de bloqueio do número em caso de envio em massa ou comportamento tido como abusivo. Para campanhas de grande volume, o caminho oficial é a API Cloud da Meta.

Quantos números posso conectar na mesma instalação?

Não há limite no software, e sim de memória: cada instância conectada mantém a sessão ativa. Com 2 GB você roda uma ou duas com tranquilidade; a partir daí, suba para 4 GB.

Dá para integrar com o n8n?

Sim, e é o uso mais comum. O n8n recebe o webhook de mensagem nova, decide o que fazer e chama de volta o endpoint de envio da Evolution. As duas aplicações podem rodar na mesma VPS, cada uma no seu subdomínio.

Continue por aqui