Posted in

Nginx + Gunicorn + Flask: configuração prática

Colocar uma aplicação Flask em produção não é sobre “fazer funcionar”
Colocar uma aplicação Flask em produção não é sobre “fazer funcionar”

Colocar uma aplicação Flask em produção não é sobre “fazer funcionar” — isso você já fez com o Gunicorn. O problema real começa depois: conexões simultâneas, clientes lentos, assets estáticos, TLS, e uma pilha que precisa aguentar carga sem colapsar.

É aqui que o Nginx entra — não como detalhe cosmético, mas como uma camada de controle entre a internet e o seu processo Python. Ele absorve o caos da rede (timeouts, retries, buffering, headers inconsistentes) e entrega para o Gunicorn algo previsível. Em troca, o Gunicorn pode focar no que importa: executar sua aplicação Flask com eficiência.

Pré-requisitos

Assumindo que:

  • sua app Flask já roda via Gunicorn (ex: gunicorn app:app)
  • você não quer reinventar roda com uWSGI
  • precisa colocar isso atrás de um proxy decente (Nginx)

Escolha: socket UNIX vs TCP

Recomendo: Unix socket

Menos overhead, mais rápido localmente.

Exemplo:

/run/gunicorn.sock

Se já está usando TCP (127.0.0.1:8000), funciona — só menos eficiente.Configuração do Nginx

Crie um server block:

/etc/nginx/sites-available/flask_app

Exemplo (usando socket UNIX)

server {
listen 80;
server_name seu-dominio.com; # limite de upload (ajuste se necessário)
client_max_body_size 20M; # arquivos estáticos
location /static/ {
alias /var/www/seu_projeto/static/;
expires 30d;
add_header Cache-Control "public, immutable";
} location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
}

Exemplo (usando TCP)

location / {
include proxy_params;
proxy_pass http://127.0.0.1:8000;
}

proxy_params (não ignore isso)

Arquivo padrão (geralmente já existe em /etc/nginx/proxy_params):

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;

Sem isso:

  • Flask não sabe IP real
  • problemas com URL generation (url_for)
  • logs inúteis

Ativar e testar

ln -s /etc/nginx/sites-available/flask_app /etc/nginx/sites-enabled
nginx -t
systemctl reload nginx

Se quebrar:

journalctl -u nginx -f

Permissões do socket (clássico bug)

Se usar Unix socket:

Gunicorn precisa:

--bind unix:/run/gunicorn.sock

E permissões corretas:

chown www-data:www-data /run/gunicorn.sock
chmod 660 /run/gunicorn.sock

Ou melhor: configure via systemd (recomendado).

systemd (evita dor de cabeça)

Exemplo básico:

/etc/systemd/system/gunicorn.service
[Unit]
Description=Gunicorn
After=network.target[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/seu_projeto
ExecStart=/usr/bin/gunicorn \
--workers 3 \
--bind unix:/run/gunicorn.sock \
app:app[Install]
WantedBy=multi-user.target

Ajustes que realmente importam

Workers do Gunicorn

workers = (2 x CPU) + 1

Mas:

  • I/O bound (API): pode subir mais
  • CPU bound: cuidado

Timeout

Se tiver tarefas lentas:

--timeout 120

Mas isso é gambiarra estrutural — ideal é async / fila.

Headers e buffering

Se tiver streaming ou SSE:

proxy_buffering off;

HTTPS (não deixe pra depois)

Use:

  • Let’s Encrypt (Certbot)
  • ou Cloudflare na frente

Onde as coisas quebram (na prática)

  • socket permission denied
  • nginx 502 (gunicorn morreu ou path errado)
  • static mal configurado (Flask servindo static → erro conceitual)
  • múltiplos workers sem session store (se usar login/session → Redis)

Pensando como sistema (não tutorial)

Você está montando um pipeline com três camadas:

network (nginx)

process manager (gunicorn)

app (flask)

Se algo degrada:

  • latência → nginx
  • throughput → gunicorn workers
  • lógica → flask

Não trate erro como “config errada” — geralmente é desbalanceamento entre camadas.

Inscrever-se
Notificar de
guest
0 Comentários
mais antigos
mais recentes
Feedbacks embutidos
Ver todos os comentários