Belajar Flask - WSGI Deployment: Gunicorn & uWSGI
Episode 22 of 27

Belajar Flask - WSGI Deployment: Gunicorn & uWSGI

Mendeploy aplikasi Flask ke produksi dengan Gunicorn dan uWSGI: memahami worker model, menjalankan server WSGI dengan benar, mengelola proses lewat systemd, dan menyusun Nginx reverse proxy lengkap dengan proxy headers dan serve static files.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Server development Flask (flask run) jelas-jelas bukan untuk produksi: ia single-threaded, tanpa manajemen worker, dan rawan overload. Episode 22 mendeploy aplikasi dengan benar: Gunicorn (dan uWSGI) sebagai server WSGI produksi, systemd untuk mengelola prosesnya, dan Nginx sebagai reverse proxy di depannya.

Setelah episode ini, aplikasi kalian siap melayani lalu lintas nyata: multi-worker, auto-restart, static files cepat, dan TLS dari episode 20.

Mengapa Flask Harus Di Bawah Server WSGI

flask run adalah server development yang: hanya satu proses, tanpa buffering yang baik, dan menampilkan debugger di produksi (berbahaya — episode 3). Server WSGI produksi seperti Gunicorn menyelesaikan ini dengan worker model:

100%

Master Gunicorn mengelola worker — tiap worker menjalankan instance aplikasi Flask. Beberapa worker = beberapa request diproses bersamaan.

Menjalankan Gunicorn

Install dan jalankan:

Install dan jalankan Gunicorn
pip install gunicorn
gunicorn --workers 3 --bind 127.0.0.1:8000 "app:create_app()"
  • --workers 3 — jumlah worker (aturan praktis: 2 × CPU cores + 1).
  • --bind 127.0.0.1:8000 — hanya di localhost; Nginx yang menerima lalu lintas publik.
  • "app:create_app()" — memanggil application factory (episode 9) — inilah alasan utama mengapa factory pattern penting.

Bersamaan dengan episode 20, Gunicorn dan Nginx tersusun end-to-end: browser → Nginx (TLS) → Gunicorn (WSGI) → Flask.

Worker Type: Sync vs Async

Gunicorn punya beberapa tipe worker. Untuk Flask (WSGI, sync), yang relevan:

WorkerCocok untukCatatan
sync (default)Aplikasi sync biasaSatu worker = satu request; butuh banyak worker untuk I/O lambat
gevent / eventletBanyak I/O (jaringan, DB lambat)Green thread — hemat resource untuk workload I/O-bound
gthreadI/O campuranThreads per worker — simpel dan stabil

Untuk mayoritas aplikasi Flask, sync dengan jumlah worker yang pas sudah cukup. Jika aplikasi banyak menunggu I/O (menghubungi API eksternal), pertimbangkan gthread atau gevent:

Gunicorn dengan gthread
gunicorn --worker-class gthread --threads 4 --workers 3 \
  --bind 127.0.0.1:8000 "app:create_app()"

Kita bandingkan tipe worker ini lebih dalam saat tuning performa di episode 24.

Warning

Jika memakai gevent/eventlet, perhatikan patching: library jaringan harus kompatibel dengan green threads. Dan jangan campur sync dengan aplikasi yang memakai konteks per-thread tanpa persiapan. Mulai dari sync yang paling bisa diprediksi, lalu ukur sebelum menambah kompleksitas.

systemd: Menjaga Aplikasi Tetap Hidup

systemd mengelola Gunicorn: memulai saat boot, restart saat crash, dan mencatat log. Buat unit file:

/etc/systemd/system/flask-app.service
[Unit]
Description=Flask App - Gunicorn
After=network.target
 
[Service]
User=www-data
Group=www-data
WorkingDirectory=/opt/flask-app
Environment="FLASK_ENV=production"
EnvironmentFile=/etc/flask-app.env
ExecStart=/opt/flask-app/.venv/bin/gunicorn \
    --workers 3 \
    --bind 127.0.0.1:8000 \
    --access-logfile - \
    --error-logfile - \
    "app:create_app()"
Restart=always
RestartSec=3
 
[Install]
WantedBy=multi-user.target

Aktifkan dan jalankan:

Aktifkan service systemd
sudo systemctl daemon-reload
sudo systemctl enable --now flask-app
systemctl status flask-app

Restart=always berarti Gunicorn dibangkitkan ulang otomatis jika crash. EnvironmentFile=/etc/flask-app.env memuat secret (episode 8) tanpa di-commit. Untuk deploy update, cukup restart: sudo systemctl restart flask-app.

Nginx Reverse Proxy Lengkap

Kita sempurnakan konfigurasi dari episode 20 dengan static files dan healthcheck:

/etc/nginx/sites-available/flask-app
server {
    listen 443 ssl http2;
    server_name flask.example.com;
 
    # TLS (episode 20)
    ssl_certificate     /etc/letsencrypt/live/flask.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/flask.example.com/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;
 
    # static files langsung dari Nginx - cepat, tanpa menyentuh Python
    location /static/ {
        alias /opt/flask-app/static/;
        expires 7d;
        add_header Cache-Control "public";
    }
 
    location / {
        proxy_pass http://127.0.0.1:8000;
        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_read_timeout 60s;
    }
}

Dua hal penting: location /static/ membuat Nginx melayani CSS/JS/gambar langsung dari disk — Python tidak terlibat sama sekali, jauh lebih cepat (episode 7). Dan healthcheck sederhana bisa ditambahkan lewat endpoint /healthz yang dipantau monitoring.

uWSGI: Alternatif Gunicorn

uWSGI adalah alternatif yang lebih tua dan lebih "berat":

Jalankan aplikasi dengan uWSGI
pip install uwsgi
uwsgi --http 127.0.0.1:8000 --module app:create_app() --master \
      --processes 4 --threads 2

Keunggulan uWSGI: konfigurasi sangat fleksibel dan performa tinggi untuk workload khusus. Kekurangannya: kompleksitas setup lebih tinggi dan binary native perlu dikompilasi. Untuk mayoritas proyek Flask, Gunicorn lebih mudah dan cukup — pilih uWSGI hanya jika kebutuhan spesifiknya terpenuhi (misal integrasi khusus, embedded config).

Verifikasi Deployment

Setelah semua tersusun, uji dari luar:

Verifikasi deployment
curl -I https://flask.example.com
curl https://flask.example.com/healthz
systemctl status flask-app

Periksa tiga hal: TLS berfungsi (200 + HTTPS), aplikasi merespons via Nginx, dan service systemd aktif. Jika aplikasi tidak muncul, lihat log: journalctl -u flask-app -f dan sudo tail -f /var/log/nginx/error.log.

Common Pitfalls Deployment

  • --bind 0.0.0.0 di Gunicorn tanpa Nginx: aplikasi terpapar langsung ke publik tanpa TLS/filter — selalu 127.0.0.1 + Nginx.
  • Lupa ProxyFix: IP client salah, url_for menghasilkan http:// (episode 20).
  • Worker terlalu sedikit/banyak: terlalu sedikit = lambat; terlalu banyak = boros memori. Mulai 2×CPU+1, lalu ukur.
  • Static files lewat Python: lambat — Nginx harus menangani /static/.
  • Deploy tanpa restart: Gunicorn tidak otomatis membaca kode baru — restart service setelah deploy.
  • Secret di unit file systemd: pakai EnvironmentFile yang tidak di-commit.

Penutup

Pada episode 22 ini, kalian telah mendeploy Flask ke produksi.

Inti yang harus dibawa pulang:

  • Gunicorn adalah server WSGI produksi: multi-worker, bind 127.0.0.1, panggil factory "app:create_app()".
  • Worker sync cukup untuk mayoritas; gthread/gevent untuk workload I/O-heavy.
  • systemd menjaga proses hidup (Restart=always) dan memuat env secret.
  • Nginx menangani TLS, static files, dan proxy dengan header yang benar.
  • Verifikasi dengan curl + log sebelum menyatakan produksi selesai.

Di episode 23 selanjutnya, kita otomatiskan seluruh alur: Docker & CI/CD — multi-stage image, docker-compose, healthcheck, dan pipeline GitHub Actions dari test sampai deploy. Sampai jumpa di episode 23!