UpuaiUpuai

Hospedar bot do Telegram ou Discord 24/7 no Brasil (Node e Python)

Guia prático para hospedar bot do Telegram ou Discord 24/7 no Brasil: rode como worker no Upuai com git push, token em variável de ambiente, logs por processo e custo em Real, começando grátis.

Equipe Upuai· Upuai Cloud10 min de leitura

Todo bot nasce igual: funciona perfeitamente no node bot.js do seu terminal e morre no momento em que você fecha o notebook. Hospedar um bot do Telegram ou Discord 24/7 é o passo que separa o script de fim de semana de um serviço que responde às 3 da manhã, quando você não está olhando.

O caminho clássico era ruim dos dois lados: VPS na mão (SSH, systemd ou PM2, plantão quando cai) ou uma PaaS gringa com fatura em dólar mais IOF por um processo que consome quase nada. E o velho atalho gratuito, que fazia o bot hibernar quando ninguém usava, deixou de existir faz tempo.

Este guia mostra o caminho que a gente considera o mais direto hoje: o bot como processo worker no Upuai, no ar com um git push, com o token guardado em variável de ambiente, logs por processo e a fatura em Real. Funciona igual para Node e Python, Telegram e Discord, e o plano Free não pede cartão. Todos os comandos e limites citados são os reais da plataforma, hoje.

Por que um bot não é um site (e por que isso muda o deploy)

A maioria dos tutoriais de deploy assume um app web: um servidor HTTP que escuta numa porta e responde requisições. Um bot típico é o oposto disso.

No modo mais comum (long polling), o bot abre a conexão de saída: ele fica perguntando aos servidores do Telegram ou mantendo o gateway do Discord aberto, esperando eventos. Não há porta pública, não há endpoint HTTP, não há health check pra responder. É um processo de longa duração que precisa de exatamente duas coisas: ficar de pé o tempo todo e voltar sozinho se cair.

Plataformas serverless e de site estático brigam com esse modelo, porque foram desenhadas pra função que executa e encerra. O que um bot pede é o modelo oposto: um container de longa duração, o mesmo que descrevemos no guia de deploy de Next.js para SSR.

No Upuai, isso tem nome: processo do tipo worker. Você declara num arquivo de config que o seu comando não é um servidor web, e a plataforma roda o processo num Kubernetes gerenciado, sem esperar porta nem health check HTTP. Se o processo morrer, o orquestrador o recoloca de pé. É essa declaração de uma linha que faz o deploy de bot deixar de ser gambiarra.

O que você precisa antes de começar

  1. O código do bot num repositório GitHub ou GitLab. Node ou Python, qualquer biblioteca (grammY, Telegraf, discord.js, python-telegram-bot, discord.py).
  2. O token do bot: no Telegram, o @BotFather te dá um com o comando /newbot; no Discord, ele sai do Developer Portal, na aba Bot da sua aplicação. Guarde e nunca commite.
  3. Uma conta no Upuai: o plano Free não pede cartão. Crie em app.upuai.com.br (login por GitHub OAuth ou código por e-mail).

Não precisa de Dockerfile nem YAML. O build usa o railpack, builder zero-config que detecta Node pelo package.json e Python pelo requirements.txt ou pyproject.toml.

Passo a passo: bot de Telegram em Node, no ar

Um bot mínimo com grammY, em bot.js:

import { Bot } from 'grammy'

const bot = new Bot(process.env.BOT_TOKEN)

bot.command('start', (ctx) => ctx.reply('No ar, 24/7.'))
bot.on('message', (ctx) => ctx.reply('Recebi: ' + ctx.message.text))

bot.start() // long polling: o bot abre a conexão, nenhuma porta necessária

O package.json só precisa da dependência e de nada especial de infra. O pulo do gato é o upuai.toml na raiz do repositório, declarando o processo como worker:

#:schema https://upuai.com.br/schemas/upuai-toml-v1.json

[processes.bot]
command = "node bot.js"
# type é opcional: qualquer nome que não seja web/clock/cron/release é inferido como worker

Com o arquivo no repo, o deploy é o fluxo padrão da plataforma. Pelo dashboard: novo projeto em app.upuai.com.br, autorize o GitHub App, escolha o repositório e pronto. Ou pela CLI:

# macOS / Linux
brew tap saiph-ti/upuai-cli
brew install upuai

upuai login   # uma vez por máquina (GitHub OAuth ou: upuai login --email)

upuai init \
  --name meu-bot \
  --repo sua-org/meu-bot \
  --branch main \
  --framework Node.js \
  --yes

upuai deploy --wait --yes

O --wait bloqueia até o deploy chegar num status final. A partir daqui, todo git push na branch conectada rebuilda e sobe o bot sozinho, e o upuai rollback --to <id> --yes reverte se uma versão nova quebrar.

Ainda sem repositório git, ou querendo testar código local não commitado? O upuai up empacota o diretório atual e deploya direto (excluindo .git, node_modules e .env* automaticamente).

E em Python: bot de Discord com discord.py

O mesmo fluxo, trocando o runtime. Um bot mínimo em bot.py:

import os
import discord

intents = discord.Intents.default()
intents.message_content = True  # habilite também no Developer Portal (intent privilegiada)

client = discord.Client(intents=intents)

@client.event
async def on_message(message):
    if message.author == client.user:
        return
    if message.content.startswith("!ping"):
        await message.channel.send("pong")

client.run(os.environ["BOT_TOKEN"])

Com discord.py no requirements.txt, o railpack detecta o projeto Python sem config extra. O upuai.toml muda uma linha:

#:schema https://upuai.com.br/schemas/upuai-toml-v1.json

[processes.bot]
command = "python bot.py"

E o init recebe --framework Python em vez de Node.js. O resto (deploy, logs, variáveis) é idêntico. Detalhe do Discord: a intent de conteúdo de mensagem é privilegiada, então além da linha no código você precisa ativá-la na aba Bot do Developer Portal, senão o bot conecta mas não lê as mensagens.

O token em variável de ambiente, nunca no código

Token de bot em repositório é a forma mais rápida de ver seu bot respondendo coisas que você não escreveu. O caminho certo é variável de ambiente, e no Upuai isso é um comando:

upuai vars set BOT_TOKEN=123456:ABC-xxxxxxxx --yes

Três detalhes que valem saber:

  • Escopo de runtime pra segredos: upuai variables set BOT_TOKEN=xxx --scope runtime mantém o token fora da imagem de build. Pra bot, é o escopo certo.
  • Variáveis valem a partir do próximo deploy. Setou e quer aplicar agora? upuai redeploy --yes.
  • .env fora do deploy: no upuai up, o empacotamento exclui .env* automaticamente. No fluxo git, quem protege é o seu .gitignore: se o .env foi commitado, ele está no repositório que o deploy puxa. Não commite .env.

Se o bot usa banco (fila de jobs, memória de conversa, contadores), upuai add --type database --engine postgres provisiona um Postgres gerenciado no mesmo projeto e injeta a DATABASE_URL no processo automaticamente. O mesmo vale pra Redis com --engine redis.

Polling ou webhook?

Os dois modos funcionam na plataforma, e a escolha muda a config:

  • Long polling (recomendado pra começar): o bot puxa as atualizações. Não precisa de URL pública, não precisa de porta, roda como o worker que configuramos acima. É o modo dos exemplos deste guia e o mais simples de operar.
  • Webhook: o Telegram (ou o Discord, em interações via HTTP) chama uma URL sua a cada evento. Nesse caso o bot é um servidor web: declare o processo como web (nome [processes.web]), escute na porta que a plataforma injeta em PORT, e a URL pública https://seu-bot.upuai.com.br sai do deploy com SSL automático. Webhook faz sentido em volume alto de mensagens ou quando você quer o mesmo serviço respondendo HTTP pra outras coisas.

A regra prática: comece com polling; migre pra webhook quando tiver motivo medido, não por moda.

Logs, restart e o dia a dia do bot no ar

Bot 24/7 sem visibilidade é bot que você descobre que caiu pelo grupo reclamando. O dia a dia na CLI:

upuai ps                          # processos do serviço (tipo, réplicas, comando)
upuai logs -n 200                 # últimas 200 linhas de runtime
upuai logs --process bot          # filtra só o processo do bot
upuai logs --build                # log do build (quando o deploy falha)
upuai restart --process bot --yes # reinicia só o bot

Dois avisos de quem já operou bot em produção:

  • Não escale bot de polling pra mais de 1 instância. Duas réplicas com o mesmo token brigam: o Telegram rejeita conexões simultâneas de getUpdates e o Discord entrega os mesmos eventos duas vezes, ou seja, resposta duplicada no chat. Uma instância de worker aguenta muito bot; se um dia precisar de mais, o caminho é webhook ou sharding, não réplica de polling.
  • Deixe o processo morrer em caso de erro fatal. Não engula exceções pra “manter vivo”: o processo que encerra com erro é reposto pelo orquestrador, e o motivo fica registrado no log. Um try/catch global que silencia erro só transforma um crash visível num zumbi invisível.

Quanto custa rodar um bot 24/7 (em Real)

A conta é em Real, com pagamento por Pix ou boleto, sem cartão internacional, sem IOF, sem câmbio na fatura (a matemática de por que isso pesa está no comparativo de custo de cloud no Brasil).

PlanoPreço/mêsProjetosServiços/projetoProcessos/serviçoLogs
FreeR$ 012212h
StarterR$ 1923324h
ProR$ 9955572h

No anual, os planos pagos saem por 10 vezes o valor mensal, o que dá 2 meses grátis.

Pra um bot, na prática:

  • Free cobre o bot inteiro: o bot é 1 serviço, e ainda sobra espaço pra 1 banco gerenciado (Postgres ou Redis) no mesmo projeto. Bot típico é leve, e o processo worker roda confortável nos recursos padrão do plano.
  • Starter (R$ 19) entra quando você quer retenção maior de log, um segundo projeto ou um terceiro processo no mesmo serviço (bot + painel web + clock de tarefas agendadas, por exemplo).
  • Pro (R$ 99) é território de quem opera vários bots ou bots com serviços em volta (painel web, API, filas).

Se você está comparando com as opções gringas de sempre, fizemos essa análise em detalhe em alternativa ao Railway no Brasil.

FAQ

O bot dorme ou hiberna no plano Free?

O modelo da plataforma é container de longa duração: o processo worker fica de pé, não é função serverless que congela entre invocações nem dyno que hiberna por inatividade. E se o processo cair, o Kubernetes gerenciado o recoloca no ar.

Preciso de Dockerfile?

Não. O railpack detecta Node pelo package.json e Python pelo requirements.txt/pyproject.toml e builda o container sozinho. Se você já tem um Dockerfile e prefere usá-lo, dá pra trocar o builder pra dockerfile no upuai.toml, mas pra bot é quase sempre desnecessário.

Posso rodar o bot e um site no mesmo repositório?

Sim, e é um caso clássico de multi-processo: declare [processes.web] pro site e [processes.bot] pro bot no mesmo upuai.toml. Um git push builda a imagem uma vez e sobe os dois processos compartilhando o mesmo build e as mesmas variáveis de ambiente.

Como o bot guarda estado (memória de conversa, fila, contadores)?

Com um banco gerenciado no mesmo projeto: upuai add --type database --engine postgres (ou --engine redis) provisiona a instância e injeta a string de conexão como variável de ambiente. No Free, bot + 1 banco cabem no limite de 2 serviços.

O deploy quebrou. Por onde começo?

upuai logs --build mostra o build, upuai logs --process bot mostra o runtime do bot. Os erros mais comuns de bot são token errado na variável de ambiente e dependência faltando no package.json/requirements.txt. Pra reverter uma versão ruim: upuai rollback --list e upuai rollback --to <id> --yes.

Do localhost ao 24/7

O resumo do caminho: código no repositório, upuai.toml com o processo declarado como worker, token em variável de ambiente e git push. O bot passa a viver num container gerenciado no Brasil, que fica de pé, volta sozinho quando cai e conta nos logs o que aconteceu. Sem VPS pra cuidar, sem dólar na fatura.

Crie sua conta grátis, sem cartão →

Referências úteis: a documentação do upuai.toml tem o esquema completo de processos, e a documentação da CLI a lista inteira de comandos.

Faça deploy no Brasil em 5 minutos

PaaS brasileira, preços em Real, infraestrutura LGPD-native.

Ver planos

Artigos relacionados