Tutoriais/n8n + Evolution API

    Stack n8n + Evolution API + PostgreSQL em uma VPS

    Este guia monta a stack completa de automação de WhatsApp mais usada no Brasil: n8n para orquestração de workflows, Evolution API para conexão com WhatsApp, PostgreSQL compartilhado e Redis — tudo em um único docker-compose.yml com Nginx roteando os subdomínios. Reserva 60 minutos e uma VPS com pelo menos 4 GB de RAM.

    ~60 minjunho/2026 · Ubuntu 24.04 LTS

    Pré-requisitos

    • VPS mínima: 2 vCPU · 4 GB RAM · 40 GB SSD (Runstack Pro recomendado)
    • Sistema: Ubuntu 24.04 LTS
    • Docker e Docker Compose instalados (veja /tutorial/como-instalar-docker)
    • Dois subdomínios DNS apontados para o IP da VPS (ex.: n8n.seudominio.com.br e evo.seudominio.com.br)
    • Portas 80 e 443 abertas no firewall
    • Nginx instalado

    Instalação passo a passo

    1. 1

      Atualizar o sistema e instalar dependências

      Instale Docker, Nginx e utilitários necessários.

      bash
      apt update && apt upgrade -y
      apt install -y curl wget nginx certbot python3-certbot-nginx
      
      # Instalar Docker
      curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh
      docker --version && docker compose version
    2. 2

      Criar a estrutura de diretórios

      Centralize todos os arquivos da stack em /opt/stack.

      bash
      mkdir -p /opt/stack
      cd /opt/stack
    3. 3

      Gerar todos os segredos da stack

      Gere senhas e chaves únicas para cada serviço antes de criar os arquivos de configuração.

      bash
      # Senha compartilhada do PostgreSQL
      echo "POSTGRES_PASSWORD: $(openssl rand -hex 24)"
      
      # Senha do Redis
      echo "REDIS_PASSWORD: $(openssl rand -hex 16)"
      
      # Chave de encriptação do n8n
      echo "N8N_ENCRYPTION_KEY: $(openssl rand -hex 24)"
      
      # API key da Evolution API
      echo "EVOLUTION_API_KEY: $(openssl rand -hex 24)"
      Dica
      Guarde todos esses valores — eles serão usados no .env a seguir.
    4. 4

      Criar o arquivo .env

      Configure todas as variáveis da stack em um único .env compartilhado.

      .env
      # /opt/stack/.env
      
      # ── PostgreSQL ──────────────────────────────────────────────
      POSTGRES_PASSWORD=SUA_SENHA_POSTGRES_AQUI
      
      # ── Redis ────────────────────────────────────────────────────
      REDIS_PASSWORD=SUA_SENHA_REDIS_AQUI
      
      # ── n8n ─────────────────────────────────────────────────────
      N8N_HOST=n8n.seudominio.com.br
      N8N_ENCRYPTION_KEY=SUA_CHAVE_N8N_AQUI
      GENERIC_TIMEZONE=America/Sao_Paulo
      
      # ── Evolution API ────────────────────────────────────────────
      EVOLUTION_SERVER_URL=https://evo.seudominio.com.br
      EVOLUTION_API_KEY=SUA_API_KEY_EVOLUTION_AQUI
      Atenção
      Substitua TODOS os valores de placeholder pelos segredos gerados no passo anterior. Nunca use valores de exemplo em produção.
    5. 5

      Criar o docker-compose.yml da stack completa

      Este arquivo unifica PostgreSQL (com bancos separados para cada serviço), Redis, n8n e Evolution API em uma única rede Docker.

      docker-compose.yml
      # /opt/stack/docker-compose.yml
      services:
      
        # ── Banco de dados compartilhado ─────────────────────────────
        postgres:
          image: postgres:16-alpine
          restart: always
          environment:
            POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
          volumes:
            - postgres_data:/var/lib/postgresql/data
            - ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro
          healthcheck:
            test: ["CMD-SHELL", "pg_isready -U postgres"]
            interval: 5s
            timeout: 5s
            retries: 10
          networks:
            - stack-net
      
        # ── Redis compartilhado ──────────────────────────────────────
        redis:
          image: redis:alpine
          restart: always
          command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes
          volumes:
            - redis_data:/data
          networks:
            - stack-net
      
        # ── n8n ──────────────────────────────────────────────────────
        n8n:
          image: docker.n8n.io/n8nio/n8n:latest
          restart: always
          ports:
            - "127.0.0.1:5678:5678"
          environment:
            - DB_TYPE=postgresdb
            - DB_POSTGRESDB_HOST=postgres
            - DB_POSTGRESDB_PORT=5432
            - DB_POSTGRESDB_DATABASE=n8n
            - DB_POSTGRESDB_USER=n8n
            - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
            - N8N_HOST=${N8N_HOST}
            - N8N_PORT=5678
            - N8N_PROTOCOL=https
            - WEBHOOK_URL=https://${N8N_HOST}/
            - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
            - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
            - TZ=${GENERIC_TIMEZONE}
          volumes:
            - n8n_data:/home/node/.n8n
          depends_on:
            postgres:
              condition: service_healthy
          networks:
            - stack-net
      
        # ── Evolution API ─────────────────────────────────────────────
        evolution-api:
          image: evoapicloud/evolution-api:latest
          restart: always
          ports:
            - "127.0.0.1:8080:8080"
          environment:
            - SERVER_URL=${EVOLUTION_SERVER_URL}
            - SERVER_PORT=8080
            - DATABASE_PROVIDER=postgresql
            - DATABASE_CONNECTION_URI=postgresql://evolution:${POSTGRES_PASSWORD}@postgres:5432/evolution_db?schema=evolution_api
            - CACHE_REDIS_ENABLED=true
            - CACHE_REDIS_URI=redis://:default@redis:6379/6
            - AUTHENTICATION_API_KEY=${EVOLUTION_API_KEY}
            - LANGUAGE=pt-BR
          volumes:
            - evolution_instances:/evolution/instances
          depends_on:
            postgres:
              condition: service_healthy
          networks:
            - stack-net
      
      volumes:
        postgres_data:
        redis_data:
        n8n_data:
        evolution_instances:
      
      networks:
        stack-net:
          driver: bridge
      Dica
      O PostgreSQL compartilhado usa um script de inicialização (init-db.sql) para criar os bancos separados do n8n e da Evolution API. Esse script é criado no próximo passo.
    6. 6

      Criar o script de inicialização do banco

      O PostgreSQL executa este script na primeira inicialização para criar os bancos e usuários de cada serviço.

      init-db.sql
      # /opt/stack/init-db.sql
      -- Criar usuário e banco para o n8n
      CREATE USER n8n WITH PASSWORD 'SUA_SENHA_POSTGRES_AQUI';
      CREATE DATABASE n8n OWNER n8n;
      
      -- Criar usuário e banco para a Evolution API
      CREATE USER evolution WITH PASSWORD 'SUA_SENHA_POSTGRES_AQUI';
      CREATE DATABASE evolution_db OWNER evolution;
      Dica
      Na Evolution API, o schema `evolution_api` é criado automaticamente pelo Prisma na primeira inicialização — não é necessário criá-lo manualmente.
      Atenção
      Substitua SUA_SENHA_POSTGRES_AQUI pelo mesmo valor de POSTGRES_PASSWORD do .env. Este arquivo é executado apenas na criação inicial do volume — alterar o arquivo depois não tem efeito sem recriar o volume.
    7. 7

      Subir a stack

      Inicie todos os serviços e verifique que estão saudáveis.

      bash
      cd /opt/stack
      docker compose up -d
      
      # Acompanhar a inicialização
      docker compose ps
      
      # Verificar logs individualmente se necessário
      docker compose logs postgres --tail=30
      docker compose logs n8n --tail=30
      docker compose logs evolution-api --tail=30
      Dica
      A Evolution API pode levar 60-90 segundos para inicializar na primeira vez enquanto o Prisma aplica o schema no banco.
    8. 8

      Configurar Nginx para os dois serviços

      Crie virtual hosts separados para o n8n e para a Evolution API.

      bash
      # Virtual host n8n
      cat > /etc/nginx/sites-available/n8n << 'NGINXEOF'
      server {
          listen 80;
          server_name n8n.seudominio.com.br;
          return 301 https://$host$request_uri;
      }
      server {
          listen 443 ssl;
          server_name n8n.seudominio.com.br;
          ssl_certificate /etc/letsencrypt/live/n8n.seudominio.com.br/fullchain.pem;
          ssl_certificate_key /etc/letsencrypt/live/n8n.seudominio.com.br/privkey.pem;
          location / {
              proxy_pass http://127.0.0.1:5678;
              proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
              proxy_set_header X-Forwarded-Proto $scheme;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection "upgrade";
              proxy_buffering off;
              proxy_read_timeout 3600s;
          }
      }
      NGINXEOF
      
      # Virtual host Evolution API
      cat > /etc/nginx/sites-available/evolution-api << 'NGINXEOF'
      server {
          listen 80;
          server_name evo.seudominio.com.br;
          return 301 https://$host$request_uri;
      }
      server {
          listen 443 ssl;
          server_name evo.seudominio.com.br;
          ssl_certificate /etc/letsencrypt/live/evo.seudominio.com.br/fullchain.pem;
          ssl_certificate_key /etc/letsencrypt/live/evo.seudominio.com.br/privkey.pem;
          location / {
              proxy_pass http://127.0.0.1:8080;
              proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
              proxy_set_header X-Forwarded-Proto $scheme;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection "upgrade";
              proxy_read_timeout 3600s;
          }
      }
      NGINXEOF
      
      ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/n8n
      ln -s /etc/nginx/sites-available/evolution-api /etc/nginx/sites-enabled/evolution-api
      nginx -t
      Atenção
      Substitua n8n.seudominio.com.br e evo.seudominio.com.br pelos seus subdomínios reais.
    9. 9

      Obter certificados SSL e configurar firewall

      Emita certificados para ambos os subdomínios e configure o UFW.

      bash
      certbot --nginx \
        -d n8n.seudominio.com.br \
        -d evo.seudominio.com.br \
        --non-interactive \
        --agree-tos \
        --email seu@email.com
      
      systemctl reload nginx
      
      # Configurar firewall
      ufw allow 22/tcp && ufw allow 80/tcp && ufw allow 443/tcp
      ufw --force enable
      ufw status verbose
    10. 10

      Verificar a stack completa

      Confirme que todos os serviços estão acessíveis.

      bash
      # Status de todos os containers
      docker compose -f /opt/stack/docker-compose.yml ps
      
      # Testar n8n
      curl -I https://n8n.seudominio.com.br
      
      # Testar Evolution API
      curl -s https://evo.seudominio.com.br/ | head -c 100
      
      # Listar instâncias da Evolution API
      curl -s https://evo.seudominio.com.br/instance/fetchInstances \
        -H "apikey: SUA_API_KEY_EVOLUTION_AQUI"
      Dica
      Acesse https://n8n.seudominio.com.br para criar a conta de owner do n8n. Para integrar a Evolution API com o n8n, use o nó HTTP Request apontando para https://evo.seudominio.com.br com o header apikey.

    $ runstack deploy --plan starter

    Não quer configurar manualmente?

    Não quer configurar manualmente? Implante o n8n + Evolution API em menos de 3 minutos com a Runstack. Infraestrutura da OPEN DATACENTER, com servidores no Brasil.

    Troubleshooting

    Perguntas frequentes

    [VERIFICAR antes de publicar]

    • 1. Confirme que o formato da DATABASE_CONNECTION_URI da Evolution API (`?schema=evolution_api`) ainda é necessário na versão atual.
    • 2. Verifique se o CACHE_REDIS_URI aceita senha via formato `redis://:senha@host:porta/db` na versão atual da Evolution API.
    • 3. Teste a criação dos bancos via init-db.sql — confirme que a senha do usuário `evolution` e `n8n` usa o mesmo POSTGRES_PASSWORD do container postgres.