← Назад к вопросам

Каким образом Django связан с Nginx и Gunicorn?

2.3 Middle🔥 151 комментариев
#DevOps и инфраструктура#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Django, Nginx и Gunicorn: Architecture и взаимодействие

Это классический стек для production Django приложений. Нужно понимать, как они работают вместе и зачем каждый нужен.

Архитектура: OSI Model

Client Browser                      Internet
       |
       | HTTP/HTTPS request
       ↓
  ┌─────────────────┐
  │     NGINX       │ ← Web server (reverse proxy)
  │ :80, :443       │   - Load balancing
  └────────┬────────┘   - SSL/TLS termination
           |            - Static files
           | TCP 8000
           ↓
  ┌──────────────────────────────────────────┐
  │     Gunicorn (WSGI Application Server)  │
  │                                          │
  │  Worker 1  Worker 2  Worker 3  Worker 4  │ ← Process pool
  │    |          |         |         |       │
  │    └──────────┼─────────┼─────────┘       │
  │               |         |                 │
  │         ┌─────┴─────────┴──┐              │
  │         |   Django App    |              │
  │         └──────────────────┘              │
  └──────────────────────────────────────────┘
           |
           | Database connection
           ↓
       PostgreSQL

Роль каждого компонента

1. NGINX: Web Server (Layer 7)

NGINX — это reverse proxy. Он:

Принимает HTTP запросы на портах 80 (HTTP) и 443 (HTTPS) ✅ Обрабатывает SSL/TLS — шифрует/дешифрует ✅ Раздаёт static файлы (CSS, JS, images) без Django ✅ Load balancing — распределяет запросы между Gunicorn workers ✅ Caching — может кешировать ответы ✅ Compression — gzip сжатие ответов ✅ URL routing — может route разные domains

Конфиг NGINX:

upstream django {
    # Balancing между 4 Gunicorn workers
    server 127.0.0.1:8000;
    server 127.0.0.1:8001;
    server 127.0.0.1:8002;
    server 127.0.0.1:8003;
}

server {
    listen 80;
    server_name example.com;
    
    # Редирект на HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com;
    
    ssl_certificate /etc/ssl/certs/cert.pem;
    ssl_certificate_key /etc/ssl/private/key.pem;
    
    # Static файлы (не идут в Django)
    location /static/ {
        alias /var/www/static/;
        expires 30d;
    }
    
    # Media файлы (uploaded users)
    location /media/ {
        alias /var/www/media/;
        expires 7d;
    }
    
    # Всё остальное -> Gunicorn
    location / {
        proxy_pass http://django;
        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;
        
        # Timeouts
        proxy_read_timeout 30s;
        proxy_connect_timeout 10s;
    }
}

2. Gunicorn: WSGI Application Server

Gunicorn (Green Unicorn) — это application server.

Запускает Django приложениеСоздаёт worker processes (обычно 4 = 2 * CPU cores) ✅ Слушает на localhost:8000 (не открыт в интернет!) ✅ WSGI совместимый (работает с Flask, Django, etc.) ✅ Graceful restart — рестарт без потери запросов ✅ Preload app — память разделяется между workers

Запуск Gunicorn:

# Simple
gunicorn myproject.wsgi:application --bind 0.0.0.0:8000 --workers 4

# Production
gunicorn myproject.wsgi:application \
  --bind 0.0.0.0:8000 \
  --workers 4 \
  --worker-class sync \
  --worker-connections 1000 \
  --max-requests 1000 \
  --max-requests-jitter 50 \
  --timeout 30 \
  --access-logfile /var/log/gunicorn/access.log \
  --error-logfile /var/log/gunicorn/error.log \
  --log-level info \
  --daemon

Systemd service:

[Unit]
Description=Gunicorn Django Application
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/app
ExecStart=/usr/bin/gunicorn \
    --workers 4 \
    --bind 127.0.0.1:8000 \
    --log-level info \
    myproject.wsgi:application

Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

3. Django: Web Framework

Django — это приложение, которое WSGI-compliant.

# myproject/wsgi.py
import os
from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')

application = get_wsgi_application()
# Это WSGI callable, которую вызывает Gunicorn

Что Django делает:

  • Обрабатывает HTTP запрос
  • Маршрутизирует (urls.py)
  • Вызывает view
  • Обращается к БД
  • Возвращает HTTP response

Поток запроса

Client Browser
    |
    | GET /api/users/1
    ↓
NGINX (0.0.0.0:443)
    | Проверка SSL: OK
    | Is static? NO
    | URL pattern: /api/users/1 → Django
    | Load balance: → Worker 2 on port 8000
    |
    ↓ TCP 127.0.0.1:8000
Gunicorn Worker 2
    |
    | Запуск WSGI приложение
    | Передача request → Django
    ↓
Django (application callable)
    |
    | URL routing: /api/users/1 → UserViewSet.retrieve
    | Обработка request
    | Query: SELECT * FROM users WHERE id=1
    |
    ↓ Database
PostgreSQL
    |
    | SELECT * FROM users WHERE id=1
    | Return: {"id": 1, "name": "Alice", ...}
    ↓
Django
    |
    | Serialization (UserSerializer)
    | Response: {"id": 1, "name": "Alice", "email": "alice@example.com"}
    ↓
Gunicorn Worker 2
    |
    | Return response to NGINX
    ↓
NGINX
    |
    | Gzip compression
    | Add headers (Cache-Control, ETag, etc.)
    | Return to client
    ↓
Client Browser
    |
    | Response: 200 OK
    | Body: {"id": 1, "name": "Alice", ...}

Важные детали

1. WSGI Protocol

WSGI (Web Server Gateway Interface) — это стандарт Python для web apps.

# WSGI callable должна принимать:
# - environ: dict с request info
# - start_response: callback для отправки headers

def simple_wsgi_app(environ, start_response):
    # environ['REQUEST_METHOD'] → 'GET'
    # environ['PATH_INFO'] → '/api/users'
    # environ['QUERY_STRING'] → 'page=1'
    
    response_headers = [
        ('Content-Type', 'application/json'),
        ('Content-Length', '13'),
    ]
    start_response('200 OK', response_headers)
    
    return [b'{"status": "ok"}']

Django предоставляет get_wsgi_application(), которая возвращает такой callable.

2. Process Pool Model

Gunicorn использует multi-process model:

GMaster Process (PID: 1000)
    |
    ├─ Worker 1 (PID: 1001) ← Обрабатывает 1 request в раз
    ├─ Worker 2 (PID: 1002) ← Обрабатывает 1 request в раз
    ├─ Worker 3 (PID: 1003) ← Обрабатывает 1 request в раз
    └─ Worker 4 (PID: 1004) ← Обрабатывает 1 request в раз

Если приходит 5 requests:
    Request 1 → Worker 1 (processing)
    Request 2 → Worker 2 (processing)
    Request 3 → Worker 3 (processing)
    Request 4 → Worker 4 (processing)
    Request 5 → Queue (waiting)

Почему multiple workers:

  • ✅ I/O blocking: если Worker 1 ждет БД, Worker 2 может обработать другой request
  • ✅ Throughput: 4 workers = ~4x requests/sec
  • ✅ Resilience: если 1 worker crash, остальные работают

3. Static Files

NGINX обрабатывает static файлы, не Django:

# Django settings.py
STATIC_ROOT = '/var/www/static/'
STATIC_URL = '/static/'

# Collect static
# python manage.py collectstatic
# NGINX config
location /static/ {
    alias /var/www/static/;  # Прямой доступ к файлам
    expires 30d;              # Кеш на 30 дней
}

Почему так:

  • ❌ Django (Python) медленнее для static файлов
  • ✅ NGINX делает это с 10x скоростью
  • ✅ Экономит процессы Django

4. Graceful Reload

# Restart без downtime
gunicorn reload

# Процесс:
# 1. Master process получает SIGHUP
# 2. Master создаёт new workers с new code
# 3. Old workers дорешают current requests
# 4. Old workers завершаются
# Result: Zero downtime!

5. Timeouts

# NGINX config
proxy_read_timeout 30s;     # Ждём 30s ответ от Django
proxy_connect_timeout 10s;  # Ждём 10s на подключение
# Gunicorn config
--timeout 30  # Worker умирает если не ответит за 30s

Если Worker зависнет:

  1. Gunicorn master убивает worker
  2. NGINX видит разорванное соединение
  3. NGINX перенаправляет request на другой worker

6. Load Balancing

upstream django {
    # Round-robin (по умолчанию)
    server 127.0.0.1:8000;
    server 127.0.0.1:8001;
    
    # Least connections (нагруженность)
    least_conn;
    server 127.0.0.1:8000;
    server 127.0.0.1:8001;
    
    # IP hash (sticky session)
    ip_hash;
    server 127.0.0.1:8000;
    server 127.0.0.1:8001;
}

Типичные проблемы и решения

Проблема 1: 502 Bad Gateway

NGINX говорит: не могу подключиться к Django

Причины:
- Gunicorn не запущен
- Gunicorn упал
- Порт неправильный

Решение:
sudo systemctl status gunicorn
sudo systemctl restart gunicorn

Проблема 2: Worker Timeout

Long-running request (>30s) kills worker

Причины:
- Медленный SQL query
- Тяжелая обработка данных

Решение:
- Оптимизировать query (добавить index)
- Использовать Celery для async tasks
- Увеличить timeout (аккуратно)

Проблема 3: Out of Memory

Workers растут в памяти со временем

Причины:
- Memory leak в коде
- Кеш растет

Решение:
настроить max-requests restart:
--max-requests 1000  # Restart worker после 1000 requests
--max-requests-jitter 50  # +random(0-50) to avoid spikes

Production Setup

# 1. NGINX
sudo systemctl start nginx
sudo systemctl enable nginx  # Auto-start

# 2. Gunicorn
sudo systemctl start gunicorn
sudo systemctl enable gunicorn  # Auto-start

# 3. Django
cd /app
python manage.py migrate          # Миграции БД
python manage.py collectstatic    # Static files

# 4. Check
ps aux | grep nginx              # NGINX процесс
ps aux | grep gunicorn           # Gunicorn процессы
curl http://127.0.0.1:8000/api/  # Django работает?

# 5. Monitor
tail -f /var/log/nginx/error.log
tail -f /var/log/gunicorn/error.log

Architecture Decisions

Почему 3-слойная архитектура?

NGINX (reverse proxy)
  ↓
Gunicorn (app server)
  ↓
Django (business logic)

Вместо:
Django directly (bad for production)
  ✗ No SSL termination
  ✗ Slow static files
  ✗ Can't load balance
  ✗ Single process (bottleneck)

Альтернативы

1. uWSGI вместо Gunicorn
   - Similar, но более heavy
   - Более features
   
2. Docker + containerization
   - Легче deploy
   - Isolation
   
3. Kubernetes
   - Auto-scaling
   - Load balancing at container level
   - Для enterprise

Резюме

NGINX + Gunicorn + Django — классическая production архитектура:

  • NGINX: Обрабатывает HTTP, SSL, static, load balancing
  • Gunicorn: Запускает multiple workers Django процессов
  • Django: Бизнес логика, DB обращения, API endpoints

Flow:

Client Browser
    ↓ HTTP request
NGINX (0.0.0.0:443)
    ↓ TCP 127.0.0.1:8000
Gunicorn Worker (load balanced)
    ↓
Django Application
    ↓
PostgreSQL Database

Key Concepts:

  • WSGI protocol — interface between web server и app
  • Multi-process model — throughput и resilience
  • Static files in NGINX — performance
  • Graceful reload — zero downtime updates
  • Timeouts — prevent hanging requests

Эта архитектура используется в тысячах Django проектов и proven в production.