Guia de Replicacao

Como montar toda a infraestrutura Uuba Tech do zero, passo a passo
Guia Completo — Marco 2026

1 Visao Geral

A Uuba Tech e um sistema completo de cobranca inteligente via WhatsApp. Ele usa inteligencia artificial para conversar com clientes que tem faturas em aberto, de forma automatica e humanizada.

Ao final deste guia, voce tera uma infraestrutura identica rodando na sua propria VPS.

O que voce vai montar

7
Servicos Docker
API
REST (FastAPI)
IA
Claude (Anthropic)
Bot
WhatsApp 24/7

Diagrama de Arquitetura

Internet | +--------------+ | Nginx | (reverse proxy + SSL) +--------------+ / | \ / | \ api.uuba.tech wa.uuba.tech developers.uuba.tech | | | +----------+ +-----------+ (mesmo que api) | uuba-api | | evolution | | (FastAPI)| | -api | +----+-----+ +-----+----+ | | +----+-----+ +----+----+ |PostgreSQL | | Redis | | (dados) | | (cache) | +-----------+ +---------+ \ +------+------+ | n8n | (automacao + IA) +------+------+ | +------+------+ | PostgreSQL | | (n8n) | +-------------+ Fluxo: Cliente envia WhatsApp -> Evolution API recebe -> Webhook para n8n -> n8n consulta uuba-api (dados do cliente) -> n8n chama Claude (IA) para gerar resposta -> n8n envia resposta via Evolution API -> Cliente recebe no WhatsApp

Servicos que serao instalados

ServicoO que fazTecnologia
uuba-apiAPI principal - gerencia clientes, faturas e cobrancasPython / FastAPI
evolution-apiGateway WhatsApp - envia e recebe mensagensNode.js
n8nAutomacao - workflows, agente IA, regua de cobrancaNode.js
postgresBanco de dados interno do n8nPostgreSQL 16
postgres-dataBanco de dados de negocio (clientes, faturas)PostgreSQL 16
redisCache para sessoes WhatsApp e debounceRedis 7
pgadminInterface visual para os bancos de dadospgAdmin 4

2 O que voce vai precisar

Antes de comecar, reuna todos estes itens. Sem eles, nao e possivel completar a instalacao.

Checklist de pre-requisitos

ItemDetalhesOnde conseguir
VPS (servidor) Ubuntu 22.04 ou superior, minimo 4 vCPUs, 8GB RAM, 100GB disco Contabo, Hostinger, DigitalOcean, Hetzner
Dominio Um dominio proprio com acesso ao painel DNS (ex: suaempresa.com.br) Registro.br, GoDaddy, Wix, Cloudflare
Chip WhatsApp Um numero de celular dedicado para o bot (nao use seu numero pessoal) Operadora de celular
Conta Anthropic API key para usar o Claude (inteligencia artificial) console.anthropic.com
Conta Conta Azul Para gerar links de pagamento (Pix/boleto) - pode ser configurado depois contaazul.com
Se voce nunca contratou uma VPS, recomendamos a Contabo (custo-beneficio) ou Hetzner (performance). Escolha um plano com pelo menos 4 vCPUs e 8GB de RAM. O processo e parecido com comprar qualquer servico online - voce cria uma conta, escolhe o plano e recebe o IP e senha por email.
O chip WhatsApp precisa ser exclusivo para o bot. Se voce usar um numero que ja tem WhatsApp pessoal, todas as suas conversas serao desconectadas. Compre um chip pre-pago novo.

O que voce vai precisar saber anotar

Durante o processo, voce vai gerar varias senhas e chaves. Tenha um lugar seguro para anotá-las (gerenciador de senhas, documento offline).

O queExemplo (placeholder)
IP da VPSYOUR_IP
Senha root da VPSYOUR_VPS_PASSWORD
Senha do PostgreSQL (n8n)YOUR_POSTGRES_PASSWORD
Senha do PostgreSQL (dados)YOUR_DATA_DB_PASSWORD
Chave de encriptacao n8nYOUR_N8N_ENCRYPTION_KEY
API Key da Uuba APIYOUR_UUBA_API_KEY
API Key do EvolutionYOUR_EVOLUTION_API_KEY
Senha do RedisYOUR_REDIS_PASSWORD
API Key do Anthropic (Claude)YOUR_ANTHROPIC_API_KEY

3 Acesso a VPS

Por que: A VPS e o seu servidor na nuvem. E como um computador que fica ligado 24 horas, acessivel pela internet. Voce vai controla-lo pelo terminal (linha de comando).

Passo 1: Conectar via SSH

SSH e a forma segura de acessar o servidor remotamente. Abra o terminal do seu computador e digite:

ssh root@YOUR_IP

Substitua YOUR_IP pelo IP que voce recebeu por email ao contratar a VPS (ex: 5.189.155.226).

Na primeira vez, vai perguntar se confia no servidor. Digite yes e aperte Enter. Depois, digite a senha root.

Passo 2: Atualizar o sistema

Por que: O servidor vem com software desatualizado. Atualizar previne falhas de seguranca.

# Atualizar lista de pacotes e instalar atualizacoes apt update && apt upgrade -y
Voce deve ver varias linhas de download. No final, sem mensagens de erro em vermelho.

Passo 3: Configurar timezone

Por que: Para que as datas e horarios no sistema estejam corretos (horario de Brasilia).

timedatectl set-timezone America/Sao_Paulo

Passo 4: Instalar ferramentas basicas

apt install -y curl wget git nano ufw

Passo 5: Configurar firewall

Por que: O firewall protege seu servidor bloqueando acessos nao autorizados. Vamos abrir apenas as portas necessarias.

# Permitir SSH (para nao perder acesso!) ufw allow OpenSSH # Permitir HTTP e HTTPS (para o site funcionar) ufw allow 80/tcp ufw allow 443/tcp # Ativar o firewall ufw --force enable # Verificar status ufw status
Se voce ativar o firewall SEM permitir SSH antes, voce vai perder acesso ao servidor! Sempre execute ufw allow OpenSSH primeiro.

4 Instalar Docker e Docker Compose

Por que: Docker e uma tecnologia que permite rodar cada servico isolado em um "container" (como uma mini maquina virtual). Isso facilita a instalacao, atualizacao e manutencao. Em vez de instalar PostgreSQL, Redis, etc. manualmente, o Docker faz tudo automaticamente.

Passo 1: Instalar Docker

# Adicionar repositorio oficial do Docker curl -fsSL https://get.docker.com | sh

Passo 2: Verificar instalacao

docker --version docker compose version
Deve mostrar algo como Docker version 27.x.x e Docker Compose version v2.x.x.

Passo 3: Testar Docker

docker run hello-world
Deve mostrar "Hello from Docker!" confirmando que tudo funciona.
Se aparecer "permission denied", execute: usermod -aG docker $USER e reconecte via SSH.

5 Estrutura de Arquivos

Por que: Todos os arquivos de configuracao ficam organizados em um unico diretorio. Isso facilita backups e manutencao.

Criar o diretorio principal

mkdir -p /opt/stack cd /opt/stack

Estrutura final

Ao final do guia, seu diretorio tera esta aparencia:

/opt/stack/ ├── docker-compose.yml # Define todos os servicos ├── .env # Senhas e configuracoes secretas ├── evolution.env # Configuracao do WhatsApp (Evolution API) └── uuba-tech/ # Codigo-fonte da API (clonado do GitHub) ├── Dockerfile.prod ├── app/ ├── alembic/ └── ...

O que cada arquivo faz

ArquivoFuncao
docker-compose.ymlO "mapa" que diz ao Docker quais servicos rodar, como conecta-los e quais portas usar
.envArmazena senhas e chaves secretas - nunca vai para o GitHub
evolution.envConfiguracao especifica do Evolution API (WhatsApp) - webhooks, cache, autenticacao
uuba-tech/Codigo-fonte da API, clonado do repositorio GitHub

Clonar o repositorio da API

cd /opt/stack git clone https://github.com/luisbarcia/uuba-tech.git
Se o repositorio for privado, voce precisara configurar uma deploy key SSH ou usar um token de acesso pessoal do GitHub.

6 Criar o docker-compose.yml

Por que: Este e o arquivo mais importante. Ele define todos os 7 servicos que formam o sistema, como eles se comunicam, e quais dados sao persistentes. O Docker le este arquivo e cria tudo automaticamente.

Copie o conteudo abaixo EXATAMENTE como esta. Um espaco a mais ou a menos pode causar erros. Use o botao "Copiar" para evitar erros de digitacao.
nano /opt/stack/docker-compose.yml

Cole o conteudo abaixo:

Ver docker-compose.yml completo (clique para expandir)
version: "3.8" services: # ============================================ # PostgreSQL - Banco de dados INTERNO do n8n # Armazena: workflows, credenciais, historico # ============================================ postgres: image: postgres:16-alpine container_name: n8n-postgres restart: unless-stopped environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"] interval: 10s timeout: 5s retries: 5 networks: - internal # ============================================ # PostgreSQL - Banco de dados de NEGOCIO # Armazena: clientes, faturas, cobrancas, evolution # ============================================ postgres-data: image: pgvector/pgvector:pg16 container_name: n8n-postgres-data restart: unless-stopped environment: POSTGRES_USER: ${DATA_DB_USER} POSTGRES_PASSWORD: ${DATA_DB_PASSWORD} POSTGRES_DB: ${DATA_DB_NAME} ports: - "127.0.0.1:5433:5432" volumes: - postgres_data_store:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ${DATA_DB_USER}"] interval: 10s timeout: 5s retries: 5 networks: - internal # ============================================ # pgAdmin - Interface visual para os bancos # Acesso via SSH tunnel na porta 5050 # ============================================ pgadmin: image: dpage/pgadmin4:latest container_name: n8n-pgadmin restart: unless-stopped environment: PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL} PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD} ports: - "127.0.0.1:5050:80" volumes: - pgadmin_data:/var/lib/pgadmin networks: - internal # ============================================ # n8n - Plataforma de automacao # Recebe webhooks, processa logica, chama IA # ============================================ n8n: image: n8nio/n8n:latest container_name: n8n restart: unless-stopped environment: DB_TYPE: postgresdb DB_POSTGRESDB_HOST: postgres DB_POSTGRESDB_PORT: 5432 DB_POSTGRESDB_DATABASE: ${POSTGRES_DB} DB_POSTGRESDB_USER: ${POSTGRES_USER} DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD} N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY} N8N_HOST: ${N8N_HOST} N8N_PROTOCOL: https WEBHOOK_URL: https://${N8N_HOST}/ NODE_FUNCTION_ALLOW_EXTERNAL: ioredis N8N_PUBLIC_API_DISABLED: "false" ports: - "0.0.0.0:5678:5678" volumes: - n8n_data:/home/node/.n8n depends_on: postgres: condition: service_healthy networks: - internal # ============================================ # Uuba API - Backend principal # REST API em Python/FastAPI # ============================================ uuba-api: build: context: ./uuba-tech/uuba-tech-api dockerfile: Dockerfile.prod container_name: uuba-api restart: unless-stopped environment: DATABASE_URL: postgresql+asyncpg://${DATA_DB_USER}:${DATA_DB_PASSWORD}@postgres-data:5432/${UUBA_DB_NAME} API_KEY: ${UUBA_API_KEY} ENVIRONMENT: production DEBUG: "false" ports: - "127.0.0.1:8080:8000" depends_on: postgres-data: condition: service_healthy healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"] interval: 30s timeout: 5s retries: 3 start_period: 10s networks: - internal # ============================================ # Evolution API - Gateway WhatsApp # Envia e recebe mensagens do WhatsApp # ============================================ evolution-api: image: evoapicloud/evolution-api:v2.3.7 container_name: evolution-api restart: unless-stopped env_file: - ./evolution.env ports: - "127.0.0.1:8085:8080" volumes: - evolution_instances:/evolution/instances depends_on: postgres-data: condition: service_healthy redis: condition: service_healthy networks: - internal # ============================================ # Redis - Cache em memoria # Usado pelo Evolution API e debounce do bot # ============================================ redis: image: redis:7-alpine container_name: redis restart: unless-stopped command: redis-server --requirepass ${REDIS_PASSWORD} volumes: - redis_data:/data healthcheck: test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] interval: 10s timeout: 5s retries: 5 networks: - internal # ============================================ # Cloudflared - Tunnel (opcional) # Expor n8n sem abrir porta no firewall # ============================================ cloudflared: image: cloudflare/cloudflared:latest container_name: cloudflared restart: unless-stopped command: tunnel --no-autoupdate run environment: TUNNEL_TOKEN: ${CLOUDFLARE_TUNNEL_TOKEN} networks: - internal volumes: postgres_data: postgres_data_store: pgadmin_data: n8n_data: evolution_instances: redis_data: networks: internal: driver: bridge

Salve o arquivo: pressione Ctrl+O, depois Enter, depois Ctrl+X.

Entendendo os servicos

O que cada bloco significa

1 image: Qual software usar (baixado automaticamente da internet)
2 environment: Configuracoes do servico (senhas, URLs, etc.)
3 ports: Qual porta do servidor aponta para qual porta do container
4 volumes: Onde salvar dados permanentes (sobrevivem a reinicializacao)
5 depends_on: Qual servico precisa estar pronto antes deste iniciar
6 healthcheck: Como verificar se o servico esta funcionando
7 networks: Todos na mesma rede interna para se comunicarem
Se ao salvar voce ver "Error parsing YAML", verifique a indentacao. YAML usa espacos (nunca tabs). Cada nivel de indentacao usa 2 espacos.

7 Criar o arquivo .env

Por que: O arquivo .env armazena todas as senhas e configuracoes secretas em um unico lugar. O docker-compose.yml le os valores daqui (as partes com ${...}). Assim, voce nunca coloca senhas diretamente no docker-compose.

nano /opt/stack/.env

Cole o conteudo abaixo, substituindo os valores YOUR_* por senhas reais:

Ver .env completo (clique para expandir)
# ============================================ # PostgreSQL (banco interno do n8n) # ============================================ POSTGRES_USER=n8n POSTGRES_PASSWORD=YOUR_POSTGRES_PASSWORD POSTGRES_DB=n8n # ============================================ # PostgreSQL (banco de dados de negocio) # ============================================ DATA_DB_USER=datauser DATA_DB_PASSWORD=YOUR_DATA_DB_PASSWORD DATA_DB_NAME=datastore # ============================================ # n8n # ============================================ N8N_ENCRYPTION_KEY=YOUR_N8N_ENCRYPTION_KEY N8N_HOST=YOUR_N8N_HOST # ============================================ # pgAdmin # ============================================ PGADMIN_EMAIL=YOUR_EMAIL@example.com PGADMIN_PASSWORD=YOUR_PGADMIN_PASSWORD # ============================================ # Uuba API # ============================================ UUBA_DB_NAME=uuba UUBA_API_KEY=YOUR_UUBA_API_KEY # ============================================ # Evolution API (WhatsApp) # ============================================ EVOLUTION_API_KEY=YOUR_EVOLUTION_API_KEY # ============================================ # Redis # ============================================ REDIS_PASSWORD=YOUR_REDIS_PASSWORD # ============================================ # Cloudflare Tunnel (opcional) # ============================================ CLOUDFLARE_TUNNEL_TOKEN=YOUR_CLOUDFLARE_TOKEN

Como gerar senhas seguras

Use este comando para gerar senhas aleatorias de 32 caracteres:

openssl rand -base64 32

Execute este comando uma vez para cada senha que precisar gerar. Anote cada uma antes de colar no .env.

Explicacao de cada variavel

VariavelO que e
POSTGRES_USER/PASSWORD/DBCredenciais do banco de dados que o n8n usa internamente. Nao tem relacao com seus dados de negocio.
DATA_DB_USER/PASSWORD/NAMECredenciais do banco principal. Aqui ficam os dados dos clientes, faturas e cobrancas.
N8N_ENCRYPTION_KEYChave que o n8n usa para criptografar credenciais salvas. Se perder, perde acesso a todas as credenciais configuradas no n8n.
N8N_HOSTO dominio onde o n8n sera acessado (ex: n8n.seudominio.com).
UUBA_API_KEYChave de autenticacao para acessar a API da Uuba. Qualquer chamada precisa enviar essa chave.
EVOLUTION_API_KEYChave de autenticacao do Evolution API. Usada para gerenciar instancias WhatsApp.
REDIS_PASSWORDSenha do Redis (cache). Protege contra acessos nao autorizados.
NUNCA envie este arquivo para o GitHub ou compartilhe por email/WhatsApp. Ele contem todas as senhas do sistema. Ele deve existir APENAS na VPS.

8 Criar o evolution.env

Por que: O Evolution API (gateway WhatsApp) tem muitas configuracoes especificas. Separamos em um arquivo proprio para ficar organizado. Aqui voce define onde salvar dados, como cachear sessoes e para onde enviar notificacoes (webhooks).

nano /opt/stack/evolution.env
Ver evolution.env completo (clique para expandir)
# ============================================ # Evolution API - Configuracao # ============================================ # URL publica onde o Evolution sera acessado SERVER_URL=https://wa.YOUR_DOMAIN # ============================================ # Banco de dados (PostgreSQL) # ============================================ DATABASE_ENABLED=true DATABASE_PROVIDER=postgresql DATABASE_CONNECTION_URI=postgresql://datauser:YOUR_DATA_DB_PASSWORD@postgres-data: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 DATABASE_SAVE_DATA_LABELS=true DATABASE_SAVE_DATA_HISTORIC=true # ============================================ # Cache (Redis) # ============================================ CACHE_REDIS_ENABLED=true CACHE_REDIS_URI=redis://:YOUR_REDIS_PASSWORD@redis:6379/1 CACHE_REDIS_PREFIX_KEY=evolution CACHE_REDIS_SAVE_INSTANCES=false CACHE_LOCAL_ENABLED=false # ============================================ # Autenticacao # ============================================ AUTHENTICATION_API_KEY=YOUR_EVOLUTION_API_KEY AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=true # ============================================ # Webhook Global # Quando alguem envia mensagem no WhatsApp, # o Evolution avisa o n8n nesta URL # ============================================ WEBHOOK_GLOBAL_ENABLED=true WEBHOOK_GLOBAL_URL=http://n8n:5678/webhook/evolution-webhook WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS=false # Eventos: quais tipos de notificacao enviar WEBHOOK_EVENTS_APPLICATION_STARTUP=false WEBHOOK_EVENTS_QRCODE_UPDATED=true WEBHOOK_EVENTS_MESSAGES_SET=true WEBHOOK_EVENTS_MESSAGES_UPSERT=true WEBHOOK_EVENTS_MESSAGES_EDITED=true WEBHOOK_EVENTS_MESSAGES_UPDATE=true WEBHOOK_EVENTS_MESSAGES_DELETE=true WEBHOOK_EVENTS_SEND_MESSAGE=true WEBHOOK_EVENTS_CONTACTS_SET=true WEBHOOK_EVENTS_CONTACTS_UPSERT=true WEBHOOK_EVENTS_CONTACTS_UPDATE=true WEBHOOK_EVENTS_PRESENCE_UPDATE=true WEBHOOK_EVENTS_CHATS_SET=true WEBHOOK_EVENTS_CHATS_UPSERT=true WEBHOOK_EVENTS_CHATS_UPDATE=true WEBHOOK_EVENTS_CHATS_DELETE=true WEBHOOK_EVENTS_GROUPS_UPSERT=true WEBHOOK_EVENTS_GROUPS_UPDATE=true WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE=true WEBHOOK_EVENTS_CONNECTION_UPDATE=true WEBHOOK_EVENTS_LABELS_EDIT=true WEBHOOK_EVENTS_LABELS_ASSOCIATION=true WEBHOOK_EVENTS_CALL=true WEBHOOK_EVENTS_TYPEBOT_START=false WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS=false WEBHOOK_EVENTS_ERRORS=true WEBHOOK_EVENTS_ERRORS_WEBHOOK=true # ============================================ # Configuracoes gerais # ============================================ LOG_LEVEL=WARN DEL_INSTANCE=false CONFIG_SESSION_PHONE_CLIENT=Uuba Bot CONFIG_SESSION_PHONE_NAME=Chrome

Webhooks - O que sao e por que importam

Webhooks sao "avisos automaticos". Quando algo acontece no WhatsApp (alguem enviou mensagem, leu, etc.), o Evolution envia uma notificacao para o n8n. O n8n entao decide o que fazer.

EventoQuando disparaPara que serve
MESSAGES_UPSERTNova mensagem recebidaPrincipal - e assim que o bot sabe que alguem mandou mensagem
MESSAGES_UPDATEMensagem lida/entregueSaber se o cliente leu a mensagem
CONNECTION_UPDATEWhatsApp conectou/desconectouMonitorar saude da conexao
QRCODE_UPDATEDNovo QR code geradoNecessario para conectar o WhatsApp
SEND_MESSAGEMensagem enviada pelo botLog de mensagens enviadas

9 Configurar Nginx

Por que: Os containers Docker rodam em portas internas (8000, 8080, 8085). Ninguem consegue acessa-los diretamente pela internet. O Nginx e um "porteiro" que recebe as requisicoes pela internet (porta 80/443) e encaminha para o container correto, dependendo do dominio usado.

Passo 1: Instalar Nginx

apt install -y nginx

Passo 2: Criar vhost para API e Documentacao

Este arquivo configura dois subdominios: api.YOUR_DOMAIN (API) e developers.YOUR_DOMAIN (documentacao).

nano /etc/nginx/sites-available/uuba-tech
Ver configuracao do vhost uuba-tech
# API - api.YOUR_DOMAIN server { listen 80; server_name api.YOUR_DOMAIN; 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; } } # Documentacao - developers.YOUR_DOMAIN server { listen 80; server_name developers.YOUR_DOMAIN; 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; } }

Passo 3: Criar vhost para WhatsApp (Evolution API)

nano /etc/nginx/sites-available/wa-uuba-tech
Ver configuracao do vhost wa-uuba-tech
# WhatsApp API - wa.YOUR_DOMAIN server { listen 80; server_name wa.YOUR_DOMAIN; location / { proxy_pass http://127.0.0.1:8085; 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; # WebSocket support (necessario para Evolution API) proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } }

Passo 4: Ativar os sites e testar

# Criar links simbolicos para ativar os sites ln -s /etc/nginx/sites-available/uuba-tech /etc/nginx/sites-enabled/ ln -s /etc/nginx/sites-available/wa-uuba-tech /etc/nginx/sites-enabled/ # Testar se a configuracao esta correta nginx -t # Recarregar nginx systemctl reload nginx
nginx -t deve mostrar "syntax is ok" e "test is successful".
Se aparecer "conflicting server name", verifique se nao existe outro arquivo em /etc/nginx/sites-enabled/ com o mesmo server_name. Remova o conflitante com rm /etc/nginx/sites-enabled/arquivo-conflitante.

10 Configurar SSL (Let's Encrypt)

Por que: SSL (o cadeado verde no navegador) criptografa a comunicacao entre o navegador e o servidor. Sem SSL, senhas e dados trafegam "abertos" pela internet. O Let's Encrypt fornece certificados SSL gratuitos.

O DNS (passo 11) precisa estar configurado ANTES deste passo. O Let's Encrypt verifica se o dominio aponta para o seu servidor. Se nao apontar, o certificado nao sera gerado.

Passo 1: Instalar Certbot

apt install -y certbot python3-certbot-nginx

Passo 2: Gerar certificados

# Certificado para API e Documentacao certbot --nginx -d api.YOUR_DOMAIN -d developers.YOUR_DOMAIN # Certificado para WhatsApp API certbot --nginx -d wa.YOUR_DOMAIN

O certbot vai perguntar seu email (para avisos de renovacao) e pedir para aceitar os termos. Quando perguntar sobre redirecionar HTTP para HTTPS, escolha 2 (Redirect).

Passo 3: Verificar renovacao automatica

Os certificados vencem a cada 90 dias, mas o certbot renova automaticamente.

# Testar se a renovacao automatica funciona certbot renew --dry-run
Deve mostrar "Congratulations, all simulated renewals succeeded".
Se falhar com "Could not automatically find a matching server block", verifique se o server_name no Nginx corresponde exatamente ao dominio. Verifique tambem se o DNS ja propagou (use dig api.YOUR_DOMAIN).

11 Configurar DNS

Por que: DNS e o "catálogo telefonico" da internet. Ele traduz nomes como "api.suaempresa.com" para o IP do seu servidor. Sem isso, ninguem consegue acessar seus servicos pelo dominio.

Registros DNS necessarios

Acesse o painel DNS do seu provedor de dominio e crie estes registros:

TipoNome (Host)ValorPara que serve
AapiYOUR_IPAPI REST principal
AdevelopersYOUR_IPDocumentacao da API
AwaYOUR_IPEvolution API (WhatsApp)

Como criar um registro A (passo a passo generico)

1 Acesse o painel do seu provedor de dominio (Registro.br, GoDaddy, Wix, Cloudflare, etc.)
2 Encontre a secao "DNS" ou "Gerenciar DNS"
3 Clique em "Adicionar registro" ou "Add Record"
4 Tipo: A | Nome: api | Valor: o IP da sua VPS | TTL: 3600
5 Repita para cada subdominio (developers, wa)

Verificar propagacao

Apos criar os registros, aguarde de 5 minutos a 48 horas para a propagacao. Verifique assim:

# Verificar se o DNS esta apontando para seu IP dig +short api.YOUR_DOMAIN dig +short developers.YOUR_DOMAIN dig +short wa.YOUR_DOMAIN
Cada comando deve retornar o IP da sua VPS (ex: YOUR_IP).
Se voce usa Cloudflare como DNS, desative o proxy (nuvem laranja) para estes subdominios. O Nginx precisa receber as conexoes diretamente para o SSL funcionar.

12 Subir os Servicos

Por que: Agora que todos os arquivos de configuracao estao prontos, vamos iniciar os containers. O Docker vai baixar as imagens, criar os containers e iniciar tudo automaticamente.

Passo 1: Iniciar todos os servicos

cd /opt/stack docker compose up -d

O -d significa "detached" (em segundo plano). Na primeira vez, vai demorar alguns minutos para baixar as imagens.

Passo 2: Verificar status de cada servico

docker compose ps
Todos os servicos devem mostrar status Up ou healthy. Se algum mostrar Restarting ou Exit, ha um problema.

Passo 3: Criar o database "evolution"

Por que: O postgres-data cria automaticamente o database padrao (datastore), mas a Evolution API precisa de um database chamado evolution. Precisamos cria-lo manualmente.

# Conectar ao PostgreSQL e criar o database evolution docker exec -it n8n-postgres-data psql -U datauser -d datastore -c "CREATE DATABASE evolution;"

Passo 4: Criar o database "uuba"

docker exec -it n8n-postgres-data psql -U datauser -d datastore -c "CREATE DATABASE uuba;"

Passo 5: Reiniciar servicos que dependem dos databases

docker compose restart evolution-api uuba-api

Passo 6: Rodar migrations da API

Por que: As migrations criam as tabelas no banco de dados (clientes, faturas, cobrancas).

docker exec uuba-api alembic upgrade head

Passo 7: Verificar saude dos servicos

# API da Uuba curl -s http://localhost:8080/health | python3 -m json.tool # Evolution API curl -s http://localhost:8085/ # n8n curl -s http://localhost:5678/healthz
Se algum servico estiver com problema, veja os logs: docker logs nome-do-container --tail 50. Os erros mais comuns sao: senha errada no .env, database nao existe, ou porta ja em uso.

13 Conectar WhatsApp

Por que: Ate agora, a Evolution API esta rodando mas nao esta conectada a nenhum numero de WhatsApp. Precisamos criar uma "instancia" e escanear o QR code com o celular do bot.

Passo 1: Acessar o Evolution Manager

Abra no navegador:

https://wa.YOUR_DOMAIN/manager

Passo 2: Fazer login

Configurar acesso ao Manager

1 No campo "Server URL", digite: https://wa.YOUR_DOMAIN
2 No campo "API Key", cole a mesma chave que voce definiu em EVOLUTION_API_KEY no .env
3 Clique em "Connect" ou "Login"

Passo 3: Criar instancia

Criar a instancia "uuba-bot"

1 Clique em "Create Instance" ou "Nova Instancia"
2 Nome da instancia: uuba-bot
3 Clique em "Create"
4 Um QR code vai aparecer na tela

Passo 4: Escanear QR Code

Conectar o celular do bot

1 No celular com o chip dedicado, abra o WhatsApp
2 Va em Configuracoes > Aparelhos conectados > Conectar aparelho
3 Escaneie o QR code que apareceu no Manager
4 Aguarde a conexao ser estabelecida (pode levar alguns segundos)

Passo 5: Verificar conexao

# Via API (substitua YOUR_EVOLUTION_API_KEY) curl -s -H "apikey: YOUR_EVOLUTION_API_KEY" \ https://wa.YOUR_DOMAIN/instance/connectionState/uuba-bot
Deve retornar {"instance":{"state":"open"}}. "open" significa que o WhatsApp esta conectado.
Se o QR code expirar (tempo limite de ~45 segundos), a pagina gera um novo automaticamente. Se a conexao cair depois, verifique se o celular esta com internet e bateria. O WhatsApp desconecta se o celular ficar muito tempo sem internet.

14 Configurar n8n

Por que: O n8n e o "cerebro" do sistema. E onde ficam os workflows que recebem mensagens, processam com IA e respondem. Antes de importar os workflows, precisamos configurar as credenciais de acesso aos servicos externos.

Passo 1: Acessar o n8n

Na primeira vez, o n8n pede para criar uma conta de administrador:

http://YOUR_IP:5678

Preencha email, nome e senha. Esta e a conta de admin do n8n (diferente das senhas do .env).

Passo 2: Criar credencial Anthropic (Claude IA)

Configurar acesso ao Claude

1 No n8n, va em Settings > Credentials > Add Credential
2 Busque por "Anthropic" e selecione
3 Cole sua API Key do Anthropic (de console.anthropic.com)
4 Clique em "Save" e depois "Test" para verificar

Passo 3: Gerar API Key do n8n

Por que: A API Key do n8n permite gerenciar workflows de fora (criar, atualizar, ativar) sem precisar usar a interface web.

Gerar chave de API

1 No n8n, va em Settings > API
2 Clique em "Create API Key"
3 Copie e guarde a chave gerada em lugar seguro

Passo 4: Criar credencial Redis (para debounce)

Configurar acesso ao Redis

1 No n8n, va em Settings > Credentials > Add Credential
2 Busque por "Redis" e selecione
3 Host: redis | Port: 6379 | Password: a mesma do REDIS_PASSWORD
4 Clique em "Save" e "Test"
O n8n salva credenciais de forma criptografada usando a N8N_ENCRYPTION_KEY. Se voce perder essa chave, todas as credenciais configuradas no n8n serao perdidas e precisarao ser reconfiguradas.

15 Importar Workflows

Por que: Os workflows sao a logica do sistema - o que fazer quando uma mensagem chega, como processar com IA, como responder. Voce pode importa-los via interface web (JSON) ou via API.

Os 3 Workflows

WorkflowFuncaoStatus
Uuba - WhatsApp Enviar Sub-workflow reutilizavel. Recebe um numero e uma mensagem e envia via Evolution API. Usado pelos outros workflows. Ativo
Uuba - WhatsApp Receber Workflow principal. Recebe mensagens do WhatsApp, identifica o cliente, usa agente IA (Claude) para gerar resposta, e envia de volta. Ativo
Uuba - Regua de Cobranca Prototipo. Consulta faturas vencidas e envia cobrancas automaticas. Sera expandido futuramente. Prototipo

Importar via interface web

Passo a passo para importar

1 No n8n, clique em + Add Workflow
2 No canto superior direito, clique nos 3 pontinhos (...)
3 Selecione "Import from File"
4 Selecione o arquivo JSON do workflow
5 O workflow sera carregado - configure as credenciais (Anthropic, etc.)
6 Ative o workflow clicando no toggle no canto superior direito

Importar via API

# Substitua YOUR_N8N_API_KEY e o arquivo JSON curl -X POST http://YOUR_IP:5678/api/v1/workflows \ -H "X-N8N-API-KEY: YOUR_N8N_API_KEY" \ -H "Content-Type: application/json" \ -d @workflow-whatsapp-enviar.json

Workflow "WhatsApp Receber" - Como funciona

Este e o workflow mais importante. Veja o que cada node (etapa) faz:

Fluxo completo de uma mensagem recebida

1 Webhook: Recebe a notificacao do Evolution API quando chega uma mensagem
2 Filtro: Ignora mensagens do proprio bot, grupos, status e outros eventos irrelevantes
3 Extrair dados: Separa o numero do remetente, texto da mensagem e nome do contato
4 Redis Debounce (gravar): Salva a mensagem no Redis com TTL de 5 segundos
5 Wait: Espera 5 segundos (para acumular mensagens rapidas)
6 Redis Debounce (verificar): Verifica se esta e a ultima mensagem daquele numero nos ultimos 5 segundos
7 Buscar cliente: Consulta a API da Uuba para identificar o cliente pelo numero de telefone
8 Montar contexto: Prepara informacoes do cliente (nome, faturas, historico) para a IA
9 Agente IA: Claude analisa a mensagem e o contexto, e gera uma resposta personalizada
10 Enviar resposta: Quebra a resposta em paragrafos e envia via sub-workflow "WhatsApp Enviar"
Importe o workflow "WhatsApp Enviar" PRIMEIRO, pois o "WhatsApp Receber" depende dele. Apos importar, atualize as referencias de credenciais (Anthropic) e URLs da API nos nodes correspondentes.

16 Configurar o Agente IA

Por que: O agente IA e o "cerebro conversacional" do bot. Ele entende o que o cliente disse, consulta dados no sistema, e responde de forma humanizada. Sem ele, o bot seria apenas um menu de opcoes.

Como o agente funciona

O agente usa o modelo Claude Sonnet 4 da Anthropic. Ele recebe a mensagem do cliente junto com todo o contexto (nome, faturas, historico) e decide como responder. Ele tambem pode usar "ferramentas" para buscar informacoes e registrar acoes.

Configuracao do LLM

ParametroValorPor que
ModeloClaude Sonnet 4Melhor custo-beneficio para conversas em portugues
Temperatura0.3Baixa = respostas mais consistentes e previsiveis
Max tokens1024Limita o tamanho da resposta (evita respostas gigantes)
Retry3xSe a API da Anthropic falhar, tenta mais 2 vezes

Ferramentas do agente (Tools)

O agente pode "chamar" estas ferramentas durante a conversa para buscar dados e registrar acoes:

FerramentaO que fazEndpoint da API
buscar_faturas Consulta faturas pendentes de um cliente GET /api/v1/faturas?cliente_id=X&status=pendente
buscar_metricas Busca metricas do cliente (total devido, dias de atraso, etc.) GET /api/v1/clientes/{id}/metricas
registrar_promessa Registra quando o cliente promete pagar em uma data PATCH /api/v1/faturas/{id}
registrar_cobranca Registra que uma cobranca foi feita (para historico) POST /api/v1/cobrancas

Memoria por cliente

O agente lembra das ultimas 10 mensagens trocadas com cada cliente. Isso permite continuidade na conversa ("voce disse que ia pagar sexta...").

ConfiguracaoValorExplicacao
TipoBuffer WindowGuarda as N mensagens mais recentes
Janela10 mensagens5 pares de pergunta/resposta
ChaveNumero de telefoneCada cliente tem seu proprio historico

Debounce com Redis

O que e: Quando alguem manda varias mensagens rapidas (tipo "Oi" / "tudo bem?" / "preciso de ajuda"), o debounce espera 5 segundos e processa tudo junto como uma unica mensagem. Isso evita que o bot responda 3 vezes seguidas.

Como o debounce funciona

1 Mensagem chega, salva no Redis com chave debounce:{telefone} e TTL de 5 segundos
2 Workflow espera 5 segundos (node Wait)
3 Le o Redis novamente: se a mensagem armazenada e a mesma que disparou este fluxo, processa
4 Se outra mensagem chegou nesse tempo, esta execucao e descartada (a mais recente sera processada)

Envio de respostas

O bot nao envia a resposta inteira de uma vez. Ele quebra em paragrafos e envia com 1.5 segundos de intervalo, simulando uma pessoa digitando. Alem disso, converte formatacao Markdown (usada pelo Claude) para formatacao WhatsApp:

Markdown (Claude gera)WhatsApp (bot envia)
**texto***texto* (negrito)
*texto*_texto_ (italico)
- item- item (mantido)

17 Testar Tudo

Por que: Antes de colocar em producao, precisamos verificar que cada parte do sistema funciona. Siga os testes na ordem.

Teste 1: API Health

curl -s https://api.YOUR_DOMAIN/health
Deve retornar {"status": "healthy"}

Teste 2: API com autenticacao

curl -s -H "X-API-Key: YOUR_UUBA_API_KEY" \ https://api.YOUR_DOMAIN/api/v1/clientes
Deve retornar uma lista (vazia se nao tiver clientes cadastrados): []

Teste 3: Evolution API

curl -s -H "apikey: YOUR_EVOLUTION_API_KEY" \ https://wa.YOUR_DOMAIN/instance/fetchInstances
Deve listar a instancia "uuba-bot" com estado "open"

Teste 4: Enviar mensagem de teste

# Enviar uma mensagem de teste (substitua o numero) curl -X POST https://wa.YOUR_DOMAIN/message/sendText/uuba-bot \ -H "apikey: YOUR_EVOLUTION_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "number": "5511999999999", "text": "Ola! Esta e uma mensagem de teste do bot Uuba." }'

Substitua 5511999999999 pelo seu numero pessoal (com codigo do pais, DDD e numero, sem espacos ou tracos).

Voce deve receber a mensagem no seu WhatsApp pessoal.

Teste 5: Receber e auto-responder

Testar o fluxo completo

1 Do seu WhatsApp pessoal, envie "Oi" para o numero do bot
2 Aguarde ~10 segundos (5s debounce + processamento)
3 O bot deve responder (se o workflow estiver ativo no n8n)
4 Se nao responder, verifique os logs no n8n: Executions no menu lateral

Teste 6: Debounce (mensagens rapidas)

Testar acumulacao de mensagens

1 Envie rapidamente 3 mensagens seguidas: "Oi" / "tudo bem?" / "preciso de ajuda"
2 O bot deve responder apenas UMA vez, considerando todas as mensagens
3 Se responder 3 vezes, o debounce nao esta funcionando - verifique a configuracao do Redis no n8n

Teste 7: Documentacao da API

# Abra no navegador https://developers.YOUR_DOMAIN
Deve abrir a pagina de documentacao interativa (Scalar) da API.
Se algum teste falhar, verifique: 1) O servico esta rodando? (docker compose ps) 2) Veja os logs (docker logs nome-container --tail 50) 3) O DNS esta correto? (dig subdominio.YOUR_DOMAIN) 4) O SSL esta valido? (acesse pelo navegador e veja o cadeado)

18 Manutencao

Apos a instalacao, voce vai precisar fazer manutencao periodica. Aqui estao os comandos mais importantes.

Ver logs de um servico

# Ultimas 50 linhas do log docker logs uuba-api --tail 50 # Acompanhar logs em tempo real (Ctrl+C para sair) docker logs -f evolution-api # Logs do n8n docker logs n8n --tail 50

Reiniciar um servico

# Reiniciar apenas a API cd /opt/stack && docker compose restart uuba-api # Reiniciar tudo cd /opt/stack && docker compose restart

Atualizar imagens

# Baixar versoes mais recentes cd /opt/stack && docker compose pull # Recriar containers com as novas imagens docker compose up -d

Atualizar a API (deploy)

cd /opt/stack && git -C uuba-tech pull && \ docker compose build --no-cache uuba-api && \ docker compose up -d uuba-api

Backup dos volumes

# Criar pasta de backup mkdir -p /opt/backups # Backup do banco de dados de negocio docker exec n8n-postgres-data pg_dumpall -U datauser > /opt/backups/postgres-data-$(date +%Y%m%d).sql # Backup do banco do n8n docker exec n8n-postgres pg_dumpall -U n8n > /opt/backups/postgres-n8n-$(date +%Y%m%d).sql

Adicionar novo numero WhatsApp

Passo a passo

1 Acesse https://wa.YOUR_DOMAIN/manager
2 Clique em "Create Instance"
3 De um nome (ex: uuba-bot-2)
4 Escaneie o QR code com o novo celular
5 Atualize o workflow no n8n para suportar a nova instancia

Renovacao SSL

# Verificar status dos certificados certbot certificates # Renovar manualmente (se necessario) certbot renew # A renovacao automatica esta em: systemctl status certbot.timer

Problemas comuns e solucoes

ProblemaCausa provavelSolucao
Container reiniciando em loop Senha errada no .env ou database nao existe Verifique logs: docker logs nome-container
WhatsApp desconectou Celular ficou sem internet ou bateria Reescaneie o QR code no Evolution Manager
Bot nao responde Workflow desativado no n8n ou credencial expirada Verifique Executions no n8n e re-ative o workflow
API retorna 502 Container da API parou docker compose restart uuba-api
SSL expirado Renovacao automatica falhou certbot renew --force-renewal
Disco cheio Logs do Docker acumularam docker system prune -a --volumes (cuidado: remove dados nao usados)
n8n lento Muitas execucoes acumuladas No n8n: Settings > Pruning > ativar limpeza automatica

19 Checklist Final

Marque cada item conforme for verificando. Todos devem estar verdes para o sistema estar 100% funcional.

Infraestrutura

  • VPS acessivel via SSH
  • Docker e Docker Compose instalados
  • Firewall (ufw) configurado (SSH, HTTP, HTTPS)
  • Diretorio /opt/stack/ criado com os arquivos
  • Repositorio da API clonado

Servicos Docker

  • PostgreSQL (n8n) rodando e healthy
  • PostgreSQL (dados) rodando e healthy
  • Database "evolution" criado
  • Database "uuba" criado
  • Redis rodando e healthy
  • n8n rodando e acessivel
  • uuba-api rodando e healthy
  • Evolution API rodando
  • pgAdmin acessivel (via SSH tunnel)
  • Migrations da API executadas

DNS e SSL

  • api.YOUR_DOMAIN aponta para o IP da VPS
  • developers.YOUR_DOMAIN aponta para o IP da VPS
  • wa.YOUR_DOMAIN aponta para o IP da VPS
  • SSL ativo em api.YOUR_DOMAIN (cadeado verde)
  • SSL ativo em developers.YOUR_DOMAIN
  • SSL ativo em wa.YOUR_DOMAIN
  • Renovacao automatica SSL funcionando

WhatsApp

  • Instancia "uuba-bot" criada no Evolution
  • QR code escaneado e WhatsApp conectado
  • Envio de mensagem de teste funcionou
  • Recebimento de mensagem testado

n8n e Workflows

  • Conta admin do n8n criada
  • Credencial Anthropic (Claude) configurada e testada
  • Credencial Redis configurada e testada
  • API Key do n8n gerada
  • Workflow "WhatsApp Enviar" importado e ativo
  • Workflow "WhatsApp Receber" importado e ativo
  • Workflow "Regua de Cobranca" importado
  • Bot respondendo mensagens automaticamente
  • Debounce funcionando (mensagens rapidas)

Documentacao e Acesso

  • API Docs (Scalar) acessivel em developers.YOUR_DOMAIN
  • Health check retornando "healthy"
  • Todas as senhas anotadas em lugar seguro
  • Backup inicial dos databases realizado
0 de 35 itens concluidos