Top.Mail.Ru
Публичное облако на базе VMware с управлением через vCloud Director
Вход / Регистрация

Как установить Django, Nginx и Gunicorn на виртуальный сервер

Команда Timeweb Cloud
Команда Timeweb Cloud
Наши инженеры, технические писатели, редакторы и маркетологи
23 мая 2022 г.
7304
13 минут чтения
Средний рейтинг статьи: 5

Веб-фреймворк Django – мощный инструмент разработки мобильных приложений и сайтов на языке программирования Python. В состав системы включен упрощенный сервер для локальной проверки работоспособности кода. Его достаточно для простых решений и тестирования, но при создании более серьезных продуктов обычно устанавливают сервер для продакшена.

В статье разберем, как установить Django на Ubuntu и внести необходимые настройки.

Как Установить Django, Nginx И Gunicorn На Виртуальный Сервер

Что понадобится

Рекомендуем для экспериментов в рамках изучения материала развернуть отдельную виртуальную машину, арендованную у провайдера Timeweb Cloud. Главное, чтобы на ней сразу же была инсталлирована свежая операционная система Ubuntu с базовыми настройками файрвола и созданным пользователем с привилегиями sudo.

Настройки из инструкции не рекомендуется выполнять под пользователем root — мы будем описывать работу именно под пользователем с привилегиями sudo.

VDS и VPS

Гибкие виртуальные серверы с почасовым
биллингом по всему миру: Россия, Азия и Европа

Инсталлируем пакеты из репозитория Ubuntu

Первоначально скачаем обновления пакетов apt, чтобы пользоваться их актуальными релизами. Следом загрузим Python 3:

  
sudo apt update sudo apt install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx curl

Команда установит pip, файлы Python, дальше на их основе мы развернем Gunicorn, СУБД PostgreSQL и установим библиотеки, какие понадобятся для работы с Django, а также веб-сервер Nginx.

Создадим БД и аккаунт в PostgreSQL

В системе Postgres стандартно применяется аутентификация «peer authentication». Такой подход позволяет обходиться без ввода логина-пароля, если название аккаунта операционки совпадает с пользователем самой базы данных. При желании можно использовать sudo, для этого передадим его системе путем ввода команды:

  
sudo -u postgres psql

Теперь в диалоговом окне PostgreSQL создадим базу данных под свой проект:

  
CREATE DATABASE myproject;

Следом пользователя с надежным паролем:

  
CREATE USER myprojectuser WITH PASSWORD 'password';

Чтобы упростить дальнейшую работу, сразу зададим ряд настроек. Например, изменим кодировку на UTF-8, зададим схему изоляции транзакций «read committed», установим часовой пояс:

  
ALTER ROLE myprojectuser SET client_encoding TO 'utf8'; ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed'; ALTER ROLE myprojectuser SET timezone TO 'UTC';

Теперь для нового пользователя надо открыть доступ на администрирование БД:

  
GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;

По завершении настройки закроем диалоговое окно PostgreSQL.

  
\q

Настройка СУБД Postgres завершена, идем дальше.

Создадим виртуальную среду Python

Нам понадобится доступ к использованию команды virtualenv, его мы получим через pip:

  
sudo -H pip3 install --upgrade pip sudo -H pip3 install virtualenv

После инсталляции сделаем новый каталог, где будут размещены проектные модули, и сразу зайдем туда:

  
mkdir ~/myprojectdir cd ~/myprojectdir

И развернем виртуальную среду Python:

  
virtualenv myprojectenv

Команда сделает подпапку myprojectenv, куда локально будет инсталлирована версия – Python и pip. После инсталляции проведем активацию:

  
source myprojectenv/bin/activate

После ввода последней команды строка поменяет вид, она показывает: пользователь теперь будет вводить команды в виртуальной среде. Примерный вариант окна:

  
(myprojectenv)user@host:~/myprojectdir$

Теперь пришло время для установки Django, Gunicorn и адаптера psycopg2 PostgreSQL:

  
pip install django gunicorn psycopg2-binary

Обязательные для работы компоненты установлены.

Сделаем свой проект Django и настроим его

Складывать файлы будем в ранее указанный каталог. В нем система сделает отдельную папку для размещения фактического кода, скрипта управления:

  
django-admin startproject myproject ~/myprojectdir

Команда явно задает название каталога ~/myprojectdir.

Поменяем настройки проекта

Запустим конфигурационный файл на редактирование:

  
nano ~/myprojectdir/myproject/settings.py

В самый верх файла добавьте:

  
import os

Далее необходимо найти директиву ALLOWED_HOSTS. Ей определены адреса, разрешенные для соединения с экземпляром Django. Запросы остальных хостов будут отклонены автоматически. Здесь надо перечислить нужные IP или домены, ограничив их квадратными скобками.

  
ALLOWED_HOSTS = ['your_server_domain_or_IP', 'second_domain_or_IP', . . ., 'localhost']

Следом перейдите в раздел, начинающийся со слова DATABASES. В нем мы поменяем назначение базы данных на PostgreSQL. Также зададим условие использовать адаптер psycopr2, имя самой БД, а также пользователя с паролем.

  
DATABASES = {     'default': {         'ENGINE': 'django.db.backends.postgresql_psycopg2',         'NAME': 'myproject',         'USER': 'myprojectuser',         'PASSWORD': 'password',         'HOST': 'localhost',         'PORT': '',     } }

Остается в «хвосте» внести параметр, фиксирующий место, где хранить статичные файлы. Это понадобится для Nginx, который мы настроим в паре с PostgreSQL.

  
STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

При закрытии файла обязательно согласитесь с сохранением изменений.

Завершим задачу настройки

Скопируем изначальную схему БД:

  
~/myprojectdir/manage.py makemigrations ~/myprojectdir/manage.py migrate

Создадим аккаунт, администрирующий проект:

  
~/myprojectdir/manage.py createsuperuser

Придумайте имя, пароль и укажите актуальный email. Если планируется собирать весь статичный контент в одной папке, укажите ее явно:

  
~/myprojectdir/manage.py collectstatic

Команда потребует подтверждения, после чего файлы переместятся в папку static. Зададим возможность подключения в брандмауэре UFW:

  
sudo ufw allow 8000

По умолчанию указанный порт заблокирован, как и остальные, еще незадействованные.

Далее запустим сервер разработки Django, выполнив команду:

  
~/myprojectdir/manage.py runserver 0.0.0.0:8000

Теперь можно проверить указанный в настройках IP или домен путем ввода в адресную строку браузера:

  
http://server_domain_or_IP:8000

Если откроется страница индекса Django, то все работает. Сразу лучше добавить к адресу путь/admin и пробно зайти в систему под заданным именем-паролем. После аутентификации будет предоставлен доступ к панели администратора. Можно закрывать терминал, где мы производили настройку нажатием комбинации < Ctrl+C>.

Создадим файлы сокета и systemd для Gunicorn

Сокет Gunicorn появляется при старте systemd, после чего прослушивает подключения. Но сначала создадим файл с привилегиями sudo:

  
sudo nano /etc/systemd/system/gunicorn.socket

В нем мы сделаем новый раздел [Unit], куда внесем описательную часть сокета, раздел [Socket], при помощи которого определим его размещение и [Install] для обеспечения установки в указанное время:

  
[Unit] Description=gunicorn socket [Socket] ListenStream=/run/gunicorn.sock [Install] WantedBy=sockets.target

При закрытии файла обязательно согласитесь на сохранение изменений. Перейдем к служебному файлу systemd. Его также надо создать и открыть на редактирование:

  
sudo nano /etc/systemd/system/gunicorn.service

Начнем с раздела [Unit], где укажем метаданные и зависимости – описание службы, предписание инициализировать ее только после подтверждения связи с хостом.

  
[Unit] Description=gunicorn daemon Requires=gunicorn.socket After=network.target

Перейдем к разделу [Service]. В нем зададим пользовательскую учетку и группу, под которой планируем запускать процесс. В этом материале укажем в качестве владельца пользователя, потому что он таковым формально и является. Зададим группу www-data, карту рабочей папки и команду, запускающую службы. В качестве примера используем 3 процесса:

  
[Unit] Description=gunicorn daemon Requires=gunicorn.socket After=network.target [Service] User=user Group=www-data WorkingDirectory=/home/user/myprojectdir ExecStart=/home/user/myprojectdir/myprojectenv/bin/gunicorn \           --access-logfile - \           --workers 3 \         --bind unix:/run/gunicorn.sock \          myproject.wsgi:application

В «хвосте» внесем раздел [Install]. В нем будем хранить информацию, куда systemd привязывать эти службы, если они будут активированы при загрузке.

  
[Unit] Description=gunicorn daemon Requires=gunicorn.socket After=network.target [Service] User=user Group=www-data WorkingDirectory=/home/user/myprojectdir ExecStart=/home/user/myprojectdir/myprojectenv/bin/gunicorn \           --access-logfile - \           --workers 3 \           --bind unix:/run/gunicorn.sock \           myproject.wsgi:application [Install] WantedBy=multi-user.target

Все, можно закрывать файл с сохраненными изменениями. Попробуем стартовать сокет Gunicorn:

  
sudo systemctl start gunicorn.socket sudo systemctl enable gunicorn.socket

Проверим файл сокета Gunicorn

Статус процесса и сам факт того, получилось ли у него стартовать, можно проверить командой:

  
sudo systemctl status gunicorn.socket

Обязательно убедитесь, что файл gunicorn.sock присутствует в папке /run:

  
file /run/gunicorn.sock

Результат проверки будет выведен на экран:

  
/run/gunicorn.sock: socket

Если при старте systemctl status выпала ошибка – в папке /run нет guricorn.sock – это сигнализирует, что сокет Gunicorn фактически не создан. Выяснить причину поможет журнал:

  
sudo journalctl -u gunicorn.socket

Перед повторным запуском рекомендуем проверить содержимое разделов, которые мы вносили выше – не закралась ли там ошибка.

Диагностируем активацию сокета

Важно учитывать, что при запуске gunicorn.socket служба gunicorn.service неактивна. Проверить это можно командой:

  
sudo systemctl status gunicorn

Результат на экране:

  
gunicorn.service - gunicorn daemon    Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled)    Active: inactive (dead)

Продиагностируем активацию сокета установлением коннекта через curl:

  
curl --unix-socket /run/gunicorn.sock localhost

Если данные отображаются в HTML-формате, все отлично – Gunicorn стартовал и готов обслуживать программы на Django. Проверим службу командой:

  
sudo systemctl status gunicorn

Результат на экране:

  
gunicorn.service - gunicorn daemon    Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled)    Active: active (running) since Mon 2022-05-11 21:15:40 UTC; 4s ago  Main PID: 1157 (gunicorn)     Tasks: 4 (limit: 1153)    CGroup: /system.slice/gunicorn.service            ├─1157 /home/user/myprojectdir/myprojectenv/bin/python3 /home/user/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock myproject.wsgi:application            ├─1178 /home/user/myprojectdir/myprojectenv/bin/python3 /home/user/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock myproject.wsgi:application            ├─1180 /home/user/myprojectdir/myprojectenv/bin/python3 /home/user/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock myproject.wsgi:application            └─1181 /home/user/myprojectdir/myprojectenv/bin/python3 /home/user/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock myproject.wsgi:application May 11 21:15:40 django1 systemd[1]: Started gunicorn daemon. May 11 21:15:40 django1 gunicorn[1157]: [2022-05-11 20:00:40 +0000] [1157] [INFO] Starting gunicorn 19.9.0 May 11 21:15:40 django1 gunicorn[1157]: [2022-05-11 20:00:40 +0000] [1157] [INFO] Listening at: unix:/run/gunicorn.sock (1157) May 11 21:15:40 django1 gunicorn[1157]: [2022-05-11 20:00:40 +0000] [1157] [INFO] Using worker: sync May 11 21:15:40 django1 gunicorn[1157]: [2022-05-11 20:00:40 +0000] [1178] [INFO] Booting worker with pid: 1178 May 11 21:15:40 django1 gunicorn[1157]: [2022-05-11 20:00:40 +0000] [1180] [INFO] Booting worker with pid: 1180 May 11 21:15:40 django1 gunicorn[1157]: [2022-05-11 20:00:40 +0000] [1181] [INFO] Booting worker with pid: 1181 May 11 21:15:41 django1 gunicorn[1157]:  - - [11/May/2022:21:15:41 +0000] "GET / HTTP/1.1" 200 16348 "-" "curl/7.58.0"

Если при выводе отражаются ошибки, искать первопричину надо начинать с журнала:

  
sudo journalctl -u gunicorn

Также желательно вручную сверить содержимое файла gunicorn.service. Можно перезапустить демона для повторного считывания данных по Gunicorn:

  
sudo systemctl daemon-reload sudo systemctl restart gunicorn

До устранения любых ошибок продолжать дальше нельзя.

Настроим Nginx как прокси для Gunicorn

Сначала сделаем и откроем модуль в папке Nginx sites-available:

  
sudo nano /etc/nginx/sites-available/myproject

Запустим редактирование файла и внесем инструкцию прослушивать порт 80, отвечать на домен или IP-адрес нашего хоста:

  
server {     listen 80;     server_name server_domain_or_IP; }

Следующим шагом зададим инструкцию игнорировать любые проблемы, связанные с поиском favicon. И укажем, где расположены статичные ресурсы, перенесенные нами ранее в каталог по пути ~/myprojectdir/static.

  
server {     listen 80;     server_name server_domain_or_IP;     location = /favicon.ico { access_log off; log_not_found off; }     location /static/ {         root /home/user/myprojectdir;     } }

Последним шагом создадим блок location / {}, который задаст соответствие любым запросам. В него внесем файл proxy_params, поставляемый в типовом наборе Nginx. Тогда поступающие данные будут перекидываться прямо в сокет.

  
server {     listen 80;     server_name server_domain_or_IP;     location = /favicon.ico { access_log off; log_not_found off; }     location /static/ {         root /home/user/myprojectdir;     }     location / {         include proxy_params;         proxy_pass http://unix:/run/gunicorn.sock;     } }

Закроем файл с сохранением изменений. И активируем его путем привязки к папке sites-enabled:

  
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled

Также на этом этапе добавим пользователя www-data в группу текущего пользователя. Для этого выполним:

  
sudo usermod -a -G ${USER} www-data

Продиагностируем Nginx на предмет ошибок в синтаксисе:

  
sudo nginx -t

Если все работает без перебоев, перезапустим веб-сервер:

  
sudo systemctl restart nginx

По завершении настройки Django с Postgres и Nginx правило доступа к серверу разработки через порт 8000 можно удалять, потому что весь трафик будет направляться на порт 80:

  
sudo ufw delete allow 8000 sudo ufw allow 'Nginx Full'

Теперь для пробы можно подключиться к нашему хосту по домену или напрямую через IP-адрес. Но перед началом реальной разработки рекомендуем защитить трафик при помощи протокола SSL/TSL. Ведь по умолчанию вся информация передается по сети без шифрования, включая и пароли (в простом текстовом формате).

Простейший вариант – установить сертификат от Let’s Encrypt. Его возможностей достаточно для защиты информации, передаваемой в обе стороны, на хост и с хоста разработчика.

Подготовили для вас выгодные тарифы на облачные серверы

  • Premium 3.3 ГГц
  • Dedicated CPU
Москва
12 мес Скидка 10%
Cloud MSK 15

270 ₽/мес

Процессор
1 x 3.3 ГГц
Память
1 ГБ
NVMe
15 ГБ
Канал
1 Гбит/с
Публичный IP
Cloud MSK 30

495 ₽/мес

Процессор
1 x 3.3 ГГц
Память
2 ГБ
NVMe
30 ГБ
Канал
1 Гбит/с
Публичный IP

Выводы

Вот мы и рассмотрели подготовку к разработке Django-приложений на PostgreSQL. Во всем этом нам помогли облачные серверы компании Timeweb Cloud. На них можно устраивать любые эксперименты, в том числе и с интересующей нас связкой Ubuntu, Django и Nginx. В созданной виртуальной среде уже можно попробовать создать собственное приложение.

23 мая 2022 г.
7304
13 минут чтения
Средний рейтинг статьи: 5

Читайте также

Хотите внести свой вклад?
Участвуйте в нашей контент-программе за
вознаграждение или запросите нужную вам инструкцию
img-server
  • Ваш комментарий
  • Предпросмотр
Комментарии 14
Pedro
25.09.2024, 07:52

Хорошая статья, но если на сервере планируется развернуть backend на Django и frontend на React, то можно ли настроить Gunicorn так же на sockets или же надо настраивать через порты? Как frontend будет общаться с backend?

Команда Timeweb Cloud
Команда Timeweb Cloud
30.09.2024, 11:29

Добрый день!

Можно настроить Gunicorn как на сокетах, так и на портах — разницы с точки зрения работы сервера не будет.

Фронтенд на React будет общаться с бэкендом через HTTP(S)-запросы, и это не зависит от того, как настроено взаимодействие между Nginx и Gunicorn (сокеты или порты). Nginx будет выступать в роли прокси-сервера, который перенаправляет запросы от фронтенда к бэкенду. Если фронтенд и бэкенд находятся на одном домене, Nginx можно настроить так, чтобы все API-запросы (например, /api/) перенаправлялись на Gunicorn, а остальные запросы обслуживались как статика для React.

krasszen
krasszen
05.03.2024, 01:17

Всё отлично, но вся инструкция делается под root. Вначале статьи неплохо было бы написать как создать пользователя и делать всё из под него.

В конце статьи написано про SSL. Напишите статью на эту тему, в продолжение этой статьи. Либо прикрепите ссылку, если статья уже есть.

Команда Timeweb Cloud
Команда Timeweb Cloud
05.03.2024, 01:50

Добрый день! В начале статьи в разделе «Что понадобится» мы уточняем, что все команды необходимо выполнять под пользователем с правами sudo и даем ссылку на инструкцию, как его создать. Команды в статье указаны с sudo.

Настроить SSL Let's Encrypt можно по этой инструкции. Добавили ссылку в статью 👌

krasszen
krasszen
05.03.2024, 04:56

Установка довольно быстро упростилась. Например тут описано в нескольких командах: https://certbot.eff.org/instructions?ws=nginx&os=ubuntufocal

Можно добавить в статью.

Александр Анищенко
Александр Анищенко
04.02.2024, 03:33

Bad Request (400) - вот такая ошибка появляется при попыпке перейти по адресу домена.

Команда Timeweb Cloud
Команда Timeweb Cloud
05.03.2024, 02:29

Добрый день! Судя по ошибке, возможно, не был разрешен доступ по домену. Убедитесь, что все выполнено в соответствии с инструкцией. Также рекомендуем проверить логи доступа Nginx для домена, на котором запущен Django (/var/log/nginx/access.log).

zahargm808
zahargm808
08.11.2023, 14:36

Команда sudo nginx –t с опечаткой, скорее всего там один некорректный символ. Выдает: nginx: invalid option: &#34;-t&#34; Перепишите ее вручную, пожалуйста

Команда Timeweb Cloud
Команда Timeweb Cloud
09.11.2023, 02:11

Поправили -t и import os. Спасибо, что обратили внимание 💙

zahargm808
zahargm808
08.11.2023, 14:13

Добрый день!

В файле

nano ~/myprojectdir/myproject/settings.py

Надо также добавить import os в самом вверху, иначе

STATIC_ROOT = os.path.join(BASE_DIR, "static/")

Не будет работать, потому что не импортирована библиотека os

K D
K D
18.10.2023, 11:26

Не подключается static. В логе увидел, что есть ограничение доступа. Т.е. надо дать nginx доступ к папке static или даже ко всей папке проекта, где и как это делать?

Команда Timeweb Cloud
Команда Timeweb Cloud
19.10.2023, 04:54

Добрый день! Перепроверили инструкцию; для решения проблемы нужно добавить пользователя www-data в группу текущего пользователя:

sudo usermod -a -G ${USER} www-data

После чего перезапустить Nginx. Добавили этот момент в подраздел Nginx как прокси для Unicorn. Спасибо за замечание!

Александр
Александр
24.07.2023, 09:31

В вашем руководстве пропущена одна команда.

Написано: "Можно сразу проверить ранее указанный в настройках IP или домен путем ввода в адресную строку своего браузера": http://server_domain_or_IP:8000

Так вот, страница сайта не откроется, т.к. ещё не запущен сервер разработки Django. Надо его запустить: ~/myprojectdir/manage.py runserver 0.0.0.0:8000

И только поле этого на порту 8000 можно посмотреть свой сайт, перейдя по ссылке: http://server_domain_or_IP:8000

Команда Timeweb Cloud
Команда Timeweb Cloud
25.07.2023, 04:17

Спасибо, что заметили! Внесли исправления в статью.

Кажется, вы отлично разбираетесь в теме. Может быть, вам будет интересно стать нашим автором и написать инструкцию (или несколько) для наших читателей?

Если решите попробовать, напишите нам на емейл content@timeweb.cloud. Обсудим темы статей, вознаграждение и условия сотрудничества :)

Произошла неизвестная ошибка
Мы используем на сайте куки.
В интернете без них никак