Публикация сайта, созданного на python фреймворке Django, на сервере под Debian.


Был установлен linux Debian 10 (в моем случае на одноплатник Orange Pi PC), проброшены порты 80 и 443 на сервер, получен постоянный ip-адрес у провайдера и привязан к зарегистрированному доменному имени сайта.

Для публикации использовался web-сервер Nginx, WSGI-сервер Gunicorn, certbot для получения, добавления и обновления ssl-сертификата.

Заливка сайта


Все действия далее выполняются под полными правами:

sudo su

В установленном дистрибутиве python уже присутствовал, поэтому использовал его:

python3 --version
Python 3.7.3

Если у вас по каким либо причинам отсутствует, установите:

apt-get install python3
apt-get install python3-venv


Нужно установить web-сервер:

apt-get install nginx

Для примера использую заготовку сайта, размещенного на githab.



Скачивание:

cd /var/www
git clone https://github.com/Virtblch/SiteOnPythonDjango.git


По завершении в каталоге /var/www появился каталог SiteOnPythonDjango с загруженным сайтом. Далее создаем и запускаем виртуальное python-окружение:

cd SiteOnPythonDjango
python3 -mvenv venv
source ./venv/bin/activate


Заходим в каталог основного приложения (в данном случае "blog"), и в ранее созданном вируальном окружении ставим фреймворк Django:

cd blog
pip install django


Далее в конфиге приложения необходимо изменить ip-адрес сервера и имя (для возможности доступа через браузер), в моем случае локальный ip-адрес 192.168.11.40, и имя сайта для доступа из внешней сети linux-bash.ru :

nano blog/settings.py
ALLOWED_HOSTS = ['192.168.11.40', 'linux-bash.ru']

Для проверки запускаем встроенный web-сервер python:

python3 ./manage.py runserver 0.0.0.0:8000

И заходим через браузер из локальной сети на сайт:

http://192.168.11.40:8000

Если ок, можно тормозить встроенный сервер ( CTRL+C ) и двигаться дальше.

Теперь ставим

WSGI-сервер Gunicorn:


pip install gunicorn

Упрощенно говоря, WSGI представляет собой интерфейс между веб-сервером и самим приложением. Он устанавливает стандартное соединение между различными серверами и приложениями (фреймворками), что обеспечивает их взаимозаменяемость в случае необходимости. Теперь для проверки работоспособности можно запустить встроенный в gunicorn web-сервер:

gunicorn --bind 0.0.0.0:8000 blog.wsgi
где blog — это имя (и каталог) основного приложения, в котором лежит конфигурационный файл settings.py.

И также проверяем доступность сайта по адресу http://192.168.11.40:8000 , затем стопим сервер CTRL+C .

* Из-за различия версий python и , соответственно, django (имеющиеся на "боевом" старее) пришлось в коде приложения изменить свежую django-библиотеку "re_path" на прежнюю "url". Если также увидели соответствующую ошибку, то:

nano blog/urls.py
в коде "re_path" изменить на "url",
закоментить "import re_path", раcкоментить "import url" .

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

nano blog/settings.py
DEBUG = False

Команда ниже собирает все статические файлы приложения (включая статические файлы админки) и из любых других папок, которые указаны в settings.py и копирует их в STATIC_ROOT :

python3 ./manage.py collectstatic

И снова проверяем доступность сайта после запуска сервера:
gunicorn --bind 0.0.0.0:8000 blog.wsgi

При отсутствии проблем стопим сервер и виртуальное окружение:

CTRL+C
deactivate

Далее прописывам Gunicorn в автозапуск демоном, меняя пользователя, из под которого он будет стартовать (у меня в примере это orangepc, создайте пользователя, добавив его в группу www-data если пользователь еще не создан) и путь к публикуемому приложению (если уже пробуете публиковать свое):

nano /etc/systemd/system/gunicorn.socket

[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target


nano /etc/systemd/system/gunicorn.service

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

[Service]
User=orangepc
Group=www-data
WorkingDirectory=/var/www/SiteOnPythonDjango/blog
ExecStart=/var/www/SiteOnPythonDjango/venv/bin/gunicorn \
--access-logfile - \
--workers 3 \
--bind unix:/run/gunicorn.sock \
blog.wsgi:application

[Install]
WantedBy=multi-user.target


*workers вычисляется как количество ядер процессора * 2 + 1 .

И даем права на каталог /var/www пользователю и группе:

sudo chown -R www-data:www-data /var/www
sudo usermod -aG www-data orangepc
sudo chmod go-rwx /var/www
sudo chmod go+x /var/www
sudo chgrp -R www-data /var/www
sudo chmod -R go-rwx /var/www
sudo chmod -R g+rwx /var/www


*Убираем все разрешения для всех, а потом их назначаем конкретному пользователю и группе.

Затем старт демона и добавление в автостарт:

systemctl start gunicorn.socket
systemctl enable gunicorn.socket


*Для применения измениний при последующем редактировании (если например где-то выше ошиблись и исправили):
systemctl daemon-reload
systemctl restart gunicorn


Проверка:
file /run/gunicorn.sock # Проверка создания сокета
systemctl status gunicorn # Статус демона
curl --unix-socket /run/gunicorn.sock 192.168.11.40 # В выводе должен быть html-код главной страницы сайта

Теперь

настраиваем Nginx

, указывая в конфиге пути к каталогам статичных файлов приложения, возможные имена сайта и использование WSGI-сервера Gunicorn:

nano /etc/nginx/sites-available/default

server {
listen 80;
server_name 192.168.11.40 linux-bash.ru;

location = /favicon.ico { access_log off; log_not_found off; }
location static/static/ {
alias /var/www/SiteOnPythonDjango/blog/static/static/;
}

location /static/files/ {
alias /var/www/SiteOnPythonDjango/blog/static/files/;
}

location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
}


Тестируем конфиг:

nginx -t

И, если ок, перезапускаем сервер:

systemctl restart nginx

И снова проверяем доступность сайта.

*Админка сайта в примере доступна по адресу http://<имя сайта>/admin (логин: admin пароль: admin).

На данном этапе сайт должен быть полностью работоспособен по протоколу HTTP.

Теперь настраиваем доступ по HTTPS, добавляя сертификат.

Установим certbot.

Certbot — это программный инструмент с открытым исходным кодом для автоматического использования сертификатов Let’s Encrypt на веб-сайтах для включения HTTPS.

apt-get install certbot python-certbot-nginx

Запуск интерактивной настройки:

certbot run --nginx

Необходимо ответить на вопросы, например указать ваш почтовый адрес, выбрать имя сайта и проч.

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

nano /etc/systemd/system/certbot-renewal.service

[Unit]
Description=Certbot Renewal

[Service]
ExecStart=/usr/bin/certbot renew --force-renewal --post-hook "systemctl reload nginx.service"



nano /etc/systemd/system/certbot-renewal.timer

[Unit]
Description=Timer for Certbot Renewal

[Timer]
OnBootSec=300
OnUnitActiveSec=1w

[Install]
WantedBy=multi-user.target


Запускаем таймер, добавляем в автозагрузку, смотрим статус:

systemctl start certbot-renewal.timer
systemctl enable certbot-renewal.timer
systemctl status certbot-renewal.timer


Должен выпуститься сертификат, сайт должен стать доступен по https://<доменное имя сайта> .

May 29, 2022