Django на VPS
В этом руководстве вы развернёте Django-проект на VPS в продакшен-режиме: виртуальное окружение, Gunicorn как systemd-сервис и Nginx в роли reverse proxy с раздачей статики, а также правильные DEBUG и ALLOWED_HOSTS.
Что понадобится
- VPS на Ubuntu 22.04/24.04, Debian 11/12 или AlmaLinux/Rocky Linux 8/9 с доступом по SSH — под root или пользователем с sudo.
- Домен, указывающий на IP сервера (подойдёт и просто IP-адрес, если домена пока нет).
- Свой Django-проект — написанный локально или лежащий в git-репозитории, с файлом зависимостей
requirements.txt. - Базовые навыки работы в терминале по SSH.
ℹ️ Совет: если конкретный стек не принципиален, в VMmanager 6 есть готовый рецепт Django — окружение Django + uWSGI + Nginx одним кликом (как войти в панель — статья «Как войти в VMmanager 6», полный каталог — «Готовые рецепты VMmanager 6»). Ниже — ручная установка с Gunicorn и systemd вместо uWSGI: она даёт больше контроля над процессом и сервисом.
Шаг 1. Установите системные пакеты
Подключитесь к серверу по SSH и установите Python с инструментами для виртуальных окружений, а также Nginx:
# Ubuntu / Debian
sudo apt update
sudo apt install -y python3-venv python3-pip nginx# AlmaLinux / Rocky
sudo dnf install -y python3 python3-pip nginxℹ️ Совет: проверьте версию — python3 --version. Современным версиям Django нужен Python 3.10 или новее. На AlmaLinux/Rocky 8 системный python3 — версии 3.6, этого недостаточно: поставьте более новую версию (например, sudo dnf install -y python3.11) и в шаге 2 создавайте окружение командой python3.11 -m venv venv вместо python3 -m venv venv. На Ubuntu/Debian и AlmaLinux/Rocky 9 системный Python обычно уже подходит.
ℹ️ Проверьте: точный минимум версии Python для вашей версии Django — в release notes на docs.djangoproject.com, со временем это требование растёт.
Шаг 2. Создайте пользователя, скопируйте проект и настройте виртуальное окружение
Запускать веб-приложение от root не стоит. Создайте отдельного системного пользователя для проекта:
# Ubuntu / Debian
sudo adduser django# AlmaLinux / Rocky
sudo useradd -m -s /bin/bash django
sudo passwd djangoℹ️ Совет: если под проект уже есть подходящий пользователь (например, тот, под которым вы заходите по SSH), используйте его — тогда просто подставляйте его имя вместо django во всех командах и файлах ниже.
Переключитесь на этого пользователя и разверните проект в его домашнем каталоге — так, чтобы manage.py лежал прямо в /home/django/myproject:
sudo -iu django
git clone https://github.com/yourname/myproject.git myproject
cd myprojectℹ️ Совет: если проекта пока нет в git-репозитории — просто скопируйте файлы на сервер через scp или rsync, в тот же каталог /home/django/myproject.
Создайте виртуальное окружение и активируйте его:
python3 -m venv venv
source venv/bin/activateУстановите зависимости проекта и Gunicorn:
pip install --upgrade pip
pip install -r requirements.txt
pip install gunicornℹ️ Совет: если Gunicorn уже указан в requirements.txt, повторная установка ничего не изменит. Если проект использует базу данных, не забудьте также выполнить python manage.py migrate — настройка самой БД выходит за рамки этой статьи.
Шаг 3. Настройте DEBUG и ALLOWED_HOSTS
Django по умолчанию настроен для разработки, а не для продакшена. Прежде чем открывать сайт наружу, отредактируйте myproject/settings.py (вместо myproject — имя пакета настроек вашего проекта):
# myproject/settings.py
DEBUG = False
ALLOWED_HOSTS = ["example.com", "www.example.com", "203.0.113.10"]⚠️ Важно: оставлять DEBUG = True в продакшене нельзя — при ошибке Django покажет посетителю полный traceback вместе с фрагментами исходного кода, локальными переменными, настройками и списком установленных библиотек.
При DEBUG = False Django вообще не отвечает на запросы, если ALLOWED_HOSTS пуст, — этот список защищает сайт от запросов с подделанным заголовком Host. Укажите в нём:
- домен(ы), по которым будет доступен сайт — например,
example.comиwww.example.com; - при необходимости — IP-адрес сервера;
- поддомены можно разрешить одной маской, поставив точку в начале значения:
.example.comподойдёт и дляexample.com, и для любого его поддомена; - значение
*(разрешить любойHost) технически допустимо, но тогда проверку заголовкаHostпридётся реализовывать самостоятельно — для обычного сайта используйте конкретный список доменов/IP.
Шаг 4. Проверьте запуск через Gunicorn
Пока вы ещё в виртуальном окружении, запустите Gunicorn вручную — это самый быстрый способ убедиться, что проект вообще поднимается, прежде чем оборачивать его в systemd:
gunicorn --bind 127.0.0.1:8000 myproject.wsgi:applicationВ соседней SSH-сессии проверьте ответ (вместо example.com подставьте значение, указанное в ALLOWED_HOSTS):
curl -I -H "Host: example.com" http://127.0.0.1:8000/Ожидаемый результат — HTTP/1.1 200 OK (или редирект, если ваш проект так настроен). Остановите Gunicorn сочетанием Ctrl+C.
ℹ️ Совет: ошибка DisallowedHost означает, что переданный заголовок Host не входит в ALLOWED_HOSTS (шаг 3). Ошибка ModuleNotFoundError: No module named 'myproject' обычно означает, что команда запущена не из каталога с manage.py — перейдите в /home/django/myproject и повторите.
Когда закончите проверку, выполните deactivate и exit — дальнейшие шаги (systemd, Nginx) выполняются от имени root или sudo-пользователя.
Шаг 5. Опишите Gunicorn как systemd-сервис
От имени root/sudo создайте юнит /etc/systemd/system/myproject.service:
[Unit]
Description=Gunicorn daemon for myproject
After=network.target
[Service]
User=django
Group=django
WorkingDirectory=/home/django/myproject
ExecStart=/home/django/myproject/venv/bin/gunicorn \
--workers 3 \
--bind 127.0.0.1:8000 \
myproject.wsgi:application
Restart=on-failure
[Install]
WantedBy=multi-user.targetUser/Group— пользователь проекта из шага 2, не root.--workers— число рабочих процессов Gunicorn; отправная точка — «(2 × число ядер) + 1», число ядер сервера показывает командаnproc.- Gunicorn запускается по полному пути внутри
venv, а не системный — так гарантированно используется окружение с зависимостями именно этого проекта.
Примените и включите сервис:
sudo systemctl daemon-reload
sudo systemctl enable --now myproject
sudo systemctl status myproject✅ Готово: если systemctl status показывает active (running) — Gunicorn поднялся как сервис: переживёт перезагрузку сервера и автоматически перезапустится при падении (Restart=on-failure).
ℹ️ Совет: логи сервиса — sudo journalctl -u myproject -f. Пригодится, если сайт не откроется и нужно быстро понять, в чём дело.
Шаг 6. Настройте Nginx: reverse proxy и раздача статики
Соберите статические файлы проекта. Вернитесь к пользователю проекта и активируйте виртуальное окружение:
sudo -iu django
cd myproject
source venv/bin/activateДобавьте в myproject/settings.py:
# myproject/settings.py
STATIC_URL = "static/"
STATIC_ROOT = BASE_DIR / "staticfiles"и выполните:
python manage.py collectstaticDjango скопирует все статические файлы — свои и сторонних приложений, включая админку — в /home/django/myproject/staticfiles/. Эту папку Nginx будет отдавать напрямую, не трогая Gunicorn.
Выйдите обратно к root/sudo (deactivate, затем exit) и создайте файл конфигурации сайта — например, sudo nano /etc/nginx/sites-available/myproject на Ubuntu/Debian или sudo nano /etc/nginx/conf.d/myproject.conf на AlmaLinux/Rocky — со следующим содержимым:
server {
listen 80;
server_name example.com www.example.com;
location /static/ {
alias /home/django/myproject/staticfiles/;
}
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;
}
}Замените server_name на свой домен (или IP сервера) — то же значение должно быть в ALLOWED_HOSTS из шага 3.
На Ubuntu/Debian подключите сайт симлинком и уберите дефолтный:
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/defaultНа AlmaLinux/Rocky отдельно подключать файл не нужно — всё из /etc/nginx/conf.d/ читается автоматически.
Проверьте конфигурацию и перезапустите Nginx:
sudo nginx -t
sudo systemctl reload nginx
sudo systemctl enable --now nginxℹ️ Совет: на Ubuntu/Debian Nginx уже запущен и в автозагрузке сразу после установки — enable --now в этом случае ничего не сломает. На AlmaLinux/Rocky эта команда обязательна, иначе Nginx не поднимется после установки или перезагрузки сервера.
⚠️ Важно: на AlmaLinux/Rocky по умолчанию включён SELinux, и он по умолчанию блокирует обращения Nginx как обратного прокси к порту 8000 — вместо сайта вы увидите 502 Bad Gateway. Разрешите такие соединения: sudo setsebool -P httpd_can_network_connect on.
Шаг 7. Откройте порт в файрволе
Если на сервере включён файрвол, сайт снаружи не откроется, пока порт 80 закрыт.
# ufw (Ubuntu/Debian)
sudo ufw allow 80/tcp# firewalld (AlmaLinux/Rocky)
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload⚠️ Важно: подробнее о настройке файрвола — в статье «Настройка файрвола UFW».
Шаг 8. Проверьте результат
Откройте домен (или IP сервера) в браузере — либо проверьте из терминала:
curl -I http://example.com/Ожидаемый ответ — HTTP/1.1 200 OK. Если на странице есть стили или картинки из /static/ (например, стили админки Django на /static/admin/), убедитесь, что они тоже загрузились, — это подтверждает, что Nginx правильно раздаёт STATIC_ROOT.
✅ Готово: сайт открывается через Nginx, статика раздаётся напрямую из staticfiles/, а Gunicorn работает в фоне под systemd с DEBUG = False и настроенным ALLOWED_HOSTS.
Что дальше
- Добавьте HTTPS (например, через Let's Encrypt/certbot) — текущий конфиг Nginx уже готов к тому, чтобы добавить поверх него блок
listen 443 ssl;. - Если сервер будет обслуживать несколько проектов — заведите под каждый свой каталог, виртуальное окружение, systemd-юнит и серверный блок Nginx со своим
server_name. - Другие готовые сценарии для VPS — в статье «Готовые рецепты VMmanager 6».