Python WSGI/ASGI #
Sama halnya dengan ekosistem PHP, runtime Python tidak dirancang untuk menangani ribuan koneksi HTTP secara simultan secara langsung dari internet. Untuk menyajikan aplikasi web Python (seperti Django, Flask, FastAPI, atau Starlette) pada lingkungan produksi skala besar, kita menempatkan Nginx di garda terdepan sebagai reverse proxy. Nginx bertindak sebagai penanggung jawab pengamanan SSL/TLS termination, penyajian berkas statis, dan buffer request, sementara eksekusi kode Python didelegasikan ke server aplikasi (application server) perantara.
Dalam ekosistem Python, komunikasi antara server web (Nginx) dan aplikasi web dijembatani oleh dua standar antarmuka: WSGI (Web Server Gateway Interface) untuk aplikasi sinkron tradisional, dan ASGI (Asynchronous Server Gateway Interface) untuk aplikasi asinkron modern. Di artikel ini, kita akan membedah perbedaan WSGI vs ASGI, membandingkan uWSGI vs Gunicorn, mengonfigurasi ASGI dengan Uvicorn, mengoptimalkan penyajian berkas statis Django/FastAPI, serta menyusun konfigurasi siap pakai tingkat produksi.
Arsitektur Integrasi Python Web Server #
Nginx bertindak sebagai filter terdepan. Jika request klien berupa file statik (seperti berkas gambar atau file CSS/JS hasil kompilasi), Nginx langsung menyajikannya dari folder penyimpanan lokal. Jika request berupa halaman dinamis atau API, Nginx meneruskannya ke server aplikasi (Gunicorn/uWSGI/Uvicorn) yang menjalankan kode Python kita.
Berikut adalah diagram alur pemrosesan request Python di server:
flowchart TD
Klien["Klien Browser"] -->|"HTTPS (Port 443)"| Nginx["Nginx Web Server"]
Nginx -->|"1. Request File Statik"| Static{"Aset Statik / Media?"}
Static -->|"Ya"| StaticDir["Sajikan Langsung dari Folder /static/ atau /media/"]
Static -->|"Tidak (Permintaan Dinamis)"| ProtoCheck{"Jenis Protokol Backend?"}
ProtoCheck -->|"WSGI (Synchronous - Django/Flask)"| WSGIApp["uWSGI / Gunicorn Server"]
ProtoCheck -->|"ASGI (Asynchronous - FastAPI)"| ASGIApp["Uvicorn / Hypercorn Server"]
WSGIApp -->|"WSGI Interface"| Django["Aplikasi Django / Flask"]
ASGIApp -->|"ASGI Interface"| FastAPI["Aplikasi FastAPI / Starlette"]
Django --> Nginx
FastAPI --> Nginx
Nginx -->|"Kembalikan HTTP Response"| Klien
classDef default fill:#f9f9f9,stroke:#d1d5db,stroke-width:1px,color:#111827;
classDef nginxStyle fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e3a8a;
classDef pythonStyle fill:#fef3c7,stroke:#d97706,stroke-width:2px,color:#78350f;
class Nginx,StaticDir nginxStyle;
class WSGIApp,ASGIApp,Django,FastAPI pythonStyle;
Memahami WSGI vs ASGI pada Ekosistem Python #
Sebelum menyusun konfigurasi Nginx, kita harus mengenali jenis protokol yang didukung oleh framework aplikasi Python kita:
1. WSGI (Web Server Gateway Interface) #
WSGI adalah standar lama (sejak 2003) yang dirancang untuk aplikasi sinkron (synchronous).
- Cara Kerja: Setiap request klien akan dilayani oleh satu proses/utas worker Python secara eksklusif. Worker akan tertahan (blocked) ketika menunggu operasi I/O (seperti query database atau pemanggilan API eksternal).
- Framework: Django (default), Flask, Bottle.
- Server Aplikasi: Gunicorn atau uWSGI.
2. ASGI (Asynchronous Server Gateway Interface) #
ASGI adalah evolusi dari WSGI yang dirancang untuk mendukung fitur asinkron (asynchronous), WebSocket, dan koneksi persisten berumur panjang secara native.
- Cara Kerja: Menggunakan model non-blocking event loop (mirip seperti Node.js). Satu proses worker dapat menangani ribuan request secara bersamaan tanpa terhambat oleh operasi I/O yang lambat.
- Framework: FastAPI, Sanic, Starlette, Django Channels.
- Server Aplikasi: Uvicorn, Hypercorn, atau Daphne.
uWSGI Native Protocol vs Gunicorn HTTP Proxy #
Pada aplikasi WSGI, kita bisa menghubungkan Nginx ke server aplikasi menggunakan protokol HTTP biasa (Gunicorn) atau menggunakan protokol biner native uWSGI (uWSGI Server).
1. uWSGI Native Protocol (uwsgi_pass)
#
uWSGI menggunakan protokol biner khusus bernama uwsgi yang memiliki overhead header lebih kecil daripada HTTP standar, sehingga sedikit lebih cepat dan efisien.
- Snippet Konfigurasi Nginx:
location / { include uwsgi_params; # Memuat parameter standar uwsgi uwsgi_pass unix:/run/uwsgi/myapp.sock; # Teruskan ke unix socket uWSGI }
2. Gunicorn HTTP Proxy (proxy_pass)
#
Gunicorn bertindak sebagai server HTTP mandiri lokal. Nginx berkomunikasi dengan Gunicorn menggunakan modul reverse proxy HTTP standar. Ini adalah pilihan yang paling populer karena konfigurasinya sangat mudah dipahami dan didebug.
- Snippet Konfigurasi Nginx:
location / { proxy_pass http://unix:/run/gunicorn/myapp.sock; # Teruskan ke unix socket Gunicorn # Atau jika menggunakan TCP port: # proxy_pass http://127.0.0.1:8000; }
Meneruskan Konteks Keamanan SSL ke Aplikasi Python #
Salah satu kendala paling umum saat menaruh aplikasi Python di belakang SSL Termination Nginx adalah aplikasi Python tidak menyadari bahwa koneksi klien luar aman (HTTPS). Jika Django atau FastAPI mencoba menghasilkan URL absolut (seperti pengalihan halaman setelah login), mereka akan menghasilkan URL http:// bukan https://. Hal ini memicu masalah Mixed Content Error di browser klien atau kegagalan CSRF Token Validation.
Kita wajib mengirimkan header X-Forwarded-Proto dari Nginx, lalu mengonfigurasi framework Python kita agar mematuhi header tersebut.
1. Konfigurasi di Nginx #
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;
# Beritahu backend bahwa klien menggunakan HTTPS di luar
proxy_set_header X-Forwarded-Proto $scheme;
}
2. Konfigurasi di Sisi Django (settings.py)
#
Tambahkan baris berikut di berkas konfigurasi Django agar ia bersedia mempercayai header dari Nginx:
# Beritahu Django untuk membaca header X-Forwarded-Proto
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# Pengerasan keamanan HTTPS tambahan
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
3. Konfigurasi di Sisi FastAPI #
FastAPI / Starlette menyediakan middleware bawaan untuk menangani skenario proxy HTTPS ini secara otomatis:
from fastapi import FastAPI
from starlette.middleware.trustedhost import TrustedHostMiddleware
from starlette.middleware.httpsredirect import HTTPSRedirectMiddleware
app = FastAPI()
# Jika kita ingin memaksa seluruh request FastAPI redirect ke HTTPS di tingkat python
# app.add_middleware(HTTPSRedirectMiddleware)
Offloading Static Files Django (collectstatic) #
Django memisahkan file kode Python dengan file aset statik (gambar admin panel, file JS/CSS admin). Di lingkungan produksi, kita menjalankan perintah Python berikut untuk mengumpulkan seluruh file statik dari berbagai modul aplikasi ke satu direktori terpusat:
python manage.py collectstatic
Setelah file terkumpul di satu folder (misalnya /var/www/myproject/static/), kita mengonfigurasi Nginx agar menyajikan folder tersebut secara langsung tanpa pernah melibatkan Gunicorn/Django.
server {
listen 80;
server_name app.unisbadri.com;
# 1. Lokasi Aset Statik Terpusat (Django collectstatic)
location /static/ {
alias /var/www/myproject/static/;
expires 30d;
add_header Cache-Control "public, no-transform";
access_log off;
}
# 2. Lokasi Unggahan File Pengguna (Django Media Files)
location /media/ {
alias /var/www/myproject/media/;
expires 30d;
add_header Cache-Control "public, no-transform";
access_log off;
}
# 3. Lokasi Request Dinamis
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;
}
}
Contoh Konfigurasi Server Block Produksi Lengkap #
1. Template Produksi Django + Gunicorn (HTTPS) #
upstream django_app_server {
# Gunakan Unix Domain Socket untuk performa lokal yang optimal
server unix:/var/run/gunicorn.sock fail_timeout=0;
}
server {
listen 80;
server_name django.unisbadri.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name django.unisbadri.com;
ssl_certificate /etc/letsencrypt/live/django.unisbadri.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/django.unisbadri.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# Limitasi ukuran file upload global
client_max_body_size 20m;
# Offload Django collectstatic
location /static/ {
alias /var/www/django-project/static/;
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# Offload Django User Uploaded Files
location /media/ {
alias /var/www/django-project/media/;
expires 30d;
add_header Cache-Control "public, no-transform";
access_log off;
}
# Routing Utama Gunicorn Reverse Proxy
location / {
# Cek ketersediaan file statis terlebih dahulu (opsional)
try_files $uri @proxy_to_app;
}
location @proxy_to_app {
proxy_pass http://django_app_server;
# Konfigurasi standard header
proxy_set_header Host $http_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;
# Penyetelan buffer dan timeouts proxy
proxy_redirect off;
proxy_read_timeout 90s;
proxy_connect_timeout 90s;
# Sembunyikan informasi teknologi
proxy_hide_header X-Powered-By;
}
}
2. Template Produksi FastAPI + Uvicorn (HTTPS + WebSocket) #
Aplikasi ASGI seperti FastAPI sering kali menangani lalu lintas real-time (WebSocket). Berikut adalah konfigurasi Nginx yang dirancang untuk mendukung reverse proxy HTTP sekaligus WebSocket tunnel secara dinamis:
# Map Connection header berdasarkan Upgrade header klien
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream fastapi_asgi_server {
# Uvicorn berjalan di port 8000
server 127.0.0.1:8000 max_fails=3 fail_timeout=10s;
keepalive 32;
}
server {
listen 80;
server_name api.unisbadri.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name api.unisbadri.com;
ssl_certificate /etc/letsencrypt/live/api.unisbadri.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.unisbadri.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# Offload Static Files (jika FastAPI menyajikan berkas frontend static)
location /static/ {
alias /var/www/fastapi-project/static/;
expires 30d;
access_log off;
}
# Proxying HTTP & WebSockets ke Uvicorn
location / {
proxy_pass http://fastapi_asgi_server;
# Aktifkan HTTP/1.1 untuk Keepalive dan WebSockets
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# Standard proxy headers
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;
# Cegah socket timeout terputus di tengah jalan untuk WebSockets
proxy_read_timeout 86400s; # Setel 24 jam (atau gunakan keepalive ping)
proxy_send_timeout 86400s;
}
}
Tuning Gunicorn & Uvicorn Worker Class di Produksi #
Saat menjalankan aplikasi Django (WSGI) atau FastAPI (ASGI) di belakang Nginx, performa dan daya tampung request sangat dipengaruhi oleh jumlah dan jenis worker yang kita gunakan di server aplikasi.
1. Menentukan Jumlah Worker Gunicorn / Uvicorn #
Secara umum, rumus baku untuk menentukan jumlah worker proses di server aplikasi Python agar CPU dapat dimanfaatkan secara optimal tanpa overhead context switching adalah: [\text{Jumlah Worker} = (2 \times \text{Jumlah Core CPU}) + 1]
Sebagai contoh, jika VPS kita memiliki 2 Core CPU: [\text{Jumlah Worker} = (2 \times 2) + 1 = 5 \text{ worker}]
Kita menjalankan Gunicorn dengan sintaksis berikut:
gunicorn --workers 5 --bind unix:/run/gunicorn/myapp.sock myproject.wsgi:application
2. Memilih Tipe Worker Class (Gunicorn/Uvicorn) #
Gunicorn mendukung berbagai tipe worker class yang disesuaikan dengan beban aplikasi kita:
sync(Default): Worker sinkron sederhana. Sangat cocok untuk aplikasi CPU-bound (perhitungan berat) yang tidak memiliki banyak I/O call eksternal. Setiap worker hanya melayani satu koneksi dalam satu waktu.geventataueventlet: Worker berbasis greenlet (coroutine). Sangat optimal untuk aplikasi I/O-bound (banyak query database lambat atau fetch HTTP API luar) karena dapat menangguhkan eksekusi utas saat menunggu data tanpa memblokir CPU.eggry/tornado: Worker asinkron alternatif.uvicorn.workers.UvicornWorker: Worker class khusus untuk menjalankan aplikasi ASGI (FastAPI) di dalam wrapper Gunicorn. Ini menggabungkan kemampuan manajemen proses Gunicorn (auto-restart, cluster management) dengan performa event loop asinkron Uvicorn yang sangat cepat berbasis uvloop.
# Menjalankan FastAPI dengan management process Gunicorn di belakang Nginx
gunicorn myfastapiapp.main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 127.0.0.1:8000
Dengan mengintegrasikan Nginx dengan Gunicorn yang menggunakan UvicornWorker, kita mendapatkan ketahanan server tingkat tinggi karena Gunicorn akan memantau kesehatan worker Uvicorn dan otomatis me-restart worker jika terdeteksi mati atau mengalami kebocoran memori.
Penyelesaian Masalah (Troubleshooting) Kasus Produksi #
Berikut adalah beberapa isu yang paling sering ditemui saat mengawinkan Nginx dengan Python backend di produksi:
- Galat
502 Bad Gatewaypada Unix Socket:- Penyebab: Nginx tidak memiliki izin (permissions) untuk membaca berkas socket
/var/run/gunicorn.sockkarena berkas dibuat oleh Gunicorn yang berjalan sebagai userrootataupython, sementara Nginx berjalan sebagaiwww-data. - Solusi: Jalankan Gunicorn dengan flag
--umask 007atau setel hak akses socket secara manualchmod 660 /var/run/gunicorn.sockagar groupwww-datamemiliki akses tulis-baca.
- Penyebab: Nginx tidak memiliki izin (permissions) untuk membaca berkas socket
- CSS Admin Panel Django Tidak Muncul (404):
- Penyebab: Kita lupa menjalankan perintah
collectstaticdi Django, atau direktorialiaspada location block/static/Nginx salah menunjuk ke folder lokal. - Solusi: Jalankan
python manage.py collectstatic, pastikan path folder di konfigurasi Nginx berakhiran slash/yang sama dengan alias target (misalalias /path/to/static/;).
- Penyebab: Kita lupa menjalankan perintah
- Perulangan Redirect Tak Terbatas (Infinite Redirect Loop):
- Penyebab: Django disetel untuk memaksa HTTPS (
SECURE_SSL_REDIRECT = True), namun Nginx memanggil Gunicorn lewat HTTP lokal tanpa menyertakan headerproxy_set_header X-Forwarded-Proto $scheme;. Django mengira request masih berupa HTTP biasa, lalu membalas dengan perintah redirect ke HTTPS secara terus-menerus. - Solusi: Tambahkan direktif header
X-Forwarded-Protodi Nginx dan pastikanSECURE_PROXY_SSL_HEADERtelah dideklarasikan disettings.pyDjango.
- Penyebab: Django disetel untuk memaksa HTTPS (
Ringkasan dan Praktik Terbaik #
- Wajib Setel SECURE_PROXY_SSL_HEADER: Jangan pernah melewatkan konfigurasi ini di Django settings jika server kita berada di belakang SSL Termination Nginx untuk mencegah masalah otentikasi CSRF.
- Lakukan Offload Aset Statik: Pastikan asset statik Django (
/static/dan/media/) dilayani langsung oleh Nginx. Hal ini memotong waktu respons server hingga 4x lipat.- Pilih Gunicorn untuk Kecepatan Rilis: Jika tim pengembang kita kurang familiar dengan penalaan parameter uWSGI yang rumit, gunakan Gunicorn HTTP proxy yang lebih ramah digunakan dan stabil.
- Gunakan HTTP/1.1 untuk Uvicorn: Uvicorn (FastAPI) membutuhkan protokol HTTP/1.1 agar WebSocket Upgrade handshake dan pemetaan koneksi asinkron dapat berjalan mulus.
← Sebelumnya: PHP-FPM (Laravel/WordPress) Berikutnya: Single Page Application (React/Vue) →