Развертывание Django на сервере: Docker, Nginx, Gunicorn | Руководство | AdminWiki

Развертывание Django: Полное руководство от настройки до production

17 декабря 2025 9 мин. чтения #Deployment #Django #Gunicorn #Web Development #devops #docker #nginx #python

Представь, что ты создал отличное Django-приложение. Оно работает локально, все тесты проходят. Но как превратить его в работающий веб-сервис, доступный из любой точки мира? Давай разберем процесс развертывания Django от начала до конца — от выбора сервера до базовой конфигурации, которую нужно проверить перед production.

Подготовка к развертыванию Django на сервере

Перед тем как начать развертывание Django на сервере, нужно понять архитектуру production-окружения. Типичная схема включает:

  • WSGI-сервер (Gunicorn или uWSGI) — запускает твое Django-приложение
  • Веб-сервер (Nginx или Apache) — обрабатывает статические файлы и проксирует запросы
  • База данных (PostgreSQL, MySQL) — production-ready СУБД
  • Кэширование (Redis, Memcached) — для повышения производительности
Важно: Никогда не используй встроенный сервер Django (runserver) в production! Он не предназначен для этого и небезопасен.

Настройка Django для production

Первым делом подготовим settings.py. Создадим разделение на локальные и production-настройки:

python
# settings/base.py
import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent.parent

SECRET_KEY = os.environ['DJANGO_SECRET_KEY']

DEBUG = False

ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com']

# Database
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ.get('DB_NAME'),
        'USER': os.environ.get('DB_USER'),
        'PASSWORD': os.environ.get('DB_PASSWORD'),
        'HOST': os.environ.get('DB_HOST', 'localhost'),
        'PORT': os.environ.get('DB_PORT', '5432'),
    }
}

# Static files
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_DIRS = [BASE_DIR / 'static']

MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'

Классическое развертывание: Gunicorn + Nginx

Шаг 1: Подготовка сервера

Для примера возьмём Ubuntu 24.04 LTS и совместимые версии Django/Python. При выборе VPS можно сравнить Timeweb Cloud (партнёрская ссылка) с другими провайдерами по ресурсам, цене и бэкапам. Перед изменениями проверь SSH и консоль восстановления. Все yourproject/yourdomain ниже замени реальными именами; выбери классический или Docker-сценарий, не запускай оба на одних портах.

bash
ssh user@your_server_ip
sudo apt update && sudo apt upgrade -y
sudo apt install python3-pip python3-venv nginx postgresql postgresql-contrib git libpq-dev python3-dev build-essential

Шаг 2: Настройка PostgreSQL

bash
sudo -u postgres psql

В открытой psql-консоли создай роль и базу с владельцем; пароль введи интерактивно через \password:

CREATE ROLE youruser LOGIN;
\password youruser
CREATE DATABASE yourdbname OWNER youruser;
\q

Шаг 3: Развертывание приложения

Клонируем проект от пользователя развёртывания. Создай /etc/yourproject.env (root:root,600) с DJANGO_SECRET_KEY (уникальный случайный секрет), DB_NAME=yourdbname, DB_USER=youruser, DB_PASSWORD, DB_HOST=127.0.0.1 и DJANGO_SETTINGS_MODULE=yourproject.settings.base. Файл имеет формат KEY=value, без shell-команд; секреты не коммить. Проверь requirements.txt: нужны Gunicorn и совместимый PostgreSQL-драйвер. Пример ниже предполагает, что manage.py лежит в /var/www/yourproject, а пакет настроек — yourproject/settings/base.py.

bash
sudo install -d -o "$USER" -g www-data -m 0755 /var/www/yourproject
cd /var/www/yourproject
git clone https://github.com/yourusername/yourproject.git .
python3 -m venv venv
venv/bin/pip install -r requirements.txt
# Секретный env загружается systemd, не исполняется shell:
sudo systemd-run --wait --pipe --collect -p WorkingDirectory=/var/www/yourproject -p EnvironmentFile=/etc/yourproject.env /var/www/yourproject/venv/bin/python manage.py check --deploy
sudo systemd-run --wait --pipe --collect -p WorkingDirectory=/var/www/yourproject -p EnvironmentFile=/etc/yourproject.env /var/www/yourproject/venv/bin/python manage.py migrate
sudo systemd-run --wait --pipe --collect -p WorkingDirectory=/var/www/yourproject -p EnvironmentFile=/etc/yourproject.env /var/www/yourproject/venv/bin/python manage.py collectstatic --noinput
sudo systemd-run --wait --pty --collect -p WorkingDirectory=/var/www/yourproject -p EnvironmentFile=/etc/yourproject.env /var/www/yourproject/venv/bin/python manage.py createsuperuser
sudo install -d -o www-data -g www-data -m 0750 /var/www/yourproject/media
# Код и статика доступны www-data на чтение; запись только в media.
sudo chgrp -R www-data /var/www/yourproject
sudo chmod -R g+rX /var/www/yourproject

Шаг 4: Настройка Gunicorn

Сохрани следующий unit как /etc/systemd/system/gunicorn.service для автоматического запуска:

config
[Unit]
Description=Gunicorn for Django
After=network.target postgresql.service

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/yourproject
EnvironmentFile=/etc/yourproject.env
RuntimeDirectory=gunicorn
RuntimeDirectoryMode=0750
UMask=0007
ExecStart=/var/www/yourproject/venv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn/gunicorn.sock yourproject.wsgi:application
Restart=on-failure

[Install]
WantedBy=multi-user.target
bash
sudo systemctl daemon-reload
sudo systemctl start gunicorn
sudo systemctl enable gunicorn
sudo systemctl status gunicorn  # Проверяем статус

Шаг 5: Настройка Nginx

config
server {
    listen 80;
    listen [::]:80;
    server_name yourdomain.com www.yourdomain.com;
    location /static/ { alias /var/www/yourproject/staticfiles/; }
    location /media/ { alias /var/www/yourproject/media/; }
    location / {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn/gunicorn.sock;
    }
}
bash
sudo ln -s /etc/nginx/sites-available/yourproject /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Важно: Сначала разреши фактический SSH-порт в UFW и firewall провайдера, проверь второй SSH-сеанс и подготовь откат через консоль. Только затем разрешай80/443 и включай firewall. До ввода учётных данных настрой HTTPS по FAQ и проверь редирект; не используй административный вход по HTTP.

Развертывание web приложения Django с помощью Docker

Docker упрощает процесс развертывания web приложения Django, обеспечивая консистентность окружения. Ниже базовый Compose-стек за локальным HTTP-портом8080. До внешнего production-доступа нужен HTTPS reverse proxy на хосте или балансировщике; публикация443 сама по себе сертификат не создаёт. Установи Docker Engine и Compose plugin по официальной инструкции для Ubuntu.

Dockerfile для Django

config
FROM python:3.11-slim
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends gcc libpq-dev && rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "yourproject.wsgi:application"]

Добавь в .dockerignore файлы .env, venv, .git и локальные бэкапы. В .env с правами600 задай DB_NAME, DB_USER, DB_PASSWORD и DJANGO_SECRET_KEY; используй отдельные случайные секреты. Этот файл нужен Compose и не должен попадать в образ. Docker-пример — локальный учебный bootstrap: POSTGRES_USER официального образа создаёт суперпользователя БД. До production создай отдельную роль приложения с минимальными правами, передай её DB_USER/DB_PASSWORD контейнеру web отдельно от учётных данных инициализации PostgreSQL и проверь миграции; не оставляй приложение под суперпользователем. Для production закрепи проверенные теги/дигесты образов и зависимости; postgres15 нельзя менять на другую major-версию без миграции данных.

docker-compose.yml

config
services:
  db:
    image: postgres:15
    restart: unless-stopped
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: ${DB_NAME:?Set DB_NAME}
      POSTGRES_USER: ${DB_USER:?Set DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD:?Set DB_PASSWORD}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
      interval: 10s
      timeout: 5s
      retries: 10
  web:
    build: .
    restart: unless-stopped
    volumes:
      - static_volume:/app/staticfiles
      - media_volume:/app/media
    environment:
      DJANGO_SETTINGS_MODULE: yourproject.settings.base
      DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:?Set DJANGO_SECRET_KEY}
      DB_HOST: db
      DB_NAME: ${DB_NAME:?Set DB_NAME}
      DB_USER: ${DB_USER:?Set DB_USER}
      DB_PASSWORD: ${DB_PASSWORD:?Set DB_PASSWORD}
    depends_on:
      db:
        condition: service_healthy
  nginx:
    image: nginx:stable-alpine
    restart: unless-stopped
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - static_volume:/static:ro
      - media_volume:/media:ro
    ports:
      - "127.0.0.1:8080:80"
    depends_on:
      - web
volumes:
  postgres_data:
  static_volume:
  media_volume:

Nginx конфигурация для Docker

config
events {}
http {
    include /etc/nginx/mime.types;
    server {
        listen 80;
        server_name yourdomain.com www.yourdomain.com;
        location /static/ { alias /static/; }
        location /media/ { alias /media/; }
        location / {
            proxy_pass http://web: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;
        }
    }
}

Сначала создай .env, проверь конфигурацию, выполни миграции и сборку статики один раз, затем запусти сервисы. Перед миграцией существующей базы сделай проверенный бэкап. Число workers и права runtime-пользователя настрой под приложение; пример Dockerfile не выполняет отдельное снижение привилегий.

bash
sudo docker compose config --quiet
sudo docker compose build
sudo docker compose up -d db
sudo docker compose run --rm web python manage.py check --deploy
sudo docker compose run --rm web python manage.py migrate
sudo docker compose run --rm web python manage.py collectstatic --noinput
sudo docker compose up -d
sudo docker compose logs --tail=100
curl -H 'Host: yourdomain.com' http://127.0.0.1:8080/

Сравнение методов развертывания

Критерий Классическое (Gunicorn+Nginx) Docker-развертывание
Сложность настройки Средняя/Высокая Низкая/Средняя
Переносимость Низкая Высокая
Масштабируемость Сложная Простая
Производительность Высокая Высокая (минимальные накладные расходы)
Идеально для Дедицированных серверов, production Разработки, микросервисов, CI/CD

Частые вопросы (FAQ)

Какой способ развертывания Django выбрать новичку?

Начни с классического способа (Gunicorn + Nginx) на виртуальном сервере. Это даст понимание, как все работает "под капотом". После освоения переходи к Docker для упрощения процессов.

Нужно ли использовать Docker в production?

Docker можно использовать в production, но он не обязателен. Нужны корректный WSGI/ASGI-сервер, HTTPS, секреты, права, бэкапы и обновления. Пример Compose здесь даёт локальный HTTP-стек; внешний TLS и настройки доверенного proxy нужно завершить отдельно.

Как настроить SSL/HTTPS для Django?

Для Nginx на хосте настрой домен/DNS, установи Certbot и получи сертификат, затем проверь HTTP→HTTPS. Для Docker локальный8080 должен стоять за TLS-proxy; согласуй передачу X-Forwarded-Proto на каждом доверенном hop. В Django настрой SECURE_PROXY_SSL_HEADER только если proxy удаляет поддельный входной заголовок и задаёт его сам, затем secure cookies и HTTPS redirect. Не включай доверие к произвольному клиентскому заголовку; проверь check --deploy, вход и CSRF.

Как организовать деплой новых версий приложения?

Создай скрипт деплоя или используй CI/CD (GitHub Actions, GitLab CI). Перед обновлением сохрани базу и media, проверь восстановление и совместимость миграций. Типичный процесс: проверенная версия кода/зависимостей, миграции, сборка статики, перезапуск Gunicorn и smoke-тест. Откат кода не всегда откатывает схему базы.

Заключение

Мы рассмотрели два основных подхода к развертыванию Django. Классический метод дает полный контроль и понимание архитектуры, а Docker-подход обеспечивает современный, переносимый и масштабируемый способ деплоя.

Профессиональный совет: Вне зависимости от выбранного метода, всегда:
  • Используйте переменные окружения для секретов
  • Настраивайте мониторинг (Sentry для ошибок, Prometheus для метрик)
  • Регулярно делайте бэкапы базы данных и media, защищайте секреты и проверяйте восстановление
  • Тестируйте процесс деплоя на staging-окружении

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

Поделиться: