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.
Antes de começar
- VPS mínima
- 2 vCPU · 4 GB RAM · 40 GB SSD (Runstack Pro recomendado)
- Sistema
- Ubuntu 24.04 LTS
- Também
- 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
Atualizar o sistema e instalar dependências
Instale Docker, Nginx e utilitários necessários.
bashapt 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
Criar a estrutura de diretórios
Centralize todos os arquivos da stack em /opt/stack.
bashmkdir -p /opt/stack cd /opt/stack - 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)" - 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 - 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 - 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; - 7
Subir a stack
Inicie todos os serviços e verifique que estão saudáveis.
bashcd /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 - 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 - 9
Obter certificados SSL e configurar firewall
Emita certificados para ambos os subdomínios e configure o UFW.
bashcertbot --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
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"
Não quer configurar manualmente?
Implante o n8n + Evolution API em menos de 5 minutos com a Runstack. Infraestrutura da OPEN Datacenter, com servidores em São Paulo.
Se der problema
O usuário `evolution` deve ter permissão para criar schemas. Verifique se ele é o OWNER do banco evolution_db.
# Conectar ao postgres e verificar:
docker compose exec postgres psql -U postgres -c "\du"
docker compose exec postgres psql -U postgres -c "\l"O banco `n8n` precisa existir. Verifique se o init-db.sql foi executado na criação do volume do PostgreSQL.
docker compose logs postgres | grep "init-db"
docker compose exec postgres psql -U postgres -c "\l"O WEBHOOK_URL do n8n deve ser a URL pública HTTPS. Verifique a variável N8N_HOST no .env e se o Nginx está funcionando para o subdomínio do n8n.
A senha do Redis no CACHE_REDIS_URI da Evolution deve corresponder ao `--requirepass` configurado no container Redis. Verifique as variáveis no .env.
docker compose logs redis --tail=20
docker compose logs evolution-api --tail=20A stack completa consome 2-3 GB de RAM em idle. Em VPS com menos de 4 GB, considere upgrade para o Runstack Pro. Verifique o uso com `docker stats`.
docker stats --no-streamPerguntas frequentes
Sim, mas o Chatwoot requer pelo menos 2 GB adicionais de RAM (Sidekiq + Rails + PostgreSQL). Adicione o Chatwoot ao docker-compose.yml usando o mesmo PostgreSQL e Redis, com um banco dedicado criado no init-db.sql. Recomendamos VPS com 6-8 GB para essa combinação.
Como ambos estão na mesma rede Docker (stack-net), o n8n pode acessar a Evolution API internamente via `http://evolution-api:8080`. No n8n, use o nó HTTP Request com essa URL interna e o header `apikey`.
Faça dump do PostgreSQL: `docker compose exec postgres pg_dumpall -U postgres > backup.sql`. Faça backup dos volumes: n8n_data (credenciais e workflows) e evolution_instances (sessões WhatsApp conectadas). Automatize com cron.
Sim. Configure um webhook global ou por instância na Evolution API apontando para `https://n8n.seudominio.com.br/webhook/evolution` (ou o caminho do seu trigger no n8n). O n8n processa os eventos e executa os workflows.
Para alto volume, considere mover o PostgreSQL para um servidor dedicado (Runstack Pro com PostgreSQL nativo), usar Redis gerenciado e rodar n8n em modo queue com workers separados. A estrutura do docker-compose.yml deste guia é o ponto de partida para essa evolução.