Материал подготовлен командой Simple-Server для администраторов VPS и выделенных серверов. Команды и пути проверяйте на тестовой машине перед production.
Кратко о задаче
Рекомендуем для экспериментов в рамках изучения материала развернуть отдельную виртуальную машину, арендованную у провайдера Simple-Server. Главное, чтобы на ней сразу же была инсталлирована свежая операционная система Ubuntu с базовыми настройками файрвола и созданным пользователем с привилегиями sudo.
Настройки из инструкции не рекомендуется выполнять под пользователем root — мы будем описывать работу именно под пользователем с привилегиями sudo.
Инсталлируем пакеты из репозитория 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, для этого передадим его системе путем ввода команды:
Теперь в диалоговом окне 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.
Настройка СУБД Postgres завершена, идем дальше.
Создадим виртуальную среду Python
Нам понадобится доступ к использованию команды virtualenv, его мы получим через pip:
sudo -H pip3 install --upgrade pip
sudo -H pip3 install virtualenvПосле инсталляции сделаем новый каталог, где будут размещены проектные модули, и сразу зайдем туда:
mkdir ~/myprojectdir
cd ~/myprojectdirИ развернем виртуальную среду Python:
Команда сделает подпапку 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В самый верх файла добавьте:
Далее необходимо найти директиву 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:
По умолчанию указанный порт заблокирован, как и остальные, еще незадействованные.
Далее запустим сервер разработки 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:
Результат проверки будет выведен на экран:
/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Если при выводе отражаются ошибки, искать первопричину надо начинать с журнала:
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. Тогда поступающие данные будут перекидываться прямо в сокет.
Закроем файл с сохранением изменений. И активируем его путем привязки к папке 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 systemctl restart nginxПо завершении настройки Django с Postgres и Nginx правило доступа к серверу разработки через порт 8000 можно удалять, потому что весь трафик будет направляться на порт 80:
sudo ufw delete allow 8000
sudo ufw allow 'Nginx Full'Теперь для пробы можно подключиться к нашему хосту по домену или напрямую через IP-адрес. Но перед началом реальной разработки рекомендуем защитить трафик при помощи протокола SSL/TSL. Ведь по умолчанию вся информация передается по сети без шифрования, включая и пароли (в простом текстовом формате).
Простейший вариант – установить сертификат от Let’s Encrypt. Его возможностей достаточно для защиты информации, передаваемой в обе стороны, на хост и с хоста разработчика.
Нужен сервер для практики? Арендуйте VPS/VDS в России — root-доступ, NVMe, DDoS-защита и поддержка 24/7.