Python WSGI

Python WSGI #

Aplikasi Python web (Django, Flask) tidak memiliki HTTP server production-ready bawaan. Mereka butuh WSGI server sebagai jembatan antara Nginx dan kode Python. Dua pilihan paling populer adalah Gunicorn dan uWSGI.

Browser → Nginx → Gunicorn/uWSGI → Django/Flask

Nginx menangani SSL, static files, gzip, dan koneksi klien. Gunicorn/uWSGI mengelola worker process Python yang memproses request.


Nginx dengan Gunicorn #

Gunicorn adalah WSGI server yang paling mudah dikonfigurasi — pilihan default untuk kebanyakan proyek Python:

# Jalankan Gunicorn
gunicorn myapp.wsgi:application \
    --workers 4 \
    --bind unix:/run/gunicorn/myapp.sock \
    --worker-class sync \
    --timeout 30 \
    --access-logfile /var/log/gunicorn/access.log \
    --error-logfile /var/log/gunicorn/error.log
upstream gunicorn_app {
    server unix:/run/gunicorn/myapp.sock;
    keepalive 16;
}

server {
    listen 443 ssl;
    http2 on;
    server_name myapp.com;

    ssl_certificate     /etc/letsencrypt/live/myapp.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/myapp.com/privkey.pem;

    # Static files Django: `python manage.py collectstatic` mengumpulkan ke sini
    location /static/ {
        alias /var/www/myapp/staticfiles/;
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    location /media/ {
        alias /var/www/myapp/media/;
        expires 30d;
        access_log off;
    }

    # Semua request ke Gunicorn
    location / {
        proxy_pass http://gunicorn_app;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        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_connect_timeout 5s;
        proxy_read_timeout 60s;
    }
}

server {
    listen 80;
    server_name myapp.com;
    return 301 https://$host$request_uri;
}

Django: Konfigurasi settings.py #

Django perlu dikonfigurasi untuk berjalan di balik proxy:

# settings.py

# Izinkan domain ini menerima request
ALLOWED_HOSTS = ['myapp.com', 'www.myapp.com']

# Baca IP asli dari header X-Forwarded-For
USE_X_FORWARDED_HOST = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

# Direktori untuk file statis setelah collectstatic
STATIC_ROOT = '/var/www/myapp/staticfiles/'
STATIC_URL = '/static/'

MEDIA_ROOT = '/var/www/myapp/media/'
MEDIA_URL = '/media/'
# Kumpulkan semua static file ke STATIC_ROOT
python manage.py collectstatic --noinput

Nginx dengan uWSGI #

uWSGI menawarkan lebih banyak opsi konfigurasi dan bisa menggunakan protokol uWSGI biner (lebih efisien dari HTTP untuk komunikasi internal):

# /etc/uwsgi/apps-available/myapp.ini
[uwsgi]
chdir = /var/www/myapp
module = myapp.wsgi:application
home = /var/www/myapp/venv

master = true
processes = 4
threads = 2

socket = /run/uwsgi/myapp.sock
chmod-socket = 660
vacuum = true    # Hapus socket saat shutdown

die-on-term = true
max-requests = 1000   # Restart worker setelah N request (cegah memory leak)
upstream uwsgi_app {
    server unix:/run/uwsgi/myapp.sock;
}

location / {
    # Gunakan protokol uwsgi (bukan http) untuk efisiensi lebih baik
    uwsgi_pass uwsgi_app;
    include uwsgi_params;

    uwsgi_read_timeout 60;
    uwsgi_connect_timeout 5;
}

Protokol uwsgi (bukan proxy_pass http://) adalah biner dan lebih efisien dari HTTP untuk komunikasi antara Nginx dan uWSGI di server yang sama.


ASGI: Django Channels dan FastAPI #

Untuk aplikasi async Python (Django Channels, FastAPI, Starlette), gunakan uvicorn sebagai ASGI server bukan Gunicorn WSGI:

# Jalankan uvicorn (contoh untuk FastAPI)
uvicorn main:app \
    --workers 4 \
    --uds /run/uvicorn/myapp.sock \
    --proxy-headers \
    --forwarded-allow-ips '*'
upstream asgi_app {
    server unix:/run/uvicorn/myapp.sock;
    keepalive 16;
}

server {
    location / {
        proxy_pass http://asgi_app;
        proxy_http_version 1.1;

        # Penting untuk ASGI dan WebSocket
        proxy_set_header Connection $http_connection;
        proxy_set_header Upgrade $http_upgrade;

        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;
    }
}

Jumlah Worker yang Tepat #

Pedoman umum untuk menentukan jumlah worker Gunicorn/uWSGI:

Worker sinkron (sync):
  Rumus: (2 × jumlah CPU core) + 1
  Server 4 core → 9 workers

Worker async (gevent/asyncio):
  Bisa jauh lebih banyak karena setiap worker menangani banyak request
  Server 4 core → 4 workers × 1000 coroutine = 4000 request konkuren

Untuk aplikasi yang banyak I/O waiting (query database, API call):
  Pertimbangkan worker async atau uWSGI dengan threads

Ringkasan #

  • Gunicorn untuk kesederhanaan, uWSGI untuk lebih banyak kontrol — keduanya berfungsi baik dengan Nginx.
  • Gunakan Unix socket untuk komunikasi Nginx ↔ Gunicorn/uWSGI di server yang sama — lebih cepat dari TCP loopback.
  • Django butuh ALLOWED_HOSTS dan SECURE_PROXY_SSL_HEADER dikonfigurasi dengan benar saat di balik Nginx.
  • Selalu jalankan collectstatic dan layani static files dari Nginx langsung — jangan lewatkan Python untuk request statis.
  • Untuk aplikasi async (FastAPI, Django Channels), gunakan uvicorn sebagai ASGI server, bukan Gunicorn WSGI.

← Sebelumnya: PHP-FPM   Berikutnya: WebSocket →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact