Container FastAPI parando sozinho na VPS? Como o processo principal e o CMD definem o ciclo de vida

Fala aí, beleza? Tu sobe a API FastAPI em Docker na VPS, testa, funciona, e pouco depois (ou no primeiro reboot do servidor) ela simplesmente não está mais lá 😛
Tenha acesso root e SSD NVMe, com 10% OFF extra pelo link da Hora de Codar.
Ver a oferta de VPS Parceria Hora de CodarEste post é sobre diagnóstico: container que encerra sozinho ou que não volta quando a VPS reinicia. A instalação do Docker e o deploy completo estão no guia de subir a API com Docker e HTTPS, então aqui vamos direto ao que decide o ciclo de vida
O diagnóstico precisa conferir tanto o comando de inicialização e a política do Docker quanto os logs e os erros da aplicação
Por que o container FastAPI para sozinho?
O container só vive enquanto o processo principal dele estiver rodando
A documentação oficial do FastAPI sobre Docker diz isso com todas as letras: normalmente é um único processo (o comando ou programa que você definiu), e quando não sobra nenhum processo rodando dentro dele, o container para
O sintoma típico é esse: o container sobe e logo some da lista
Aqui costuma aparecer uma confusão comum, que é tratar imagem e container como a mesma coisa
E qual é a diferença?
- Imagem: a versão estática, com arquivos, variáveis de ambiente e o comando padrão, sem nada em execução
- Container: a instância em execução dessa imagem
Se você conhece orientação a objetos, a ideia é bem semelhante a classe e objeto: a imagem é a receita, o container é a coisa rodando 🙂
Por isso reconstruir a imagem não mantém nada no ar
O que mantém o container vivo é o processo que ele executa
Solução: garantir que o comando padrão da imagem seja o servidor da API rodando em primeiro plano. Se esse comando termina, o container termina junto
Como prevenir: trate o CMD como a linha que decide o ciclo de vida, e não como um detalhe esquecido no fim do Dockerfile
Como ver containers parados e descobrir o estado de cada um:
Rode docker ps -a
O sintoma é clássico: você roda docker ps e a API não aparece. A causa é simples: segundo a referência do docker container ls, por padrão o docker ps mostra só os containers em execução
A flag -a (ou --all) lista todos, inclusive os parados:
docker ps -a
# equivalente
docker container ls --all
Na listagem, cada container aparece com um estado, e cada um conta uma parte da história:
- running: está em execução, então o problema provavelmente está em outro lugar (porta, proxy e tal)
- exited: não está mais rodando, porque o processo terminou ou porque alguém rodou
docker stop - created: o container foi criado, mas nunca foi iniciado
Checagem: procure o container da API e veja se ele está como exited ou created
Se está exited e ninguém deu docker stop, o processo principal terminou, e aí vale olhar o CMD (próxima seção)
Se está created, ele nem chegou a ser iniciado
Erro comum: concluir que o container foi apagado só porque sumiu do docker ps. Na maioria das vezes ele está ali, parado, esperando você olhar com o -a
CMD na forma exec ou shell: qual usar no Dockerfile do FastAPI?
Use a forma exec, com colchetes
O sintoma aqui é mais sutil: você para o container e o encerramento é brusco, e o código que deveria rodar no desligamento (os eventos de lifespan) não dispara
Que lifespan? É o mecanismo do FastAPI pra executar lógica quando a aplicação inicia e quando ela encerra, tipo abrir e fechar conexões
A documentação do FastAPI recomenda a forma exec justamente para o FastAPI encerrar de forma graciosa e os eventos de lifespan serem disparados
Lado a lado fica assim:
# Forma exec (recomendada)
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
# Forma shell (evitar)
CMD fastapi run app/main.py --port 80
Parece só estética, né? Não é haha
Checagem: troque o CMD para a forma com colchetes, faça o rebuild da imagem e crie um container novo a partir dela. Lembra que a imagem é estática: o container antigo continua com o comando antigo
Como prevenir: antes de mexer em qualquer outra coisa, revise o CMD. É a primeira linha que eu olharia num container que se comporta estranho ao parar
Container não volta depois que a VPS reinicia: política de reinício
O padrão do Docker é não reiniciar, então você precisa definir a política com --restart
O sintoma: o servidor reinicia e a API fica fora do ar até alguém entrar e subir na mão
Mais controle no próximo deploy.
Configure sua aplicação em uma VPS Hostinger com acesso root. Escolha os recursos conforme o que seu projeto precisa.
- SSD NVMe
- AMD EPYC
- Backups semanais
A causa está na documentação de início automático do Docker: a política é definida com a flag --restart no docker run, e o valor padrão é no
As opções são:
- no: padrão, não reinicia
- always: sempre reinicia se o container parar
- unless-stopped: igual ao always, mas se você parou o container manualmente, ele não volta nem quando o daemon reinicia
- on-failure[:max-retries]: reinicia só quando o processo sai com código diferente de zero, com limite opcional de tentativas
O exemplo oficial com unless-stopped segue este formato:
docker run -d --name <nome> --restart unless-stopped <imagem>
Qual a diferença entre always e unless-stopped?
A diferença aparece depois de um docker stop manual
Com always, a política fica ignorada até o daemon Docker reiniciar ou até você reiniciar o container manualmente. Ou seja, num reboot do servidor ele volta
Com unless-stopped, o container continua parado mesmo depois que o daemon reinicia
Erro comum: dar docker stop pra testar e esperar que o unless-stopped traga o container de volta. Ele não vai trazer, e isso é o comportamento esperado, não um bug!
Por que o container em loop de falha demora pra voltar?
Porque o Docker aplica um atraso crescente entre as tentativas, pra não sobrecarregar o servidor
Segundo a referência do docker run, o atraso começa em 100 ms e dobra a cada tentativa, respeitando o limite de tentativas configurado para on-failure e as ações manuais de parada
Se o container consegue rodar por pelo menos 10 segundos, o atraso volta pra 100 ms
Então se a API quebra logo depois de subir, cada nova tentativa demora mais… e parece que o Docker desistiu. Não desistiu, só está esperando
Nesse caso, a política de reinício não resolve nada: o problema é o processo principal terminando, volta lá no CMD e nos logs da aplicação
O Docker inicia junto com o sistema?
No Debian e no Ubuntu, sim, o serviço Docker já inicia no boot por padrão
Em outras distribuições Linux com systemd, a documentação de pós-instalação do Docker indica habilitar os serviços:
sudo systemctl enable docker.service
sudo systemctl enable containerd.service
Sem o daemon subindo no boot, nenhuma política de reinício funciona, porque não tem quem reinicie o container
Como prevenir: defina a política já no primeiro docker run, e não depois que a API caiu em produção
Que servidor eu preciso pra controlar isso?
Um servidor em que você tenha acesso root, porque mexer em systemctl e no daemon do Docker exige isso
A recomendação da Hora de Codar pra esse cenário é a VPS da Hostinger (este artigo contém links de afiliado da Hostinger). Os planos de VPS KVM da Hostinger incluem acesso root completo, SSD NVMe, processadores AMD EPYC e backups semanais gratuitos que podem ser restaurados pelo painel, com opção de servidor no Brasil
Mas se liga: container que não volta é erro de configuração
Trocar de servidor não corrige CMD na forma errada nem política de reinício faltando. O servidor só te dá o controle pra aplicar a correção
Como conferir os headers quando a API está atrás de um proxy
A seção oficial sobre proxy de terminação TLS orienta adicionar --proxy-headers nesse cenário. Confira também quais endereços podem enviar esses headers, em vez de tratar qualquer remetente como confiável
O sintoma: a API está atrás de Nginx ou Traefik com HTTPS, mas enxerga a requisição como HTTP, ou não recebe o host e o IP originais do cliente

Crie sistemas com IA para vender
Prompts, modelos e checklists para criar e publicar seu sistema com IA e preparar a oferta para o primeiro cliente.
Quero o e-book gratuito Receba o livro e os bônus no seu e-mail.A causa, segundo a documentação do FastAPI sobre rodar atrás de proxy, é que por segurança o servidor iniciado pelo comando fastapi run não interpreta esses headers, porque não sabe que está atrás de um proxy confiável
E que headers são esses? Eles preservam dados da requisição original:
- X-Forwarded-For: o IP do cliente
- X-Forwarded-Proto: o protocolo, por exemplo https
- X-Forwarded-Host: o host original
A mesma documentação trata a flag --forwarded-allow-ips como a opção que define quais IPs são considerados confiáveis para que esses headers sejam lidos. Com --forwarded-allow-ips="*" o servidor confia em qualquer IP, cenário que a documentação associa a situações em que só o proxy confiável fala com o servidor
Separadamente, o Dockerfile oficial do FastAPI traz um comentário indicando adicionar --proxy-headers quando a aplicação roda atrás de um proxy como Nginx ou Traefik:
# If running behind a proxy like Nginx or Traefik add --proxy-headers
CMD ["fastapi", "run", "app/main.py", "--port", "80", "--proxy-headers"]
Como prevenir: antes de copiar uma linha de CMD pronta da internet juntando as duas flags, confira na documentação "Behind a Proxy" qual IP (ou faixa) representa o seu proxy, em vez de liberar tudo com "*" por padrão sempre que for viável. E repare que o CMD continua em colchetes, não vale ganhar o proxy e perder o encerramento gracioso xD
Build lento a cada mudança: cache de camadas e pip –no-cache-dir
A ordem das instruções no Dockerfile é o que faz o Docker reaproveitar a instalação das dependências
O sintoma: você muda uma linha da API e o build baixa e instala todas as dependências de novo
A causa: copiar o código antes do requirements.txt invalida o cache do passo de instalação, já que qualquer mudança no código muda aquela camada e tudo que vem depois
A documentação do FastAPI orienta copiar primeiro só o requirements.txt, instalar as dependências e só depois copiar o código. Como o requirements muda pouco, o Docker reaproveita o cache desse passo
O trecho abaixo é um exemplo didático que mostra só a ordem (o Dockerfile completo, com imagem base e diretório de trabalho, está na documentação):
# 1. primeiro, só o arquivo de dependências
COPY ./requirements.txt ./requirements.txt
# 2. instalação: camada reaproveitada enquanto o requirements não muda
RUN pip install --no-cache-dir --upgrade -r requirements.txt
# 3. só depois, o código da aplicação
COPY ./app ./app
Erro comum: achar que --no-cache-dir desliga o cache do Docker
Não desliga! Segundo a documentação do FastAPI, essa opção é do pip: ela faz o pip não guardar localmente os pacotes baixados depois de instalados
Checagem: altere só um arquivo dentro de app, rode o build de novo e confirme que o passo do pip install não baixa e instala tudo outra vez
Um processo por container ou vários workers: o que muda no ciclo de vida?
Depende de onde o container roda, mas a regra do processo principal vale em qualquer caso
Em cluster, tipo Kubernetes, a documentação do FastAPI sobre workers recomenda não usar --workers e rodar um único processo Uvicorn por container, deixando a replicação pro nível do cluster
Fora desse cenário, quando você usa --workers, a própria documentação explica que o processo pai passa a funcionar como gerenciador de processos dos workers
E isso muda o que é o processo principal: o processo que o Docker observa deixa de ser o servidor atendendo requisições e passa a ser esse gerenciador. Então quem decide se o container continua rodando é ele: se o processo pai (gerenciador) termina, o container para, não importa quantos workers ele mantinha vivos
Ou seja, a regra do início deste artigo, o container vive enquanto o processo principal vive, não muda com workers. Só muda quem é esse processo principal
Quantos workers cabem no seu servidor é outra conversa, e fica pro guia sobre workers do FastAPI com pouca RAM
Conteúdo do canal Hora de Codar
No canal Hora de Codar tem um vídeo mostrando o plugin OMO (All My Open Agent) pro Open Code, com agentes especialistas pra planejamento e execução
Fica aqui pra quem quer conhecer o canal e usa o Open Code no dia a dia 🙂
Próximo passo: deixar a API resiliente na VPS
Como sugestão de validação em um ambiente de teste ou numa janela de manutenção, confira o comportamento após reiniciar o servidor:
- Rode
docker ps -ae anote o estado do container da API (running, exited ou created) - Abra o Dockerfile e confirme que o
CMDestá na forma exec, com colchetes. Se não estiver, corrija e faça o rebuild da imagem - Antes de substituir um container, preserve os dados e volumes necessários. Em um ambiente de teste preparado para a substituição, crie o novo container com a política:
docker run -d --name <nome> --restart unless-stopped <imagem>. Erro comum deste passo: esquecer que um container parado comdocker stopnão volta sozinho com unless-stopped - Reinicie a VPS e, quando ela voltar, rode
docker psde novo. A API precisa aparecer em execução sem você subir nada na mão
Se ainda não tem um servidor com acesso root pra fazer esse controle, dá pra conferir a VPS para este projeto e já começar com a política de reinício certa desde o primeiro container
Até o próximo post! 😀
Quer aprender mais sobre inteligência artificial e programação na prática? Conheça o canal Hora de Codar no YouTube e acompanhe os próximos vídeos.
Formações
Formação Claude Code
Domine Claude Code do absoluto zero até o avançado
- 120 aulas
- 4 projetos
- 9h 48min
Blog | Mais populares

Checklist de segurança n8n VPS pública: guia essencial para proteger sua instalação
Checklist de segurança n8n VPS pública: guia essencial para proteger sua instalação A popularidade da automação de processos com o n8n está em alta, principalmente […]

Checklist de segurança n8n VPS 2026: proteja sua automação
Confira o checklist de segurança n8n VPS 2026 e mantenha sua automação protegida. Veja práticas essenciais e atualizadas para seu servidor. Manter seu ambiente de […]
Quanto custa uma VPS? Preço atualizado 2026
Quando se fala em quanto custa uma VPS, é preciso contextualizar o tema a partir de um provedor específico, porque o preço só faz sentido […]
