Разработка Django-приложения на PostgreSQL + Nginx + Gunicorn в Debian 8

Published by Leave your thoughts

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

Данное руководство поможет установить и настроить компоненты, необходимые для обслуживания приложений Django на сервере Debian 8: СУБД PostgreSQL (вместо SQLite), сервер приложений Gunicorn, Nginx (как обратный прокси-сервер для Gunicorn).

Требования

Для выполнения руководства понадобится:

  • Свежий предварительно настроенный сервер Debian 8.
  • Пользователь с доступом к команде sudo.

Все необходимые рекомендации можно найти в руководстве по начальной настройке сервера.

1: Установка зависимостей

Для начала нужно установить из репозиториев системы недостающее программное обеспечение: менеджер пакетов pip, базу данных и связующие библиотеки. Прежде чем начать установку пакетов, обновите индекс пакетов системы.

Чтобы установить зависимости Python 2, введите:

sudo apt-get update
sudo apt-get install python-pip python-dev libpq-dev postgresql postgresql-contrib nginx

Установить пакеты для Python 3 можно с помощью следующей команды:

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

Эта команда устанавливает pip, инструменты разработки Python, систему управления базами данных PostgreSQL и веб-сервер Nginx.

2: Создание базы данных и пользователя PostgreSQL

Теперь нужно создать БД и пользователя для приложения Django.

Для локальных соединений PostgreSQL по умолчанию использует схему так называемой «одноранговой аутентификации» (англ. peer authentication). В целом, это означает, что если имя пользователя операционной системы совпадает с именем валидного пользователя Postgres, данный системный пользователь может войти в СУБД без дальнейшей аутентификации.

При установке PostgreSQL был создан пользователь операционной системы по имени postgres, что совпадает с пользователем postgres – администратором системы PostgreSQL. Измените пользователя и войдите как postgres. Для этого можно использовать sudo и опцию –u:

sudo -u postgres psql

Итак, сначала нужно создать БД для проекта Django.

Примечание: В данном руководстве БД условно называется myproject, но лучше использовать более описательное имя.

CREATE DATABASE myproject;
CREATE DATABASE

Примечание: Каждая команда должна заканчиваться точкой с запятой.

Затем создайте пользователя для новой БД и пароль для него:

CREATE USER myprojectuser WITH PASSWORD 'password';
CREATE ROLE

Затем нужно изменить параметры подключения для нового пользователя. Это позволит ускорить выполнение операций базы данных, при этом значения не придётся запрашивать при установке каждого соединения.

Установите UTF-8 как кодировку по умолчанию, чего требует Django. Также установите схему по умолчанию изоляции транзакций «read committed», которая блокирует считывание с незавершенных транзакций. В завершение нужно установить часовой пояс. По умолчанию проекты Django будут использовать UTC.

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';
ALTER ROLE
ALTER ROLE
ALTER ROLE

Передайте новому пользователю права на доступ к этой базе данных:

GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;
GRANT

Закройте командную строку SQL и вернитесь в сессию оболочки пользователя postgres:

\q

3: Виртуальная среда Python

Теперь нужно подготовить виртуальную среду Python, в которой будет храниться приложение. Для этого установите инструмент virtualenv:

# Python 2:
sudo pip install virtualenv
# Python 3:
sudo pip3 install virtualenv

Создайте каталог для хранения приложения и откройте его:

mkdir ~/myproject
cd ~/myproject

Примечание: Вместо условного названия каталога укажите название вашего проекта.

В этом каталоге нужно создать виртуальную среду Python:

virtualenv venv

Эта команда создаст каталог venv в каталоге проекта myproject и установит в него локальную копию Python и pip. В этом каталоге можно настроить изолированную среду Python для проекта.

Прежде чем установить зависимости Python, нужно включить виртуальную среду.

source venv/bin/activate

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

(venv)user@host:~/myproject$

Теперь можно установить Django, Gunicorn и psycopg2 (адаптер PostgreSQL).

pip install django gunicorn psycopg2

Примечание: Вне зависимости от версии Python в виртуальной среде нужно использовать команду pip (не pip3).

4: Создание и настройка проекта Django

Теперь все компоненты Python установлены, можно приступать к разработке проекта.

Создание проекта Django

Установите файлы проекта Django в подготовленный каталог. Это создаст каталог с кодом и поместит в этом каталоге скрипт управления. Точка в конце команды значит, что создать файлы нужно в текущем каталоге:

django-admin.py startproject myproject .

Примечание: Если вы пропустите точку в конце команды, она создаст дополнительный уровень каталогов.

Теперь структура каталогов выглядит так:

.
└── ./myproject/
├── manage.py
├── myproject/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── venv/
└── . . .

Настройка проекта

После этого нужно настроить проект. Откройте файл settings.py в текстовом редакторе:

nano ~/myproject/myproject/settings.py

Найдите в файле директиву ALLOWED_HOSTS. Она содержит белый список адресов и доменов, которые могут подключаться к Django. Если входящий запрос содержит заголовок Host, который не включен в этот список, такой запрос будет сброшен. Это обеспечит дополнительный уровень безопасности Django.

Перечислите в квадратных скобках все заведомо безопасные для Django IP-адреса или домены. Каждый элемент нужно взять в одинарные кавычки. Все элементы списка разделяются запятыми. Чтобы добавить в список поддомены, поставьте перед доменным именем точку. В приведённом ниже фрагменте вы найдёте несколько закомментированных примеров того, как может выглядеть директива ALLOWED_HOSTS.

. . .
# The simplest case: just add the domain name(s) and IP addresses of your Django server
# ALLOWED_HOSTS = [ 'example.com', '203.0.113.5']
# To respond to 'example.com' and any subdomains, start the domain with a dot
# ALLOWED_HOSTS = ['.example.com', '203.0.113.5']
ALLOWED_HOSTS = ['your_server_domain_or_IP', 'second_domain_or_IP', . . .]

Затем найдите DATABASES – раздел настроек доступа к БД. Этот раздел содержит настройки для БД SQLite, однако проект использует БД PostgreSQL. Замените данные стандартной БД данными PostgreSQL. Настройте Django для использования psycopg2. Укажите имя БД, имя и пароль пользователя базы данных, а затем укажите, что база данных находится на локальном компьютере. Настройки порта (параметр PORT) можно не заполнять.

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

Перейдите в конец файла и укажите, где должны находиться статические файлы. Это необходимо для того, чтобы веб-сервер Nginx мог обрабатывать запросы по этим файлам. Следующая строка поместит эти файлы в каталог под названием static в каталоге проекта:

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

Сохраните и закройте файл.

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

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

cd ~/myproject
./manage.py makemigrations
./manage.py migrate

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

./manage.py createsuperuser

Укажите его имя, адрес электронной почты и пароль пользователя.

Переместите весь статический контент в подготовленный каталог:

./manage.py collectstatic

Подтвердите операцию. Теперь все статические файлы хранятся в каталоге static.

Если сервер был настроен согласно этому руководству, на данный момент порт сервера разработки Django (8000) заблокирован брандмауэром. Чтобы протестировать работу приложения, нужно разблокировать этот порт.

Если вы используете ufw, введите:

sudo ufw allow 8000

Если вы используете iptables, команда во многом будет зависеть от текущих настроек брандмауэра. В большинстве случаев сработает такое правило:

sudo iptables -I INPUT -p tcp --dport 8000 -j ACCEPT

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

Теперь можно протестировать проект, запустив сервер разработки Django:

./manage.py runserver 0.0.0.0:8000

Откройте в браузере доменное имя или IP-адрес и укажите порт :8000.

http://server_domain_or_IP:8000

На экране появится приветственная страница Django:

It worked!
Congratulations on your first Django-powered page.

Добавьте в конец ссылки /admin в конец адреса. Браузер запросит учётные данные администратора. Заполните появившиеся на экране поля, указав имя и пароль только что созданной учётной записи администратора при помощи команды createsuperuser. После этого на экране появится интерфейс администратора.

Завершив проверку, остановите сервер разработки, нажав CTRL-C в окне терминала.

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

Тестирование Gunicorn

Теперь нужно проверить, может ли веб-сервер Gunicorn обслуживать приложение. Введите:

cd ~/myproject
gunicorn --bind 0.0.0.0:8000 myproject.wsgi:application

Эта команда запустит Gunicorn в том же интерфейсе, в котором до этого работал сервер разработки Django. Вернитесь и снова протестируйте приложение.

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

Чтобы передать серверу Gunicorn модуль, нужно указать путь к каталогу файла wsgi.py, который является точкой входа в приложение. Внутри этого файла находится функция application, которая используется для связи с приложением.

Примечание: Чтобы узнать больше о спецификации WSGI, читайте эту статью.

Завершив тестирование, нажмите в окне терминала CTRL-C, чтобы остановить сервер Gunicorn.

Теперь приложение Django готово. Отключите виртуальную среду:

deactivate

5: Создание сервиса systemd для Gunicorn

После этого нужно создать файл сервиса для системы инициализации systemd. Такой файл позволяет системе инициализации автоматически запускать Gunicorn и обслуживать приложение.

Создайте и откройте файл для Gunicorn с расширением .service в каталоге /etc/systemd/system:

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

Добавьте раздел [Unit], который определяет метаданные и зависимости приложения. Внесите в него описание сервиса.

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

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

Затем нужно указать полный путь к исполняемому файлу Gunicorn, чтобы система инициализации знала, где искать эти файлы (в виртуальной среде). Systemd требует полного пути к исполняемым файлам Gunicorn в виртуальной среде.

Система будет запускать три рабочих процесса (измените это в случае необходимости). Она подключится к socket-файлу Unix в каталоге проекта (такой вариант быстрее и надёжнее сетевых портов). Также здесь можно указать любые дополнительные настройки Gunicorn.

[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=8host
Group=www-data
WorkingDirectory=/home/8host/myproject
ExecStart=/home/8host/myproject/venv/bin/gunicorn --workers 3 --bind unix:/home/8host/myproject/myproject.sock myproject.wsgi:application

В конец файла нужно добавить раздел [Install], который определяет, к чему должен подключиться сервис во время автозапуска.

[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=8host
Group=www-data
WorkingDirectory=/home/8host/myproject
ExecStart=/home/8host/myproject/venv/bin/gunicorn --workers 3 --bind unix:/home/8host/myproject/myproject.sock myproject.wsgi:application
[Install]
WantedBy=multi-user.target

Итак, сервис systemd готов. Сохраните и закройте файл.

Запустите сервис Gunicorn и включите его автозапуск.

sudo systemctl start gunicorn
sudo systemctl enable gunicorn
Created symlink from /etc/systemd/system/multi-user.target.wants/gunicorn.service to /etc/systemd/system/gunicorn.service.

Проверьте состояние сервиса:

sudo systemctl status gunicorn
gunicorn.service - gunicorn daemon
Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled)
Active: active (running) since Wed 2016-12-21 21:05:07 UTC; 49s ago
Main PID: 10154 (gunicorn)
CGroup: /system.slice/gunicorn.service
├─10154 /home/8host/myproject/venv/bin/python3 /home/8host/myproject/venv/bin/gunicorn --workers 3 --bind unix:/home/8host/myproject/myproject.sock myproject.wsgi:application
├─10157 /home/8host/myproject/venv/bin/python3 /home/8host/myproject/venv/bin/gunicorn --workers 3 --bind unix:/home/8host/myproject/myproject.sock myproject.wsgi:application
├─10158 /home/8host/myproject/venv/bin/python3 /home/8host/myproject/venv/bin/gunicorn --workers 3 --bind unix:/home/8host/myproject/myproject.sock myproject.wsgi:application
└─10159 /home/8host/myproject/venv/bin/python3 /home/8host/myproject/venv/bin/gunicorn --workers 3 --bind unix:/home/8host/myproject/myproject.sock myproject.wsgi:application
Dec 21 21:05:07 debian-512mb-nyc3-01 systemd[1]: Started gunicorn daemon.
Dec 21 21:05:07 debian-512mb-nyc3-01 gunicorn[10154]: [2016-12-21 21:05:07 +0000] [10154] [INFO] Starting gunicorn 19.6.0
Dec 21 21:05:07 debian-512mb-nyc3-01 gunicorn[10154]: [2016-12-21 21:05:07 +0000] [10154] [INFO] Listening at: unix:/home/8host/myproject/myproject.sock (10154)
Dec 21 21:05:07 debian-512mb-nyc3-01 gunicorn[10154]: [2016-12-21 21:05:07 +0000] [10154] [INFO] Using worker: sync
Dec 21 21:05:07 debian-512mb-nyc3-01 gunicorn[10154]: [2016-12-21 21:05:07 +0000] [10157] [INFO] Booting worker with pid: 10157
Dec 21 21:05:07 debian-512mb-nyc3-01 gunicorn[10154]: [2016-12-21 21:05:07 +0000] [10158] [INFO] Booting worker with pid: 10158
Dec 21 21:05:07 debian-512mb-nyc3-01 gunicorn[10154]: [2016-12-21 21:05:07 +0000] [10159] [INFO] Booting worker with pid: 10159

Состояние сервиса должно быть active.

Теперь нужно проверить файл сокета. Запросите содержимое каталога ~/myproject. В нем должен быть такой файл.

ls -l ~/myproject
total 16
-rwxr-xr-x 1 8host 8host     807 Dec 21 20:46 manage.py
drwxr-xr-x 3 8host 8host    4096 Dec 21 20:54 myproject
srwxrwxrwx 1 8host www-data    0 Dec 21 21:05 myproject.sock
drwxr-xr-x 3 8host 8host    4096 Dec 21 20:54 static
drwxr-xr-x 5 8host 8host    4096 Dec 21 20:41 venv

Как видите, такой файл существует. Он принадлежит группе www-data.

6: Настройка обратного прокси-сервера Nginx

Теперь приложение Gunicorn готово. Настройте Nginx для передачи трафика приложения.

Создайте новый блок server (виртуальный хост) в каталоге sites-available:

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

Добавьте в файл блок server. Задайте порт, который должен прослушивать веб-сервер (в данном случае – стандартный порт 80) и укажите доменное имя или IP в директиве server_name.

server {
listen 80;
server_name server_domain_or_IP;
}

Веб-сервер Nginx должен игнорировать проблемы с фавиконом. Затем нужно указать местонахождение статических файлов, собранных в каталоге ~/myproject/static. У всех этих файлов стандартный префикс URI (/static), потому можно создать блок location для обслуживания этих запросов.

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

Теперь создайте блок location / {} для всех остальных запросов. Добавьте в него стандартный файл proxy_params, который входит в установку Nginx, и направьте трафик на сокет Gunicorn.

server {
listen 80;
server_name server_domain_or_IP;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/8host/myproject;
}
location / {
include proxy_params;
proxy_pass http://unix:/home/8host/myproject/myproject.sock;
}
}

Сохраните и закройте файл.

Чтобы включить файл, создайте символьную ссылку на каталог sites-enabled.

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

Проверьте синтаксис Nginx на наличие ошибок:

sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Если ошибок нет, перезапустите Nginx:

sudo systemctl restart nginx

Теперь вы можете просмотреть приложение в браузере, открыв IP-адрес или домен и указав порт 80.

Поскольку порт сервера разработки (8000) больше не используется, его нужно заблокировать.

Если вы используете ufw, введите:

sudo ufw delete allow 8000
sudo ufw allow 'WWW'

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

sudo iptables -D INPUT -p tcp --dport 8000 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 80 -j ACCEPT

Теперь откройте в браузере доменное имя или IP, чтобы просмотреть приложение.

Примечание: После настройки обратного прокси-сервера Nginx настоятельно рекомендуется защитить подключения при помощи сертификатов SSL/TLS. В противном случае все данные будут передаваться в виде простого текста и легко могут быть перехвачены злоумышленниками. Сервис Let’s Encrypt позволяет получить бесплатный сертификат. Подробнее об этом – в этом руководстве.  Чтобы создать самоподписанный сертификат, читайте эту статью.

Заключение

Теперь на сервере хранится Django-проект в собственной виртуальной среде. Gunicorn может преобразовывать запросы в понятный Django формат. Веб-сервер Nginx настроен в качестве обратного прокси-сервера для обработки клиентских подключений.

Полученное тестовое приложение можно использовать в качестве шаблона для разработки более сложного приложения.

Tags: , , , , , , ,

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *


*

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>