Как стать автором
Обновить

Виртуальный хостинг Django, модель N

Время на прочтение 5 мин
Количество просмотров 5.8K
Существует множество способов разворачивания Django-приложений в *nix-среде. Не буду претендовать на оригинальность, просто поделюсь самым-самым-самым-самым своим.

Вводные условия


Предпосылки:
  • Один клиент (заказчик) — один юзер в системе на сервере.
  • Все проекты клиента — в одной файловой иерархии.
  • Virtualenv — это хорошо и must use.
  • Ftp — зло, используем современные средства (sftp).
  • Количество файлов для управления проектами должно быть сведено к минимуму.
Используемый софт:
  • nginx
  • uwsgi
  • cron
  • virtualenv
  • openssh


И нефиг тут шариться


Часто бывает так, что наряду с разработчиками к файловому дереву своих проектов желают иметь доступ также и пользователи/клиенты/заказчики (называть можно как угодно), т.е. «почти» сторонние люди. А значит ограничить сторонних пользователей в возможности шариться по дискам сервера — неплохая идея. На первый взгляд приходит идея ограничить пользователя своей домашней директорией. Не стоит поддаваться этому порыву, ведь в своей домашней директории пользователь царь и бог, и одно неверное движение и ты отец может привести к неработоспособности проекта. Поэтому пойдем на хитрость и создадим следующую иерархию:
/home
  /client -- директория с проектами данного клиента
    /client -- домашняя директория пользователя "client"
    /another_project
    /project
      /www-root
      /static
      /app1
      /app2
      manage.py
      settings.py
      django_wsgi.py
      ...
    /var
      /log -- логи nginx'a, не забыть включить ее в logrotate
      /tmp -- chmod 770 -- временные файлы проекта
      /run -- тут будут пиды и сокеты
  /client2 -- директория с проектами другого клиента
  /client3 -- директория с проектами еще одного клиента

домашняя директория пользователя «client» имеет права client:client, остальные директории, если это особо не оговорено, root:client и chmod 750 соответвтенно. В группу client также надо включить пользователя nginx для того, чтобы nginx имел право доступа к статическим файлам внутри проекта. Также в системе создаем группу sftponly в которую включаем клиентов. В конфиг sshd (/etc/ssh/sshd_config) добавляем следующее:
Match Group sftponly
        X11Forwarding no
        AllowAgentForwarding no
        AllowTcpForwarding no
        ChrootDirectory /home/%u
        ForceCommand internal-sftp
и строчку
Subsystem      sftp    /usr/lib/misc/sftp-server
заменяем на
Subsystem       sftp    internal-sftp

В итоге мы получаем ситуацию, когда пользователь, зайдя на сервер по sftp (допустим используя winscp) попадает в свою домашнюю директорию, может подняться на один уровень вверх, шастать по своим проектам, смотреть логи. Однако подняться выше или удалить какую либо важную директорию он не в силах (chmod 750 однако).

nginx — как много в этом слове


Nginx — пожалуй лучший из http-серверов для отдачи статического контента и разруливания вопросов связанных с генерацией динамического. В нашем случае nginx должен быть собран вместе с uwsgi-модулем (идет в штатной поставке). При установке по умолчанию (по крайней мере в gentoo) nginx хранит свои конфиги в /etc/nginx. Не будем нарушать эту традицию, и даже наоборот попытаемся ей воспользоваться. В основной конфиг nginx'a (/etc/nginx/nginx.conf) в конец секции http нужно добавить строчку
include /etc/nginx/vhost.d/*.conf ;
в результате чего мы сможем иметь по одному конфиругационному файлу (/etc/nginx/vhost.d/project.conf) на проект.
Примерно по такому:
#uwsgi# USER    client
#uwsgi# PRJ     cool_site.ru
#uwsgi# HOME    ~/../project
#uwsgi# VE      ~/.virtualenvs/project
#uwsgi# SOCKET  ../var/run/uwsgi-project
#uwsgi# LOG     ../var/log/uwsgi-project.log
#uwsgi# PID     ../var/run/uwsgi-project.pid
#uwsgi# WORKERS 2

upstream wsgi_cluster__project {
    server unix:/home/client/var/run/uwsgi-project;
}

server {
    listen      80;
    server_name .cool_site.ru;
    charset     utf8;
    autoindex   off;
    root        /home/client/project/www-root;
    access_log  /home/client/var/log/nginx_access.log ;
    error_log   /home/client/var/log/nginx_error.log error;

    location /static {
        root           /home/client/project;
        expires       1d;
    }
    location / {
        try_files       $uri    @django;
    }
    location @django {
        uwsgi_pass   wsgi_cluster__project;
        include        uwsgi_params;
    }
}
Строчки, начинающиеся с #uwsgi# будут восприниматься nginx'ом как комментарии, однако стартовый скрипт nust (о котором речь ниже) смотрит на эти строчки, считая их директивами для себя.

nust — Nginx Uwsgi STarter


Когда-то, когда uwsgi только начал появляться, умел падать в процессе эксплуатации, не имел «императорского» режима, но уже был чертовски востребован — на скорую руку был написан скрипт, переписать который по нормальному руки так и не дошли по одной единственной причине — он работает. Итак, как он работает и что он делает.
Nust запускается по крону (crontab -e)
*/5  * * * *    nust -s -c /etc/nust.conf
со своим файлом конфигурации. Файл конфигурации имеет две секции, первая из которых относится непосредственно к nust'y и определяет пути и утилиты, которые им используются, а вторая — умолчания для uwsgi.
[nust]
pstree = /usr/bin/pstree
vhosts = /etc/nginx/vhost.d/*.conf
uwsgi  = /usr/bin/uwsgi
uwsgi_def_args  = --ini=/etc/nust.conf
dbdir  = /var/run
kill   = /bin/kill -s TERM
kill_k9= /bin/kill -s KILL

[uwsgi]
master=
disable-logging=
vacuum=
logfile-chown=
chmod-socket=666
catch-exceptions=
memory-report=

Проинсталлировать nust в систему можно следующим образом:
sudo pip install nust

В конфиге nginx'a с помощью «фигурного комментария» #uwsgi# можно переопределить следующие опции:
  • WORKERS — количество параллельных рабочих процессов
  • MODULE — имя стартуемого python-модуля (django_wsgi.py)
  • PRJ — имя проекта
  • PID — pid-файл дерева рабочих процессов (var/run/uwsgi.pid)
  • LOG — путь к лог-файлу uwsgi (var/log/uwsgi.log)
  • HARAKIRI — максимальное время выполнения запроса, сек.
  • MAX_REQ — количество обрабатываемых запросов, после которых рабочий процесс будет перезапущен
А вот эти опции являются обязательными:
  • USER — пользователь из под которого будет запущен проект
  • HOME — домашняя директория проекта (НЕ ПОЛЬЗОВАТЕЛЯ!)
  • VE — путь к виртуальному окружению (результату работы virtualenv)
  • SOCKET — где создавать файл-сокет. Если не задан, то будет взят из секции upstream.
Пути могут указываться тремя способами:
  • абсолютный путь, начинается со слэша
    (/tmp)
  • путь относительно домашней директории пользователя
    (~/gde-to/tam/)
  • путь относительно домашней директории проекта
    (var/run/uwsgi.pid)

Для старта какого-либо питоновского кода под uwsgi нужен так называемый модуль. Для запуска django подойдет следующий код, размещенный в django_wsgi.py:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

Прописывать запуск nust'a в стартовые скрипты системы нет необходимости, так как nust запускается по крону периодически. Помимо просто старта проектов nust следит за их состоянием (упал, не запущен, запущен, но не пингуется), а также за состоянием конфигов виртуальных хостов nginx'a. Если конфиг виртуального хоста был изменен, то соответствующий ему проект будет перезапущен.

Вместо послесловия


Ну вот собственно и все. Надеюсь не забыл ничего важного. Спасибо за внимание.
Теги:
Хабы:
+26
Комментарии 14
Комментарии Комментарии 14

Публикации

Истории

Работа

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн