Como instalar o Typebot em uma VPS
O Typebot monta conversas em formato de fluxo — o visitante responde uma pergunta por vez, e o resultado vai para onde você mandar. Serve de formulário de captação, qualificação de lead ou atendimento de primeiro nível.
A instalação tem uma particularidade: são duas aplicações. O builder é onde você desenha os fluxos; o viewer é o que o visitante abre. Cada uma quer o seu subdomínio.
Antes de começar
- VPS com Docker instalado — veja o guia de Docker.
- Dois subdomínios apontados para o IP:
bot.seudominio.com.br(builder) echat.seudominio.com.br(viewer). - 4 GB de RAM é o que recomendo. São duas aplicações Node, mais PostgreSQL e MinIO; em 2 GB fica apertado e o builder engasga.
- Um servidor SMTP para os e-mails de login (o Typebot autentica por link mágico).
Aponte os dois subdomínios
Crie dois registros A, ambos para o IP da VPS. Sem os dois, o certificado de um deles falha e metade do sistema não abre.
dig +short bot.seudominio.com.br
dig +short chat.seudominio.com.br
Gere as chaves e o arquivo de ambiente
O Typebot exige uma chave de criptografia de exatamente 32 caracteres. Menos do que isso e a aplicação nem sobe.
mkdir -p /opt/typebot && cd /opt/typebot
cat > .env <<EOF
DOMINIO_BUILDER=bot.seudominio.com.br
DOMINIO_VIEWER=chat.seudominio.com.br
[email protected]
ENCRYPTION_SECRET=$(openssl rand -base64 24 | cut -c1-32)
POSTGRES_PASSWORD=$(openssl rand -hex 24)
MINIO_PASSWORD=$(openssl rand -hex 20)
# SMTP para o link de login
SMTP_HOST=smtp.seudominio.com.br
SMTP_PORT=587
[email protected]
SMTP_PASSWORD=troque-aqui
[email protected]
EOF
chmod 600 .env
grep ENCRYPTION_SECRET .env | cut -d= -f2 | wc -c
O último comando precisa responder 33 — são 32 caracteres mais a quebra de linha.
Escreva o docker-compose.yml
São cinco serviços: PostgreSQL, MinIO (armazena os arquivos que os visitantes enviam), builder, viewer e o Caddy na frente dos dois domínios.
cat > /opt/typebot/docker-compose.yml <<'EOF'
services:
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: typebot
POSTGRES_USER: typebot
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U typebot"]
interval: 10s
retries: 5
minio:
image: minio/minio
restart: unless-stopped
command: server /data
environment:
MINIO_ROOT_USER: typebot
MINIO_ROOT_PASSWORD: ${MINIO_PASSWORD}
volumes:
- minio_data:/data
criar-bucket:
image: minio/mc
depends_on:
- minio
entrypoint: >
/bin/sh -c "
until (/usr/bin/mc alias set minio http://minio:9000 typebot \"$$MINIO_PASSWORD\"); do sleep 1; done;
/usr/bin/mc mb --ignore-existing minio/typebot;
/usr/bin/mc anonymous set download minio/typebot/public;
exit 0;
"
environment:
MINIO_PASSWORD: ${MINIO_PASSWORD}
builder:
image: baptistearno/typebot-builder:latest
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
environment:
DATABASE_URL: postgresql://typebot:${POSTGRES_PASSWORD}@postgres:5432/typebot
ENCRYPTION_SECRET: ${ENCRYPTION_SECRET}
NEXTAUTH_URL: https://${DOMINIO_BUILDER}
NEXT_PUBLIC_VIEWER_URL: https://${DOMINIO_VIEWER}
ADMIN_EMAIL: ${EMAIL}
SMTP_HOST: ${SMTP_HOST}
SMTP_PORT: ${SMTP_PORT}
SMTP_USERNAME: ${SMTP_USERNAME}
SMTP_PASSWORD: ${SMTP_PASSWORD}
NEXT_PUBLIC_SMTP_FROM: 'Typebot <${EMAIL_REMETENTE}>'
S3_ACCESS_KEY: typebot
S3_SECRET_KEY: ${MINIO_PASSWORD}
S3_BUCKET: typebot
S3_ENDPOINT: minio
S3_PORT: 9000
S3_SSL: "false"
viewer:
image: baptistearno/typebot-viewer:latest
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
environment:
DATABASE_URL: postgresql://typebot:${POSTGRES_PASSWORD}@postgres:5432/typebot
ENCRYPTION_SECRET: ${ENCRYPTION_SECRET}
NEXTAUTH_URL: https://${DOMINIO_BUILDER}
NEXT_PUBLIC_VIEWER_URL: https://${DOMINIO_VIEWER}
S3_ACCESS_KEY: typebot
S3_SECRET_KEY: ${MINIO_PASSWORD}
S3_BUCKET: typebot
S3_ENDPOINT: minio
S3_PORT: 9000
S3_SSL: "false"
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
environment:
DOMINIO_BUILDER: ${DOMINIO_BUILDER}
DOMINIO_VIEWER: ${DOMINIO_VIEWER}
EMAIL: ${EMAIL}
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
volumes:
postgres_data:
minio_data:
caddy_data:
caddy_config:
EOF
cat > /opt/typebot/Caddyfile <<'EOF'
{$DOMINIO_BUILDER} {
tls {$EMAIL}
reverse_proxy builder:3000
}
{$DOMINIO_VIEWER} {
tls {$EMAIL}
reverse_proxy viewer:3000
}
EOF
Suba e crie a conta
cd /opt/typebot
docker compose up -d
docker compose ps
# o builder demora mais na primeira subida: roda as migrações do banco
docker compose logs -f builder
Abra https://bot.seudominio.com.br. O login é por link enviado no e-mail — por isso o SMTP precisa estar certo. O endereço que estiver em ADMIN_EMAIL vira administrador da instalação.
Se o e-mail não chegar, você ainda consegue o link de acesso no log: docker compose logs builder | grep -i "sign in".
Publique o primeiro fluxo
No builder, crie um typebot, monte as perguntas e clique em Publish. O endereço público sai no domínio do viewer, e é ele que você incorpora no site ou envia por link.
Para embutir numa página, o Typebot gera o trecho de código pronto em Share → Embed.
Configure o backup
O que importa é o banco (fluxos e respostas) e o MinIO (arquivos enviados).
cat > /opt/typebot/backup.sh <<'EOF'
#!/bin/bash
set -e
cd /opt/typebot
source .env
DESTINO=/opt/typebot/backups
mkdir -p $DESTINO
DATA=$(date +%Y%m%d-%H%M)
docker compose exec -T postgres pg_dump -U typebot typebot | gzip > "$DESTINO/typebot-$DATA.sql.gz"
docker run --rm -v typebot_minio_data:/dados -v "$DESTINO":/backup alpine tar czf "/backup/arquivos-$DATA.tar.gz" -C /dados .
find "$DESTINO" -name '*.gz' -mtime +7 -delete
EOF
chmod +x /opt/typebot/backup.sh
(crontab -l 2>/dev/null; echo '0 3 * * * /opt/typebot/backup.sh') | crontab -
Se algo não funcionar
O builder não sobe e o log fala da chave de criptografia
O ENCRYPTION_SECRET precisa ter exatamente 32 caracteres. Confira com grep ENCRYPTION_SECRET .env | cut -d= -f2 | wc -c — a resposta deve ser 33, contando a quebra de linha.
O e-mail de login nunca chega
Pegue o link direto do log enquanto ajusta o SMTP:
docker compose logs builder | grep -i 'sign in' | tail -3
O fluxo publicado abre em branco
Quase sempre é o NEXT_PUBLIC_VIEWER_URL apontando para o domínio errado. Corrija no .env e recrie os dois contêineres — variáveis NEXT_PUBLIC_ são gravadas na subida e não mudam sozinhas.
docker compose up -d --force-recreate builder viewer
Memória reservada no KVM, NVMe Gen 4 e rota nacional. Ativação automática.
Perguntas frequentes
Preciso mesmo de dois subdomínios?
Sim. O builder e o viewer são aplicações separadas e o Typebot usa a distinção entre elas para montar os links públicos dos fluxos. Tentar servir as duas no mesmo domínio gera conflito de rotas e sessão.
Roda em 2 GB de RAM?
Sobe, mas fica no limite: são duas aplicações Next.js, PostgreSQL e MinIO no mesmo host. O builder é o que mais consome enquanto você edita. Para uso real, 4 GB.
Dá para conectar o Typebot ao WhatsApp?
Dá. O caminho comum é o fluxo chamar um webhook do n8n, que conversa com a Evolution API. As três aplicações convivem na mesma VPS, se houver memória.
Continue por aqui
Como instalar o n8n em uma VPS com Docker e HTTPS
Sobe o n8n com banco PostgreSQL e certificado automático, em uma VPS Ubuntu com acesso root.
Como instalar a Evolution API em uma VPS
API não oficial de WhatsApp com PostgreSQL e Redis, pronta para integrar com n8n, Typebot ou seu próprio sistema.
Como instalar o Chatwoot em uma VPS
Central de atendimento auto-hospedada: caixa de entrada única para site, e-mail e WhatsApp, com histórico no seu servidor.