---
title: "Como hospedar API FastAPI na VPS com Gunicorn e Nginx"
description: "Hospede uma API FastAPI na VPS Ubuntu: ambiente virtual, Gunicorn com workers Uvicorn, serviço systemd, Nginx com HTTPS e os erros mais comuns."
url: "https://streethosting.com.br/guias/vps/hospedar-api-fastapi-vps"
category: "vps"
slug: "hospedar-api-fastapi-vps"
datePublished: "2026-09-28"
dateModified: "2026-09-28"
author: "Equipe StreetHosting"
difficulty: "intermediario"
language: "pt-BR"
keywords:
  - "hospedar fastapi vps"
  - "deploy fastapi ubuntu"
  - "gunicorn uvicorn worker"
  - "fastapi nginx proxy reverso"
  - "fastapi systemd service"
---

# FastAPI em produção na VPS: Gunicorn, Uvicorn, systemd e HTTPS

Uma API FastAPI pronta para produção em uma VPS Ubuntu 24.04: Python em ambiente virtual, Gunicorn gerenciando workers Uvicorn pelo pacote atual, serviço systemd com reload sem queda, Nginx com HTTPS e como dimensionar os workers.

> **Resposta rápida**
>
> Para **hospedar FastAPI na VPS**, instale a aplicação em um ambiente virtual Python, rode com Gunicorn usando a classe `uvicorn_worker.UvicornWorker` do pacote `uvicorn-worker`, escutando só em 127.0.0.1:8000, e deixe o systemd manter o processo vivo. O Nginx fica na frente com HTTPS do Let's Encrypt, e o firewall libera apenas SSH, 80 e 443.

## Como a API fica montada na VPS

O FastAPI é um framework ASGI: ele define as rotas, mas quem abre a porta e fala HTTP é um servidor ASGI, o Uvicorn. Em produção, o Gunicorn entra como gerente de processos, subindo vários workers Uvicorn para usar todos os vCPUs e substituindo os que travam. Cada peça tem um papel claro:

| Peça | Função | Onde escuta |
| --- | --- | --- |
| Nginx | Recebe o tráfego, termina o HTTPS e repassa para a API | 80 e 443 públicas |
| Gunicorn | Gerencia os processos, recicla e reinicia workers | 127.0.0.1:8000 |
| Workers Uvicorn | Executam a aplicação FastAPI em modo assíncrono | Dentro do Gunicorn |
| systemd | Inicia no boot, reinicia se cair, guarda os logs | Nenhuma porta |
| PostgreSQL | Banco de dados, se a API usar | 5432 só no 127.0.0.1 |

A regra de ouro é a mesma de qualquer API: só o Nginx fica exposto. A porta 8000 nunca é aberta no firewall, e o processo Python roda com um usuário sem privilégios, que não consegue alterar o próprio código.

## Python e ambiente virtual

O Ubuntu 24.04 vem com Python 3.12, versão suportada pelo FastAPI atual. Falta o módulo de ambientes virtuais e o Git:

```
sudo apt update
sudo apt install -y python3-venv python3-pip git
python3 --version
```

O ambiente virtual não é opcional. Desde o Ubuntu 23.04, o `pip install` fora de um ambiente virtual é bloqueado com o erro `externally-managed-environment`, para proteger os pacotes Python do próprio sistema. E mesmo sem o bloqueio, isolar as dependências por projeto evita que atualizar uma biblioteca quebre outra aplicação. O guia de [Python e pip na VPS Ubuntu](https://streethosting.com.br/guias/vps/instalar-python-pip-vps-ubuntu) explica esse bloqueio e outras formas de instalar versões diferentes do Python.

Crie o usuário de sistema que vai rodar a API, a pasta do projeto e o ambiente virtual. O código pertence ao seu usuário; o serviço só lê. A pasta fica em `/opt` e não na sua pasta pessoal porque, no Ubuntu 24.04, as pastas pessoais são fechadas para outros usuários, e o usuário da API não conseguiria nem ler o código.

```
sudo useradd --system --home-dir /opt/minha-api --shell /usr/sbin/nologin api
sudo mkdir -p /opt/minha-api /etc/minha-api
sudo chown usuario:usuario /opt/minha-api

git clone https://github.com/sua-conta/minha-api.git /opt/minha-api/app
python3 -m venv /opt/minha-api/venv
/opt/minha-api/venv/bin/pip install --upgrade pip
/opt/minha-api/venv/bin/pip install -r /opt/minha-api/app/requirements.txt
/opt/minha-api/venv/bin/pip install gunicorn uvicorn-worker
```

Se o projeto ainda não tem um `requirements.txt`, o mínimo é `"fastapi[standard]"`, que já traz o Uvicorn com as dependências de desempenho. Fixe as versões no arquivo para que a VPS instale exatamente o que você testou.

## Gunicorn com workers Uvicorn

O Gunicorn sozinho fala WSGI, o padrão síncrono do Python. Para rodar FastAPI ele precisa de uma classe de worker ASGI. Durante anos essa classe veio dentro do Uvicorn, em `uvicorn.workers.UvicornWorker`, mas esse módulo foi marcado como obsoleto. O caminho atual é o pacote `uvicorn-worker`, mantido pela mesma equipe, que se importa como `uvicorn_worker`. Tutoriais antigos ainda mostram o caminho velho; troque ao encontrar.

Teste na mão antes de criar o serviço. O exemplo assume que o objeto `app` está em `app/main.py`; ajuste para o seu projeto:

```
cd /opt/minha-api/app
/opt/minha-api/venv/bin/gunicorn app.main:app \
  -k uvicorn_worker.UvicornWorker -w 2 -b 127.0.0.1:8000

# em outro terminal
curl -i http://127.0.0.1:8000/docs
```

Vale criar também uma rota simples de saúde, como `/health`, que responde 200 quando a aplicação está de pé e, se quiser, testa a conexão com o banco. Ela serve para conferir cada deploy com um curl e para qualquer monitoramento externo, sem depender da documentação, que você vai desligar em produção mais adiante.

### Quantos workers usar

A documentação do Gunicorn sugere dois workers por núcleo mais um, mas essa conta foi feita para workers síncronos, que atendem uma requisição por vez. Um worker Uvicorn atende muitas requisições ao mesmo tempo enquanto espera banco e rede, então um por vCPU costuma bastar. Cada worker é um processo separado, com a sua própria memória.

| vCPUs da VPS | Workers para começar | Observação |
| --- | --- | --- |
| 1 | 1 ou 2 | Dois só se a API passa a maior parte do tempo esperando banco |
| 2 | 2 | Ponto de partida da maioria das APIs |
| 4 | 4 | Meça a latência antes de subir mais |
| 6 ou mais | Um por vCPU | Deixe um vCPU livre se o banco roda na mesma VPS |

> **Atenção**
>
> Worker nenhum salva uma rota `async def` que chama código bloqueante, como a biblioteca requests ou um driver de banco síncrono. Isso trava o loop daquele worker inteiro enquanto a chamada dura. Use bibliotecas assíncronas ou declare a rota com `def` comum, que o FastAPI executa em uma thread separada.

Se preferir não usar Gunicorn, `uvicorn app.main:app --workers 2` e `fastapi run --workers 2` também sobem vários processos e reiniciam os que morrem. O que se perde é a recarga sem queda por sinal e a reciclagem automática de workers, que o Gunicorn faz bem.

## Serviço systemd com recarga sem queda

Senhas e configurações ficam em um arquivo de ambiente que só o root lê. O systemd carrega o arquivo antes de trocar para o usuário da API, e a aplicação lê as variáveis com `os.environ` ou com o pydantic settings.

```
sudo nano /etc/minha-api/minha-api.env

DATABASE_URL=postgresql://minha_api:troque-esta-senha@127.0.0.1:5432/minha_api
AMBIENTE=producao

sudo chmod 600 /etc/minha-api/minha-api.env
sudo nano /etc/systemd/system/minha-api.service

[Unit]
Description=API FastAPI minha-api
After=network-online.target postgresql.service
Wants=network-online.target

[Service]
User=api
Group=api
WorkingDirectory=/opt/minha-api/app
EnvironmentFile=/etc/minha-api/minha-api.env
ExecStart=/opt/minha-api/venv/bin/gunicorn app.main:app \
    -k uvicorn_worker.UvicornWorker -w 2 -b 127.0.0.1:8000 \
    --timeout 60 --graceful-timeout 30 \
    --max-requests 1000 --max-requests-jitter 100 \
    --access-logfile -
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
```

- **ExecReload com HUP:** o Gunicorn sobe workers novos com o código atualizado e encerra os antigos depois que terminam o que estavam fazendo. É a atualização sem derrubar conexões.
- **max requests com jitter:** recicla cada worker depois de cerca de mil requisições, com uma variação aleatória para não reiniciar todos juntos. Contém vazamentos de memória lentos de bibliotecas.
- **timeout:** um worker que para de responder por 60 segundos é encerrado e substituído.
- **access logfile com traço:** manda o log de acesso para a saída padrão, que o systemd grava no journal.

```
sudo systemctl daemon-reload
sudo systemctl enable --now minha-api
systemctl status minha-api
journalctl -u minha-api -f
```

### Onde a API pode gravar arquivos

Como o usuário `api` não escreve na pasta do código, uploads, arquivos temporários de processamento ou um banco SQLite precisam de um lugar próprio. O jeito mais limpo é pedir ao systemd: acrescente `StateDirectory=minha-api` na seção `[Service]`. Ele cria `/var/lib/minha-api` com o usuário da API como dono e publica o caminho na variável `STATE_DIRECTORY`, que a aplicação lê. Assim uma falha na API pode, no máximo, mexer nos dados dela, nunca no código que está rodando.

> **Dica**
>
> Evite a opção `--preload` se você depende do reload. Ela carrega a aplicação uma vez no processo principal para economizar memória, mas aí o HUP reinicia os workers com o código antigo, e só um restart completo aplica a versão nova.

## Nginx, domínio e HTTPS

Crie um registro A para o subdomínio da API apontando para o IP da VPS, como no guia de [apontar domínio para a VPS](https://streethosting.com.br/guias/vps/apontar-dominio-vps-registro-dns). O bloco do Nginx é o de proxy reverso com os cabeçalhos de origem e, se a API usa WebSocket, os de upgrade:

```
sudo apt install -y nginx
sudo nano /etc/nginx/sites-available/minha-api

server {
    listen 80;
    listen [::]:80;
    server_name api.seu-dominio.com.br;

    client_max_body_size 10m;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        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;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

sudo ln -s /etc/nginx/sites-available/minha-api /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d api.seu-dominio.com.br
```

O Uvicorn confia nos cabeçalhos Forwarded vindos de 127.0.0.1 por padrão, e o Gunicorn repassa essa mesma regra ao worker. Com o Nginx na mesma VPS, o IP real do cliente e o protocolo https chegam à aplicação sem configuração extra. Se um dia o proxy estiver em outra máquina, ajuste `--forwarded-allow-ips` com o IP dele, nunca com um curinga aberto. Regras de firewall e renovação do certificado estão nos guias de [firewall UFW](https://streethosting.com.br/guias/vps/firewall-ufw-vps-ubuntu) e de [certificado SSL com Nginx](https://streethosting.com.br/guias/vps/certificado-ssl-vps-lets-encrypt-nginx).

Se a API mantém conexões WebSocket, saiba que o Nginx encerra uma conexão que fica 60 segundos sem tráfego. Ou a aplicação envia um ping periódico, o que é a solução mais robusta, ou você aumenta o `proxy_read_timeout` nesse bloco para alguns minutos.

### Esconder a documentação em produção

O FastAPI publica por padrão a documentação interativa em `/docs` e `/redoc`, além do esquema em `/openapi.json`. É ótimo para quem consome a API, mas em uma API privada entrega o mapa completo de rotas e parâmetros a qualquer um. Controle isso pela mesma variável de ambiente do arquivo de configuração:

```
import os
from fastapi import FastAPI

publico = os.environ.get("AMBIENTE") != "producao"

app = FastAPI(
    docs_url="/docs" if publico else None,
    redoc_url="/redoc" if publico else None,
    openapi_url="/openapi.json" if publico else None,
)
```

## Atualizar a API e resolver erros comuns

Para publicar uma versão nova, atualize o código e as dependências e peça o reload. As migrações de banco, se você usa Alembic, rodam antes do reload, para que o código novo encontre o esquema certo:

```
cd /opt/minha-api/app
git pull origin main
/opt/minha-api/venv/bin/pip install -r requirements.txt
/opt/minha-api/venv/bin/alembic upgrade head
sudo systemctl reload minha-api
```

Marque cada versão publicada com uma tag no Git. Se a versão nova der problema, voltar é fazer checkout da tag anterior, reinstalar as dependências e pedir outro reload, em menos de um minuto. Só as migrações de banco não voltam sozinhas: escreva o downgrade de cada uma, ou faça migrações que o código antigo também tolere, como adicionar colunas antes de remover as velhas.

Se o banco ainda não existe, o guia de [PostgreSQL na VPS Ubuntu](https://streethosting.com.br/guias/vps/instalar-postgresql-vps-ubuntu) cria usuário e banco dedicados com acesso só local.

| Erro | Causa | Como resolver |
| --- | --- | --- |
| externally managed environment no pip | pip rodando fora do ambiente virtual | Use o pip de dentro da pasta venv |
| No module named uvicorn_worker | Pacote do worker não instalado no venv | Instale o pacote do worker com o pip do venv |
| Aviso de módulo obsoleto do Uvicorn | Serviço ainda usa uvicorn.workers | Troque a classe para uvicorn_worker.UvicornWorker |
| WORKER TIMEOUT no log | Rota travada ou código bloqueante em async def | Encontre a rota lenta e tire o bloqueio do loop |
| 502 Bad Gateway | Serviço parado ou porta diferente da do Nginx | Veja o journal e confira o bind em 127.0.0.1:8000 |
| IP do cliente sempre 127.0.0.1 | Cabeçalhos do proxy ausentes | Confira os cabeçalhos Forwarded no bloco do Nginx |
| ModuleNotFoundError: No module named app | WorkingDirectory errado ou caminho do módulo trocado | Confira a pasta da unidade e o caminho app.main:app |
| PermissionError ao gravar arquivo | Usuário da API sem escrita na pasta do código | Grave em StateDirectory, nunca na pasta do código |

## Qual VPS escolher para FastAPI

Python executa cada requisição em um único núcleo por worker, então o clock do processador define quanto tempo cada resposta leva. Por isso a [VPS Ryzen 9 9950X](https://streethosting.com.br/vps/ryzen), com até 5,7 GHz, memória DDR5 e NVMe, é a indicação principal para APIs FastAPI. O guia de [como escolher VPS para API](https://streethosting.com.br/guias/vps/escolher-vps-para-api) aprofunda o dimensionamento por requisições por segundo. Se a API faz processamento pesado de CPU, como gerar PDFs, redimensionar imagens ou rodar inferência, cada worker ocupado prende um vCPU inteiro. Nesse caso o número de vCPUs pesa tanto quanto o clock, e a linha Xeon entra como opção econômica.

| Cenário | Plano sugerido | Preço mensal |
| --- | --- | --- |
| API pequena, 1 ou 2 workers | Ryzen 1 vCPU, 2 GB DDR5, 20 GB NVMe | R$ 39,00 |
| API com PostgreSQL na mesma VPS | Ryzen 2 vCPU, 4 GB DDR5, 40 GB NVMe | R$ 64,00 |
| API com tráfego, banco e Redis | Ryzen 4 vCPU, 8 GB DDR5, 80 GB NVMe | R$ 114,00 |
| Mais workers com orçamento curto | Xeon 3 vCPU, 4 GB DDR4, 40 GB NVMe | R$ 40,00 |

Todos os planos de [VPS](https://streethosting.com.br/vps) ficam em São Paulo, com AntiDDoS incluso, acesso root e ativação em até 60 segundos. Quando a API crescer, o upgrade pelo painel cobra só a diferença proporcional e exige um reinício da VM; depois, aumente o número de workers na unidade systemd.

- [ ] Dependências em ambiente virtual com versões fixadas
- [ ] Gunicorn com uvicorn_worker.UvicornWorker
- [ ] API escutando só em 127.0.0.1:8000
- [ ] Serviço systemd com usuário próprio, ExecReload e Restart
- [ ] Senhas em arquivo de ambiente com permissão 600
- [ ] Nginx com cabeçalhos Forwarded e HTTPS pelo Certbot
- [ ] UFW liberando só SSH, 80 e 443

## Perguntas frequentes

### Preciso do Gunicorn ou posso rodar só o Uvicorn?

Os dois caminhos funcionam. O Uvicorn com a opção workers já sobe vários processos e reinicia os que morrem. O Gunicorn acrescenta recarga sem queda por sinal, reciclagem de workers depois de um número de requisições e encerramento de workers travados, por isso continua sendo a escolha mais comum em VPS.

### O que aconteceu com uvicorn.workers.UvicornWorker?

O módulo de workers dentro do Uvicorn foi marcado como obsoleto. A classe passou para um pacote próprio, instalado com pip e importado como uvicorn_worker. Na linha de comando do Gunicorn, basta trocar o caminho da classe para uvicorn_worker.UvicornWorker.

### Quantos workers usar na API FastAPI?

Comece com um worker por vCPU. Cada worker Uvicorn atende muitas requisições ao mesmo tempo, então a fórmula de dois por núcleo mais um, pensada para workers síncronos, costuma ser exagerada. Aumente só se a CPU sobrar e a latência subir sob carga.

### Como esconder a documentação /docs em produção?

Crie a aplicação com docs_url, redoc_url e openapi_url iguais a None, de preferência controlados por uma variável de ambiente. Assim o esquema da API deixa de ficar público, sem mudar nenhuma rota.

### Quanto de RAM uma API FastAPI precisa?

Cada worker é um processo com a sua própria cópia da aplicação. Uma API simples ocupa algumas dezenas de MB por worker, então 2 GB bastam para a API e um banco pequeno. Se a aplicação carrega modelos de machine learning ou grandes estruturas em memória, multiplique esse peso pelo número de workers.

## Guias relacionados

- [Como instalar Python e pip na VPS Ubuntu](https://streethosting.com.br/guias/vps/instalar-python-pip-vps-ubuntu.md)
- [Como instalar PostgreSQL na VPS Ubuntu com segurança](https://streethosting.com.br/guias/vps/instalar-postgresql-vps-ubuntu.md)
- [Como configurar o Nginx como reverse proxy na VPS](https://streethosting.com.br/guias/vps/configurar-nginx-reverse-proxy-vps.md)
- [Como escolher VPS para API: CPU, RAM e conexões](https://streethosting.com.br/guias/vps/escolher-vps-para-api.md)
- [Como hospedar aplicação Node.js em VPS no Brasil](https://streethosting.com.br/guias/vps/hospedar-api-nodejs-vps-brasil.md)

## Produtos citados

- https://streethosting.com.br/vps/ryzen
- https://streethosting.com.br/vps

## Dados estruturados

```json
[
  {
    "@context": "https://schema.org",
    "@type": [
      "Article",
      "TechArticle"
    ],
    "headline": "FastAPI em produção na VPS: Gunicorn, Uvicorn, systemd e HTTPS",
    "name": "Como hospedar API FastAPI na VPS com Gunicorn e Nginx",
    "abstract": "Uma API FastAPI pronta para produção em uma VPS Ubuntu 24.04: Python em ambiente virtual, Gunicorn gerenciando workers Uvicorn pelo pacote atual, serviço systemd com reload sem queda, Nginx com HTTPS e como dimensionar os workers.",
    "description": "Hospede uma API FastAPI na VPS Ubuntu: ambiente virtual, Gunicorn com workers Uvicorn, serviço systemd, Nginx com HTTPS e os erros mais comuns.",
    "datePublished": "2026-09-28",
    "dateModified": "2026-09-28",
    "author": {
      "@type": "Organization",
      "name": "Equipe StreetHosting"
    },
    "publisher": {
      "@type": "Organization",
      "name": "StreetHosting",
      "url": "https://streethosting.com.br"
    },
    "inLanguage": "pt-BR",
    "mainEntityOfPage": {
      "@type": "WebPage",
      "@id": "https://streethosting.com.br/guias/vps/hospedar-api-fastapi-vps"
    }
  },
  {
    "@context": "https://schema.org",
    "@type": "FAQPage",
    "mainEntity": [
      {
        "@type": "Question",
        "name": "Preciso do Gunicorn ou posso rodar só o Uvicorn?",
        "acceptedAnswer": {
          "@type": "Answer",
          "text": "Os dois caminhos funcionam. O Uvicorn com a opção workers já sobe vários processos e reinicia os que morrem. O Gunicorn acrescenta recarga sem queda por sinal, reciclagem de workers depois de um número de requisições e encerramento de workers travados, por isso continua sendo a escolha mais comum em VPS."
        }
      },
      {
        "@type": "Question",
        "name": "O que aconteceu com uvicorn.workers.UvicornWorker?",
        "acceptedAnswer": {
          "@type": "Answer",
          "text": "O módulo de workers dentro do Uvicorn foi marcado como obsoleto. A classe passou para um pacote próprio, instalado com pip e importado como uvicorn_worker. Na linha de comando do Gunicorn, basta trocar o caminho da classe para uvicorn_worker.UvicornWorker."
        }
      },
      {
        "@type": "Question",
        "name": "Quantos workers usar na API FastAPI?",
        "acceptedAnswer": {
          "@type": "Answer",
          "text": "Comece com um worker por vCPU. Cada worker Uvicorn atende muitas requisições ao mesmo tempo, então a fórmula de dois por núcleo mais um, pensada para workers síncronos, costuma ser exagerada. Aumente só se a CPU sobrar e a latência subir sob carga."
        }
      },
      {
        "@type": "Question",
        "name": "Como esconder a documentação /docs em produção?",
        "acceptedAnswer": {
          "@type": "Answer",
          "text": "Crie a aplicação com docs_url, redoc_url e openapi_url iguais a None, de preferência controlados por uma variável de ambiente. Assim o esquema da API deixa de ficar público, sem mudar nenhuma rota."
        }
      },
      {
        "@type": "Question",
        "name": "Quanto de RAM uma API FastAPI precisa?",
        "acceptedAnswer": {
          "@type": "Answer",
          "text": "Cada worker é um processo com a sua própria cópia da aplicação. Uma API simples ocupa algumas dezenas de MB por worker, então 2 GB bastam para a API e um banco pequeno. Se a aplicação carrega modelos de machine learning ou grandes estruturas em memória, multiplique esse peso pelo número de workers."
        }
      }
    ]
  }
]
```
