Развертывание Django на nginx + uwsgi

Attention!

На данный момент блог не использует Django, как, впрочем, и любой другой фреймворк. Данный блог полностью перешел на статические генераторы веб-контента.

DJangon + Nginx + uWSGI

Первый дни августа принесли изменения в мой блог/сайт. Со стороны, кроме изменения внешнего вида, это может быть и не заметно, но на самом деле это не так. Во-первых, был приобретен домен kalnitsky.org. Во-вторых, сайт был написан с использованием оригинального Django, а не Django-Nonrel для запуска на GAE. И, наконец, в-третьих, блог теперь располагается на серверах ITL.

Для всего этого был приобретен VDS (Virtual Dedicated Server). И в этой статье я хочу рассказать о том, как можно легко поднять Django приложение на VDS. Сразу хочу отметить, что статья не покажет "как лучше" или "как правильней" сделать. Я лишь покажу один из возможных путей решений.

0. Выбор системы

На VDS я установил Debian 6 amd64 Minimal. Моей домашней ОС выступает Debian, поэтому, я думаю, нет ничего удивительного в том, что в качестве серверной ОС я выбрал именно её. Minimal же выбрал для того, чтобы не было предустановленных apache, mysql и иже с ними.

Итак, система выбрана и поставлена. Теперь можно подключаться по ssh.

1. Создание пользователя

По-умолчанию на нашей системе создан только root-пользователь. Я не привык работать от имени этого пользователя и не советую кому другому привыкать.

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

adduser username

где username — имя создаваемого пользователя.

Это команда попросит дважды ввести вас пароль, а также ввести некоторую дополнительную информацию: полное имя, телефон и т.д.

Warning

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

Пользователь создан, но хотелось бы иметь возможность выполнять комманды от root. Для этого установим утилиту sudo.

aptitude install sudo

Теперь запускаем visudo и под строкой:

root    ALL=(ALL:ALL) ALL

добавляем строку:

username    ALL=(ALL:ALL) ALL

А также после строки:

Defaults env_reset

добавляем строку:

Defaults env_keep += HOME

Сохраняемся и выходим. Теперь можно смело подключаться по ssh от имени созданного нами пользователя. Мой пользователь носит имя igor и далее я буду использовать именно это имя во всех путях.

2. Структура проекта

Для удобства последующего администрирования, было бы неплохо определится со структурой проекта. Проект я храню в домашнем каталоге пользователя /home/igor/ и имеет он следующую структуру:

+ /home
|-+ /igor
  |-+ /kalnitsky.org
    |-+ /conf
    |-+ /logs
    |-+ /www

В каталоге /home/igor/kalnitsky.org хранится веб-сайт, включающий как файлы скрипта, так и конфигурационные файлы с файлами логов. Django проект у меня лежит в подкаталоге www.

3. Развертывание Django-проекта

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

Почему я выбрал nginx? Потому что он:

  1. является легковесным быстрым веб-сервером;
  2. поддерживает WSGI (через uWSGI).

WSGI (Web Server Gateway Interface) — это стандарт взаимодействия между Python-программой, выполняющейся на стороне сервера, и самим веб-сервером.

uWSGI — это WSGI сервер, который запускает python-приложение, и позволяет сообщать его с nginx-сервером.

Собственно, необходимый инструментарий определен: nginx + uWSGI.

К сожалению, репозиторий Debian 6 содержит в себе nginx старой версии, который нам никак не подходит из-за отсутствия модуля, позволяющего сообщаться с uWSGI. Поэтому, надо либо обновиться до Debian Wheezy, либо собирать его из исходников. Я предпочитаю обновление до Debian Wheezy, так как это не только упростить жизнь в дальнейшем, но и преподнесет более свежее ПО (в частности, python 2.7).

Для подключения репозиториев Debian Wheezy необходимо отредактировать файл /etc/apt/sources.list и добавить в него следующие строчки:

deb http://ftp.debian.org/debian/ wheezy main contrib non-free
deb http://security.debian.org wheezy/updates main contrib non-free

Далее обновляем индекс и ПО:

sudo aptitude update
sudo aptitude upgrade

4. Установка nginx

Итак, до Debian Wheezy мы обновились, а, следовательно, установка nginx теперь будет крайне проста:

sudo aptitude install nginx

5. Установка uWSGI

uWSGI не включен в репозитарий Debian Wheezy, но установить последнию версию можно из PyPI. Установка из PyPI осуществляется с помощью утилиты pip. Очевидно, установка uwsgi сводится к выполнению двух комманд:

sudo aptitude install python-pip build-essential python-dev libxml2-dev
sudo pip install uwsgi

6. Конфигурация nginx

Создадим файл конфигурации для нашего проекта. У меня это /home/igor/kalnitsky.org/conf/nginx.conf. В файл конфигурации вставьте следующее:

server {
    listen        80;
    listen        443;

    # указываем свой домен
    server_name   kalnitsky.org www.kalnitsky.org;

    # здесь мы задаем абсолютные пути к логам.
    # как я упоминал уже выше, каталог с логами у меня хранится в каталоге
    # с проектом, поэтому пути следующие:
    access_log    /home/igor/kalnitsky.org/logs/nginx_access.log;
    error_log     /home/igor/kalnitsky.org/logs/nginx_error.log;

    # ниже указывается каталог с django-проектом. как я указывал выше,
    # я храню его в подкаталоге www, поэтому путь такой:
    root          /home/igor/kalnitsky.org/www/;

    location /
    {
        # ниже надо указать путь к socket'у, при помощи которого
        # nginx и uwsgi будут сообщаться.
        # в данном случае путь это '/var/tmp/kalnitsky_uwsgi.sock'
        uwsgi_pass unix:///var/tmp/kalnitsky_uwsgi.sock;
        include uwsgi_params;

        # 8 — число буфферов
        # 128k — размер буфера
        # фактически, мы сможем передать от Django в nginx только 1 мб информации.
        # играйтесь с этим значением при поднятии своего проекта
        uwsgi_buffers 8 128k;
    }

    # ниже описывается директория со статическими файлами проекта (css,js,etc)
    # / — это STATIC_URL, который вы должны посмотреть в
    # в settings.py своего django проекта.
    location / {
        # а вот здесь указываем абсолютный путь к директории со
        # статическими файлами
        alias /home/igor/kalnitsky.org/www/;
        expires 30d;
    }
}

nginx подключает все файлы конфигурации находящиеся в каталоге /etc/nginx/sites-enabled/, поэтому необходимо поместить созданный нами файл конфигурации в этот каталог. Но поместим мы его не копированием, а созданием ссылки.

sudo ln ~/kalnitsky.org/conf/nginx.conf /etc/nginx/sites-enabled/

7. Конфигурация uWSGI

uWSGI конфигурируется проще. Создадим файл конфигураций uwsgi.yaml (у меня он находится в /home/igor/kalnitsky.org/conf/uwsgi.yaml) со следующим содержанием:

uwsgi:
    # указываем socket, при помощи которого будет происходить
    # взаимодействие между nginx и uwsgi
    socket: /var/tmp/kalnitsky_uwsgi.sock
    # здесь указываем путь к django-проекту
    pythonpath: /home/igor/kalnitsky.org/www
    # устанавливаем переменную окружения, которая хранит имя settings файла
    env: DJANGO_SETTINGS_MODULE=settings
    # это имя модуля, который будет запускаться на выполнение
    # в такой постановке, будет запускаться wsgi.py из директории
    # указанной выше в 'pythonpath'
    module: wsgi
    # путь к лог файлу
    daemonize: /home/igor/kalnitsky.org/logs/uwsgi.log
    # прочие настройки, значения который можно посмотреть на сайте uWSGI
    max-requests: 5000
    buffer-size: 32768
    harakiri: 30
    reload-mercy: 8
    master: 1
    no-orphans: 1
    # если выполнить команду "touch <имя ниже указанного файла>",
    # то произойдет перезапуск uwsgi демона.
    touch-reload: /home/igor/kalnitsky.org/uwsgi

Следующий шаг можно опустить, но он призван помочь при перезагрузках системы. nginx стартует вместе со стартом системы, а вот uwsgi — нет, и это нехорошо. Вообще было бы хорошо сделать init-скрипт, но очень часть с этим могут возникнуть проблема (например, у мена из-за vzquota). Поэтому я решил организовать автозагрузку с помощью cron — планировщика задач в unix-подобных операционных системах.

Для того чтобы добавить uwsgi в автозагрузку с помощью cron, необходимо добавить в файл /etc/crontab следующие строки:

# run uWSGI instances
@reboot root    uwsgi -y /home/igor/kalnitsky.org/conf/uwsgi.yaml

Конфиг описан, осталось написать wsgi.py и положить его в каталог указанный в pythonpath (i.g., в /home/igor/kalnitsky.org/www). wsgi.py выглядит до безумия просто:

import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

Warning

Начиная с Django 1.4, wsgi.py генерируется автоматически при создании нового проекта.

8. Мы топали-топали, и, наконец, притопали...

Ну вот кажется и все. Теперь остается с остановленным дыханием перезагрузить nginx и запустить uwsgi:

sudo service nginx restart
sudo uwsgi -y ~/kalnitsky.org/conf/uwsgi.yaml

А теперь заходим по веб-адресу сайта и проверяем работоспособность системы. :)

P.S Если у кого возникли какие вопросы — не стесняйтесь задавать их в комментариях. Критика тоже здраво оценивается, ибо я не админ — и мог где-то поступить несколько неверно. :)