Implantar uma stack Flask PostgreSQL Nginx é o caminho padrão para levar uma aplicação Python web do seu laptop para um servidor de produção. Este guia percorre cada camada: um banco de dados PostgreSQL, Gunicorn como servidor de aplicação WSGI, systemd para manter o processo em execução e Nginx como proxy reverso voltado para a internet. Ao final, você terá uma configuração robusta e pronta para produção sobre a qual poderá construir.
Pré-requisitos
- Servidor Ubuntu 22.04 ou 24.04 (acesso root ou sudo)
- Um nome de domínio apontando para o IP do servidor (opcional para SSL depois)
- Familiaridade básica com linha de comando Linux e Python
- Uma aplicação Flask pronta para implantar (ou use o exemplo mínimo deste guia)
Instalando as Dependências do Sistema
Comece atualizando o índice de pacotes e instalando tudo de uma vez:
sudo apt update && sudo apt upgrade -y
sudo apt install -y python3 python3-pip python3-venv \
postgresql postgresql-contrib \
nginx curl
Verifique as instalações:
python3 --version # Python 3.10+
psql --version # psql 14+
nginx -v # nginx/1.22+
Configurando o PostgreSQL
Criar um Banco de Dados e Usuário
Mude para a conta de sistema postgres e abra o shell interativo:
sudo -u postgres psql
Dentro do psql, crie um usuário e banco de dados dedicados. Nunca use o superusuário padrão postgres para conexões da aplicação:
CREATE USER flaskapp WITH PASSWORD 'StrongPassw0rd!';
CREATE DATABASE flaskdb OWNER flaskapp;
GRANT ALL PRIVILEGES ON DATABASE flaskdb TO flaskapp;
\q
Testar a Conexão
Confirme a conectividade antes de conectar ao Flask:
psql -U flaskapp -h 127.0.0.1 -d flaskdb -c "\conninfo"
Você deve ver a confirmação de que a conexão foi bem-sucedida. Se falhar, verifique se o pg_hba.conf permite autenticação md5 ou scram-sha-256 para conexões locais:
sudo nano /etc/postgresql/14/main/pg_hba.conf
# Certifique-se de que esta linha existe:
# host all all 127.0.0.1/32 scram-sha-256
sudo systemctl restart postgresql
Implantando a Aplicação Flask
Estrutura do Projeto
Coloque sua aplicação em /srv/flaskapp. Usar /srv mantém as aplicações web separadas dos arquivos do sistema:
/srv/flaskapp/
├── venv/
├── app/
│ ├── __init__.py
│ └── models.py
├── wsgi.py
├── .env
└── requirements.txt
Criar o Ambiente Virtual
sudo mkdir -p /srv/flaskapp
sudo chown $USER:$USER /srv/flaskapp
cd /srv/flaskapp
python3 -m venv venv
source venv/bin/activate
Instalar Pacotes Python
pip install flask flask-sqlalchemy psycopg2-binary gunicorn python-dotenv
pip freeze > requirements.txt
Aplicação Flask Mínima
Crie app/__init__.py:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import os
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ["DATABASE_URL"]
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SECRET_KEY"] = os.environ["SECRET_KEY"]
db.init_app(app)
@app.route("/")
def index():
return "Flask + PostgreSQL + Nginx is running."
return app
Crie wsgi.py (o ponto de entrada que o Gunicorn chama):
from app import create_app
app = create_app()
if __name__ == "__main__":
app.run()
Variáveis de Ambiente
Armazene os segredos em /srv/flaskapp/.env. Nunca envie este arquivo para controle de versão:
DATABASE_URL=postgresql://flaskapp:StrongPassw0rd!@127.0.0.1:5432/flaskdb
SECRET_KEY=replace-with-a-long-random-string
FLASK_ENV=production
Restrinja as permissões imediatamente:
chmod 600 /srv/flaskapp/.env
Testar o Gunicorn Manualmente
Antes de configurar o systemd, verifique se o Gunicorn consegue iniciar sua aplicação:
source /srv/flaskapp/venv/bin/activate
cd /srv/flaskapp
gunicorn --workers 3 --bind 0.0.0.0:8000 wsgi:app
Acesse http://seu-ip-do-servidor:8000 — você deve ver a resposta do Flask. Se sim, pare o Gunicorn com Ctrl+C e avance para o systemd.
Serviço Gunicorn no systemd
Executar o Gunicorn sob o systemd oferece reinicializações automáticas em caso de falha, inicialização na partida e registro centralizado via journalctl.
Escolhendo a Quantidade de Workers
| RAM do Servidor | Workers Recomendados |
|---|---|
| 512 MB | 2 |
| 1 GB | 3 |
| 2 GB | 5 |
| 4 GB+ | 9 |
Uma fórmula comum: (2 × núcleos de CPU) + 1. Três workers é um padrão seguro para a maioria das instâncias de VPS pequenas.
Criar o Arquivo de Unidade de Serviço
sudo nano /etc/systemd/system/flaskapp.service
Cole o seguinte — ajuste caminhos e usuário conforme necessário:
[Unit]
Description=Gunicorn instance for Flask app
After=network.target postgresql.service
[Service]
User=www-data
Group=www-data
WorkingDirectory=/srv/flaskapp
EnvironmentFile=/srv/flaskapp/.env
ExecStart=/srv/flaskapp/venv/bin/gunicorn \
--workers 3 \
--bind unix:/run/flaskapp/gunicorn.sock \
--access-logfile /var/log/flaskapp/access.log \
--error-logfile /var/log/flaskapp/error.log \
wsgi:app
RuntimeDirectory=flaskapp
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
Campos-chave explicados:
EnvironmentFile— carrega os segredos do.envno ambiente do processoRuntimeDirectory— o systemd cria automaticamente/run/flaskapp/e limpa na paradaAfter=postgresql.service— garante que o banco de dados esteja ativo antes de iniciar a aplicação- socket
unix:— mais rápido do que TCP para comunicação local Nginx-Gunicorn
Crie o diretório de log e ajuste a propriedade:
sudo mkdir -p /var/log/flaskapp
sudo chown www-data:www-data /var/log/flaskapp
sudo chown -R www-data:www-data /srv/flaskapp
Habilite e inicie o serviço:
sudo systemctl daemon-reload
sudo systemctl enable flaskapp
sudo systemctl start flaskapp
sudo systemctl status flaskapp
Você deve ver Active: active (running). Verifique se o socket foi criado:
ls -la /run/flaskapp/gunicorn.sock
Configuração do Proxy Reverso Nginx
O Nginx fica na frente do Gunicorn, trata o tráfego HTTP/HTTPS de entrada e encaminha as requisições da aplicação para o socket Unix.
Criar a Configuração do Site
sudo nano /etc/nginx/sites-available/flaskapp
server {
listen 80;
server_name example.com www.example.com;
# Arquivos estáticos servidos diretamente pelo Nginx — sem sobrecarga do Gunicorn
location /static/ {
alias /srv/flaskapp/app/static/;
expires 30d;
add_header Cache-Control "public, immutable";
}
location / {
proxy_pass http://unix:/run/flaskapp/gunicorn.sock;
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;
# Evitar que clientes lentos prendam workers do Gunicorn
proxy_read_timeout 90;
proxy_connect_timeout 90;
}
}
Habilite o site e teste a configuração:
sudo ln -s /etc/nginx/sites-available/flaskapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Adicionar SSL com Certbot
Em produção, sempre encerre o TLS no Nginx. O Certbot automatiza a emissão e renovação de certificados:
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
O Certbot reescreve sua configuração Nginx com diretivas SSL e configura a renovação automática via timer do systemd.
Cenário do Mundo Real
Você tem uma aplicação SaaS em produção construída com Flask que processa pedidos de clientes armazenados no PostgreSQL. O tráfego atinge o pico ao meio-dia com ~200 usuários simultâneos. Sem o buffer do Nginx, clientes móveis lentos manteriam os workers do Gunicorn ocupados por mais de 30 segundos cada, causando timeouts de requisição. Com a configuração deste guia:
- O Nginx aceita a conexão imediatamente e faz buffer do cliente lento
- Encaminha o corpo completo da requisição para o Gunicorn em milissegundos
- O Gunicorn processa a requisição e escreve a resposta de volta para o Nginx
- O Nginx transmite a resposta para o cliente lento enquanto o Gunicorn já está livre para a próxima requisição
Seus três workers do Gunicorn agora podem atender muito mais do que três usuários simultâneos. Adicione mais workers ou mude para workers assíncronos gevent quando precisar de mais escalabilidade.
Armadilhas e Casos Especiais
Permissões do socket Unix: O usuário www-data do Nginx deve poder ler o socket do Gunicorn. Executar ambos como www-data (conforme mostrado acima) é a correção mais simples. Se executarem como usuários diferentes, adicione www-data ao grupo da aplicação e defina o socket como 660.
DATABASE_URL com caracteres especiais: Senhas contendo @, / ou % devem ser codificadas em percentual na URL. Alternativamente, use variáveis de ambiente individuais (PGUSER, PGPASSWORD, etc.) e construa a URL em Python.
python-dotenv ausente em produção: EnvironmentFile no systemd lê o .env diretamente — você não precisa de python-dotenv para o caminho do systemd. Você precisa se executar flask run localmente.
Padrão de fábrica de app vs. app no nível do módulo: O wsgi:app do Gunicorn espera um callable. Com o padrão de fábrica, exponha o app criado no nível do módulo em wsgi.py conforme mostrado acima. Não chame create_app() dentro de uma função sem expor o resultado.
max_connections do PostgreSQL: Cada worker do Gunicorn abre sua própria conexão com o banco de dados. Com 9 workers em 4 servidores você pode atingir o limite padrão de 100 conexões. Use PgBouncer como pooler de conexões na frente do PostgreSQL para implantações com muitos workers.
Solução de Problemas
502 Bad Gateway do Nginx:
Verifique se o serviço Gunicorn está em execução e se o socket existe:
sudo systemctl status flaskapp
ls /run/flaskapp/gunicorn.sock
Verifique também os logs de erro do Nginx: sudo tail -50 /var/log/nginx/error.log
[CRITICAL] WORKER TIMEOUT nos logs do Gunicorn:
Uma requisição está demorando mais do que o timeout padrão de 30 segundos. Aumente com --timeout 120 ou otimize a consulta lenta que o está causando.
OperationalError: could not connect to server:
O PostgreSQL não está em execução ou o DATABASE_URL está errado. Teste a string de conexão diretamente com psql $DATABASE_URL.
Permission denied no socket:
Incompatibilidade de usuário entre Nginx e Gunicorn. Verifique se ambos executam como www-data:
ps aux | grep -E "gunicorn|nginx" | awk '{print $1, $11}'
Arquivos estáticos retornando 404:
O caminho alias no Nginx deve corresponder ao seu diretório estático real. Nota: alias requer uma barra no final; root não.
Resumo
- Instale o PostgreSQL, crie um usuário e banco de dados dedicados e restrinja as permissões do arquivo
.envpara manter as credenciais seguras - Execute o Flask sob o Gunicorn com um socket Unix — nunca exponha o Gunicorn diretamente à internet
- Use uma unidade
[Service]do systemd comEnvironmentFileeRuntimeDirectorypara gerenciamento limpo de processos e reinicialização automática - Configure o Nginx para fazer proxy de
/para o socket do Gunicorn e servir/static/diretamente para eliminar a carga desnecessária no servidor de aplicação - Adicione SSL via Certbot imediatamente — HTTP simples nunca é aceitável em produção
- Fique atento ao esgotamento do pool de conexões com o PostgreSQL ao escalar workers do Gunicorn; use PgBouncer se necessário