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.
Шаг 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Шаг 2. Создайте пользователя, скопируйте проект и настройте виртуальное окружение
Запускать веб-приложение от root не стоит. Создайте отдельного системного пользователя для проекта:
# Ubuntu / Debian
sudo adduser django# AlmaLinux / Rocky
sudo useradd -m -s /bin/bash django
sudo passwd djangoПереключитесь на этого пользователя и разверните проект в его домашнем каталоге — так, чтобы manage.py лежал прямо в /home/django/myproject:
sudo -iu django
git clone https://github.com/yourname/myproject.git myproject
cd myprojectСоздайте виртуальное окружение и активируйте его:
python3 -m venv venv
source venv/bin/activateУстановите зависимости проекта и Gunicorn:
pip install --upgrade pip
pip install -r requirements.txt
pip install gunicornШаг 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 = 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.
Когда закончите проверку, выполните 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Шаг 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Шаг 7. Откройте порт в файрволе
Если на сервере включён файрвол, сайт снаружи не откроется, пока порт 80 закрыт.
# ufw (Ubuntu/Debian)
sudo ufw allow 80/tcp# firewalld (AlmaLinux/Rocky)
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reloadШаг 8. Проверьте результат
Откройте домен (или IP сервера) в браузере — либо проверьте из терминала:
curl -I http://example.com/Ожидаемый ответ — HTTP/1.1 200 OK. Если на странице есть стили или картинки из /static/ (например, стили админки Django на /static/admin/), убедитесь, что они тоже загрузились, — это подтверждает, что Nginx правильно раздаёт STATIC_ROOT.
Что дальше
- Добавьте HTTPS (например, через Let's Encrypt/certbot) — текущий конфиг Nginx уже готов к тому, чтобы добавить поверх него блок
listen 443 ssl;. - Если сервер будет обслуживать несколько проектов — заведите под каждый свой каталог, виртуальное окружение, systemd-юнит и серверный блок Nginx со своим
server_name. - Другие готовые сценарии для VPS — в статье «Готовые рецепты VMmanager 6».