Существует множество способов разворачивания Django-приложений в *nix-среде. Не буду претендовать на оригинальность, просто поделюсь самым-самым-самым-самым своим.
Предпосылки:
Часто бывает так, что наряду с разработчиками к файловому дереву своих проектов желают иметь доступ также и пользователи/клиенты/заказчики (называть можно как угодно), т.е. «почти» сторонние люди. А значит ограничить сторонних пользователей в возможности шариться по дискам сервера — неплохая идея. На первый взгляд приходит идея ограничить пользователя своей домашней директорией. Не стоит поддаваться этому порыву, ведь в своей домашней директории пользователь царь и бог, и одно неверное движениеи ты отец может привести к неработоспособности проекта. Поэтому пойдем на хитрость и создадим следующую иерархию:
домашняя директория пользователя «client» имеет права client:client, остальные директории, если это особо не оговорено, root:client и chmod 750 соответвтенно. В группу client также надо включить пользователя nginx для того, чтобы nginx имел право доступа к статическим файлам внутри проекта. Также в системе создаем группу sftponly в которую включаем клиентов. В конфиг sshd (/etc/ssh/sshd_config) добавляем следующее:
В итоге мы получаем ситуацию, когда пользователь, зайдя на сервер по sftp (допустим используя winscp) попадает в свою домашнюю директорию, может подняться на один уровень вверх, шастать по своим проектам, смотреть логи. Однако подняться выше или удалить какую либо важную директорию он не в силах (chmod 750 однако).
Nginx — пожалуй лучший из http-серверов для отдачи статического контента и разруливания вопросов связанных с генерацией динамического. В нашем случае nginx должен быть собран вместе с uwsgi-модулем (идет в штатной поставке). При установке по умолчанию (по крайней мере в gentoo) nginx хранит свои конфиги в /etc/nginx. Не будем нарушать эту традицию, и даже наоборот попытаемся ей воспользоваться. В основной конфиг nginx'a (/etc/nginx/nginx.conf) в конец секции http нужно добавить строчку
Примерно по такому:
Когда-то, когда uwsgi только начал появляться, умел падать в процессе эксплуатации, не имел «императорского» режима, но уже был чертовски востребован — на скорую руку был написан скрипт, переписать который по нормальному руки так и не дошли по одной единственной причине — он работает. Итак, как он работает и что он делает.
Nust запускается по крону (crontab -e)
Проинсталлировать nust в систему можно следующим образом:
В конфиге nginx'a с помощью «фигурного комментария» #uwsgi# можно переопределить следующие опции:
Для старта какого-либо питоновского кода под uwsgi нужен так называемый модуль. Для запуска django подойдет следующий код, размещенный в django_wsgi.py:
Прописывать запуск nust'a в стартовые скрипты системы нет необходимости, так как nust запускается по крону периодически. Помимо просто старта проектов nust следит за их состоянием (упал, не запущен, запущен, но не пингуется), а также за состоянием конфигов виртуальных хостов nginx'a. Если конфиг виртуального хоста был изменен, то соответствующий ему проект будет перезапущен.
Ну вот собственно и все. Надеюсь не забыл ничего важного. Спасибо за внимание.
Вводные условия
Предпосылки:
- Один клиент (заказчик) — один юзер в системе на сервере.
- Все проекты клиента — в одной файловой иерархии.
- 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. Если конфиг виртуального хоста был изменен, то соответствующий ему проект будет перезапущен.
Вместо послесловия
Ну вот собственно и все. Надеюсь не забыл ничего важного. Спасибо за внимание.