Como hospedar uma aplicação Python em produção

CONTEÚDO TBF HOST

Como hospedar uma aplicação Python em produção

Quem desenvolve em Python conhece bem o comando que sobe o servidor de desenvolvimento. Ele funciona tão bem localmente que a pergunta aparece naturalmente: por que não usar isso em produção?

A resposta está na documentação de praticamente todos os frameworks, e costuma ser dada em uma linha: o servidor embutido não foi feito para isso. Ele prioriza conveniência de desenvolvimento — recarregamento automático, mensagens de erro detalhadas — e não segurança, desempenho ou capacidade de atender requisições concorrentes.

Este guia cobre o que substitui esse comando em produção: como a arquitetura se organiza, o que o servidor precisa oferecer, e as decisões que evitam os problemas mais comuns de aplicações Python recém-publicadas.

Por que hospedagem compartilhada raramente serve

A barreira aparece cedo, e vale entender por quê.

O modelo tradicional de hospedagem compartilhada foi construído em torno de um fluxo específico: o servidor web recebe a requisição, invoca um interpretador que executa o código, devolve a resposta e encerra. Funciona bem para o modelo clássico de PHP.

Aplicações Python de produção seguem outra lógica. Elas rodam como um serviço permanente: um processo que carrega o framework e as dependências uma vez, permanece em memória e atende requisições sucessivas. Reiniciar o interpretador a cada requisição seria proibitivamente lento.

Esse modelo exige processo de longa duração, porta própria, controle de ambiente e a possibilidade de instalar bibliotecas — inclusive as que precisam ser compiladas. Na prática, um servidor com acesso root.

WSGI e ASGI: a interface que separa as coisas

Existe uma peça conceitual que, quando entendida, faz o resto da arquitetura ficar óbvia.

Python padronizou como um servidor web conversa com uma aplicação web. Essa padronização é o que permite trocar de servidor sem reescrever a aplicação, e trocar de framework sem trocar o servidor.

WSGI é a interface síncrona, usada historicamente por Django e Flask. Cada requisição ocupa um trabalhador do início ao fim.

ASGI é a interface assíncrona, criada para suportar o que o WSGI não comporta: conexões persistentes como WebSocket, eventos enviados pelo servidor e código assíncrono. Frameworks como FastAPI operam nesse modelo, e o Django também o suporta.

A consequência prática para infraestrutura: a interface determina qual servidor de aplicação usar. Uma aplicação ASGI executada por um servidor exclusivamente WSGI perde justamente as capacidades assíncronas que motivaram a escolha. É um dos erros de configuração mais comuns, e ele não gera erro visível — apenas desempenho pior do que o esperado.

A arquitetura de produção

Uma aplicação Python em produção tem tipicamente três camadas, e cada uma resolve um problema diferente.

1. Servidor web na borda

Recebe o tráfego da internet, termina o TLS, serve arquivos estáticos e de mídia, e encaminha o restante para a aplicação. É a camada que fica exposta.

Servir estáticos pelo servidor web, e não pela aplicação, é uma das otimizações mais simples e mais esquecidas: cada arquivo entregue pelo servidor web é um trabalhador da aplicação que permanece livre para atender requisições reais.

2. Servidor de aplicação

É o que substitui o servidor de desenvolvimento. Ele carrega a aplicação, gerencia um conjunto de trabalhadores e distribui as requisições entre eles.

O número de trabalhadores é a decisão de configuração mais relevante nessa camada, e ela depende do perfil da aplicação:

  • Aplicações limitadas por processamento — cálculo, transformação de dados, geração de documentos — se beneficiam de um número de trabalhadores proporcional aos núcleos disponíveis.
  • Aplicações limitadas por espera — que passam a maior parte do tempo aguardando banco de dados ou APIs externas — comportam mais concorrência, seja por trabalhadores assíncronos, seja pelo modelo ASGI.

Uma armadilha frequente: cada trabalhador é um processo que carrega a aplicação inteira na memória. Configurar muitos trabalhadores em um servidor com pouca memória leva ao esgotamento — e o sistema operacional começa a encerrar processos, produzindo falhas intermitentes difíceis de diagnosticar.

3. Supervisão

Assim como qualquer serviço, a aplicação precisa iniciar automaticamente após reinicialização do servidor, ser reiniciada em caso de falha e ter sua saída registrada em log. Um gerenciador de serviços do sistema operacional resolve isso.

Ambiente isolado e dependências

Python tem uma particularidade que causa problemas específicos em produção.

O sistema operacional geralmente já traz uma instalação de Python usada por ferramentas internas. Instalar dependências da sua aplicação nessa instalação global mistura os dois mundos e pode quebrar utilitários do sistema — ou fazer com que uma atualização do sistema quebre a sua aplicação.

A prática consolidada é isolar o ambiente da aplicação, seja por ambiente virtual, seja por contêiner. Duas regras que evitam retrabalho:

  1. Fixe as versões das dependências. Instalar sem versão fixa significa que produção pode receber uma versão diferente da testada, e a diferença pode aparecer semanas depois.
  2. Considere as dependências de compilação. Bibliotecas científicas e conectores de banco frequentemente exigem componentes de sistema para instalar. É uma diferença relevante em relação a linguagens puramente interpretadas, e uma razão a mais para precisar de controle sobre o servidor.

Sobre a versão do Python: use uma versão que ainda esteja recebendo correções de segurança. O ciclo de suporte de cada versão é publicado oficialmente pelo projeto, e vale consultá-lo na data da decisão, planejando a atualização antes do encerramento do suporte em vez de depois.

Tarefas em segundo plano

Esta é a diferença que mais frequentemente separa uma aplicação que funciona de uma que trava sob carga.

Envio de e-mail, geração de relatório, processamento de imagem, chamada a uma API lenta de terceiros, importação de arquivo — todas essas operações têm algo em comum: não devem acontecer durante o ciclo da requisição.

Quando acontecem, o trabalhador fica ocupado enquanto a operação dura. Com trabalhadores suficientes ocupados simultaneamente, novas requisições ficam em fila e o site inteiro parece travado — ainda que o servidor esteja longe do limite de recursos.

A solução padrão é uma fila: a aplicação registra a tarefa e responde imediatamente ao usuário, enquanto processos separados executam o trabalho pesado. Isso adiciona componentes à arquitetura — normalmente um intermediário de mensagens e processos trabalhadores próprios — e é um argumento a favor de um ambiente onde você controla o que roda.

Vale a mesma observação feita no artigo sobre aplicações Node.js em produção: a decisão entre resolver com mais recursos ou com arquitetura assíncrona depende do perfil da carga, não do tamanho do servidor.

Banco de dados e conexões

Um detalhe que causa problema em produção e não aparece em desenvolvimento: cada trabalhador mantém suas próprias conexões com o banco de dados.

Multiplique o número de trabalhadores pelo número de conexões por trabalhador e compare com o limite configurado no banco. Aplicações que “funcionam bem até um certo ponto e então falham” frequentemente esgotaram o limite de conexões, não a memória.

Para aplicações com muitos trabalhadores, um agrupador de conexões resolve, mantendo um conjunto controlado de conexões reutilizadas. É configuração de infraestrutura, não de código.

Publicação e configuração

O roteiro de publicação de uma aplicação Python tem etapas específicas:

  1. Instalar dependências no ambiente isolado, com versões fixadas.
  2. Aplicar migrações de banco, com atenção à ordem em relação ao código novo — migrações compatíveis com as duas versões evitam indisponibilidade.
  3. Coletar arquivos estáticos, quando o framework exigir essa etapa.
  4. Recarregar os trabalhadores de forma que as requisições em andamento sejam concluídas antes do encerramento dos antigos.
  5. Verificar o estado por um endpoint de saúde antes de considerar a publicação concluída.

Sobre configuração: chaves, credenciais e endereços de serviço ficam em variáveis de ambiente, fora do código e separados por ambiente. E há um item específico do ecossistema Python que merece destaque — a configuração de modo de depuração precisa estar desativada em produção. Quando ativa, ela expõe detalhes internos da aplicação, incluindo trechos de configuração, em páginas de erro visíveis publicamente. É uma das falhas de segurança mais frequentes em aplicações Python publicadas às pressas.

Antes de considerar em produção

  • A aplicação roda sob um servidor de aplicação adequado à interface que ela usa, e não sob o servidor de desenvolvimento?
  • O número de trabalhadores foi definido a partir do perfil de carga e da memória disponível?
  • Existe supervisão que reinicia a aplicação e a sobe após reinicialização do servidor?
  • O ambiente está isolado e as versões das dependências fixadas?
  • Arquivos estáticos são servidos pelo servidor web, não pela aplicação?
  • O modo de depuração está desativado e os segredos estão fora do código?
  • Tarefas longas foram movidas para fila?
  • O total de conexões com o banco cabe no limite configurado?
  • Logs têm rotação e existe alerta quando a aplicação para de responder?

Conclusão

Levar uma aplicação Python para produção é substituir a conveniência do ambiente de desenvolvimento por uma arquitetura com responsabilidades separadas: servidor web na borda, servidor de aplicação executando o código, supervisão mantendo tudo vivo e, quando necessário, fila absorvendo o trabalho pesado.

As decisões que mais evitam problema são baratas no início: escolher o servidor de aplicação compatível com a interface da aplicação, dimensionar trabalhadores pela memória real, isolar o ambiente com versões fixadas, desativar o modo de depuração e tirar as tarefas longas do ciclo da requisição.

Se você está definindo onde publicar, o requisito de partida é um ambiente que execute serviços permanentes e permita instalar as dependências que a sua aplicação exige. Conheça o Cloud Server para Python da TBF Host e avalie a configuração adequada ao perfil do seu projeto.

Perguntas frequentes

Posso hospedar uma aplicação Python em hospedagem compartilhada?

Raramente funciona bem. O modelo de hospedagem compartilhada executa o código a cada requisição e encerra o processo, enquanto aplicações Python de produção rodam como serviço permanente que carrega framework e dependências uma vez e permanece em memória. Isso exige processo de longa duração, porta própria e controle sobre o ambiente.

Posso usar o servidor de desenvolvimento do Django ou Flask em produção?

Não. Os próprios frameworks desaconselham. O servidor embutido prioriza conveniência de desenvolvimento, como recarregamento automático e mensagens de erro detalhadas, e não foi construído para segurança, desempenho ou atendimento de requisições concorrentes. Em produção, usa-se um servidor de aplicação adequado.

Qual a diferença entre WSGI e ASGI?

São as interfaces padronizadas que definem como um servidor web conversa com uma aplicação Python. O WSGI é síncrono e ocupa um trabalhador por requisição, do início ao fim. O ASGI é assíncrono e suporta conexões persistentes, como WebSocket, além de código assíncrono. A interface usada determina qual servidor de aplicação escolher.

Quantos workers configurar em uma aplicação Python?

Depende do perfil da carga e da memória disponível. Aplicações limitadas por processamento se beneficiam de um número proporcional aos núcleos. Aplicações que passam a maior parte do tempo esperando banco ou APIs externas comportam mais concorrência. Cada trabalhador carrega a aplicação inteira na memória, então excesso de workers leva a esgotamento e falhas intermitentes.

Por que minha aplicação Python trava sob carga mesmo com recursos sobrando?

Geralmente porque operações longas estão sendo executadas durante o ciclo da requisição — envio de e-mail, geração de relatório, chamada a API lenta. Cada uma ocupa um trabalhador enquanto dura, e com trabalhadores suficientes ocupados as novas requisições ficam em fila. A solução é mover essas tarefas para uma fila processada separadamente.

Preciso de ambiente virtual em produção?

Sim, ou de contêiner. O sistema operacional traz uma instalação de Python usada por ferramentas internas, e instalar as dependências da aplicação nela pode quebrar utilitários do sistema ou fazer com que uma atualização do sistema quebre a aplicação. Também é importante fixar as versões das dependências.

O que é preciso desativar em uma aplicação Python em produção?

O modo de depuração. Quando ativo, ele expõe detalhes internos da aplicação, incluindo trechos de configuração, em páginas de erro visíveis publicamente. É uma das falhas de segurança mais frequentes em aplicações publicadas sem revisão de configuração.

Por que minha aplicação falha depois de certo volume de acessos?

Uma causa frequente é o esgotamento do limite de conexões do banco de dados. Cada trabalhador mantém suas próprias conexões, então o total é o número de trabalhadores multiplicado pelas conexões de cada um. Quando esse total ultrapassa o limite configurado no banco, novas requisições falham mesmo com memória e processamento sobrando.

Facebook
X
LinkedIn