Возможно кому-то пригодится мой опыт настройки хостинга множества Django-приложений. Всё нижеизложенное я проводил на операционной системе Gentoo.
Итак, для начала необходимо установить следующие пакеты:
1. Создаём пользователя под которым будут работать django-процессы (uwsgi и файлы на диске):
useradd -m django
1.1. Заходим под ним:
su django
2. Создадим в его домашней директории /home/django 3 папки:
mkdir ~/env ~/projects ~/vassals
3. Разворачиваем исходники проектов в папку ~/projects. Мы используем bitbucket.org для хранения и разработки наших проектов. Если вы используете иную схему - разворачиваете каждый проект в отдельной подпапке и переходите к п. 4. Далее я описываю как это делать с bitbucket.org.
3.1. Сгенерируем id_rsa.pub ключ для доступа по ssh к bitbucket:
ssh-keygen
3.2. Добавим содержимое ~/.ssh/id_rsa.pub в настройки профиля юзвера на bitbucket (ssh keys)
3.3. Клонируем пакеты к себе
cd ~/projects
hg clone ssh://hg@bitbucket.org/my_super_nickname/project1
hg clone ssh://hg@bitbucket.org/my_super_nickname/project2
4. Создадим виртуальные окружения для наших проектов в папке ~/env. Будьте внимательны на этом этапе, т.к. нужно чётко выбрать для каждого окружения правильную версию Python (т.е. версию на которой это разрабатывалось и тестировалось). В принципе, ничего страшного если ошиблись - просто удалите потом подпапку ~/env/<название проекта> и создайте по-новой.
4.1. Инициализируем виртуальные окружения:
export WORKON_HOME=~/env
mkdir -p $WORKON_HOME
source /usr/bin/virtualenvwrapper.sh
4.2. Добавим 2 строки инициализации в профиль пользователя django:
echo 'export WORKON_HOME=~/env' >> ~/.bashrc
echo 'source /usr/bin/virtualenvwrapper.sh' >> ~/.bashrc
Это нужно для того чтобы при логине под юзвером django у нас восстанавливался "скелет" для виртуальных окружений. Актуально потом, когда ваши проекты будут меняться и, соответственно, могут меняться их требования (новые или иных версий python-пакеты, смена версии Python).
4.3. Собственно, создаём окружения для каждого проекта:
mkvirtualenv project1
deactivate
mkvirtualenv project2
deactivate
4.4. TIP: Для того чтобы перейти в конкретное окружение (например, для manage.py collectstatic или pip install) - надо выполнить комманду:
workon <имя проекта>
где <имя проекта> - название нужного окружения.
5. Переходим в папку с клонированным проектом:
cd ~/projects/project1
5.1. Активируем окружение согласно п. 4.4.
6. Устанавливаем требуемые для проекта пакеты питона:
pip install -r requirements.txt
Возможно, вы ставите пакеты для Django-проекта иначе (например, через pip install project1.bundle).
6.1. Повторяем это для каждого проекта, начиная с п. 4.4.
7. Для сервера uWSGI, в папке ~/vassals создадим для каждого проекта по файл:
cd ~/vassals
touch project1.ini
touch project2.ini
7.1. Содержимое каждого из файлов - одинаковое (благодаря макро-подстановке %n равной basename файла):
[uwsgi]
virtualenv = /home/django/env/%n
chdir = /home/django/projects/%n
plugins = python27
pythonpath = ..
socket = /var/run/uwsgi/%n.sock
logto = /var/log/uwsgi/%n.log
env = DJANGO_SETTINGS_MODULE=%n.settings
module = django.core.handlers.wsgi:WSGIHandler()
buffer-size = 32768
Внимание! Папки /var/run/uwsgi и /var/log/uwsgi должны быть доступны на запись пользователю django. В первой будут лежать сокеты для связи uWSGI и nginx, во второй - логи uWSGI по каждому проекту. Также обратите внимание на строчку plugins = python27 - здесь должна быть указана версия питона используемая в проекте.
8. Выходим обратно под пользователя root, чтобы отредактировать настройки uWSGI (для Gentoo, они расположены в /etc/conf.d/uwsgi). Приводим к следующему виду:
UWSGI_SOCKET=
UWSGI_THREADS=1
UWSGI_PROGRAM=
UWSGI_XML_CONFIG=
UWSGI_PROCESSES=1
UWSGI_LOG_FILE=
UWSGI_DIR=
UWSGI_USER=django
UWSGI_EMPEROR_PATH=/home/django/vassals
UWSGI_EXTRA_OPTIONS=
9. Необходимо создать папки /var/run/uwsgi, /var/log/uwsgi и сделать их владельцами пользователя django:
mkdir /var/run/uwsgi
mkdir /var/log/uwsgi
chown -R django:django /var/run/uwsgi /var/log/uwsgi
10. Добавляем uwsgi в автозагрузку и запускаем:
rc-update add uwsgi default
/etc/init.d/uwsgi start
11. И самое простое - поставим и настроим nginx. Тут самое главное - указать, что имя пользователя под которым запускается nginx. Обычно это системный пользователь www-data или nginx. Этот пользователь должен быть в одной группе с django-пользователем чтобы иметь доступ к статическим файлам (возможно даже на запись). Конфиг /etc/nginx/nginx.conf должен быть примерно такого содержания:
user nginx;
worker_processes 1;
error_log /var/log/nginx/error_log info;
events {
worker_connections 1024;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main
'$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio"';
client_header_timeout 10m;
client_body_timeout 10m;
send_timeout 10m;
connection_pool_size 256;
client_header_buffer_size 1k;
large_client_header_buffers 4 16k;
request_pool_size 4k;
gzip on;
gzip_min_length 1100;
gzip_buffers 4 8k;
gzip_types text/plain;
output_buffers 1 32k;
postpone_output 1460;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 75 20;
ignore_invalid_headers on;
index index.html;
include /etc/nginx/vhosts.d/*.conf;
}
12.1 Создадим подпапку /etc/nginx/vhosts.d и в ней по файлу для каждого проекта:
mkdir /etc/nginx/vhosts.d
cd /etc/nginx/vhosts.d
touch project1.conf
touch project2.conf
Вот содержимое project1.conf (для project2.conf он аналогичен):
upstream wsgi_project1 {
server unix:/var/run/uwsgi/project1.sock;
}
server {
listen 80;
server_name <доменное имя нашего сайта> default; << default означает, что если будут обращаться по IP к нашему серверу - то именно этот сайт будет там
charset utf8;
autoindex off;
access_log /var/log/nginx/project1_access.log;
error_log /var/log/nginx/project1_error.log error;
set $project_home /home/django/projects/project1;
location /images {
root $project_home/static;
expires 1d;
}
location /css {
root $project_home/static;
expires 1d;
}
location /js {
root $project_home/static;
expires 1d;
}
location /static {
root $project_home;
expires 1d;
}
location / {
try_files $uri @django;
}
location @django {
uwsgi_pass wsgi_project1;
include uwsgi_params;
}
}
12.2 Добавим nginx в автозагрузку и запустим его:
rc-update add nginx default
/etc/init.d/nginx start
Это пока всё. Если у кого-то будут замечания и дополнения - оставляйте их в комментариях. Вместе мы победим =)
Итак, для начала необходимо установить следующие пакеты:
- www-servers/uwsgi (нужно добавить в /etc/portage/package.keywords, т.к. сообщество Gentoo считает его нестабильным =)
- www-servers/nginx (с включённым USE-флагом nginx_modules_http_uwsgi)
- dev-lang/python (нужной вам версии, можно иметь несколько версий одновременно, переключая их с помощью eselect python)
- dev-python/virtualenv
- dev-python/virtualenvwrapper
1. Создаём пользователя под которым будут работать django-процессы (uwsgi и файлы на диске):
useradd -m django
1.1. Заходим под ним:
su django
2. Создадим в его домашней директории /home/django 3 папки:
mkdir ~/env ~/projects ~/vassals
- env - для виртуальных окружений, чтобы у каждого проекта были свои версии пакетов не мешающие другим проектам (например, для одного можно использовать python 2.7, для другого python 3.2 и т.п.);
- projects - для проектов;
- vassals - для uWSGI с настройками запуска в режиме emperor (это такой интересный режим, когда запускается 1 монитор-сервис uWSGI и по процессу на каждый найденный конфиг в этой папке. Что самое замечательное - uWSGI может динамически запускать новый процесс при обнаружении в этой папке нового конфига без перезапуска монитор-сервиса).
3. Разворачиваем исходники проектов в папку ~/projects. Мы используем bitbucket.org для хранения и разработки наших проектов. Если вы используете иную схему - разворачиваете каждый проект в отдельной подпапке и переходите к п. 4. Далее я описываю как это делать с bitbucket.org.
3.1. Сгенерируем id_rsa.pub ключ для доступа по ssh к bitbucket:
ssh-keygen
3.2. Добавим содержимое ~/.ssh/id_rsa.pub в настройки профиля юзвера на bitbucket (ssh keys)
3.3. Клонируем пакеты к себе
cd ~/projects
hg clone ssh://hg@bitbucket.org/my_super_nickname/project1
hg clone ssh://hg@bitbucket.org/my_super_nickname/project2
4. Создадим виртуальные окружения для наших проектов в папке ~/env. Будьте внимательны на этом этапе, т.к. нужно чётко выбрать для каждого окружения правильную версию Python (т.е. версию на которой это разрабатывалось и тестировалось). В принципе, ничего страшного если ошиблись - просто удалите потом подпапку ~/env/<название проекта> и создайте по-новой.
4.1. Инициализируем виртуальные окружения:
export WORKON_HOME=~/env
mkdir -p $WORKON_HOME
source /usr/bin/virtualenvwrapper.sh
4.2. Добавим 2 строки инициализации в профиль пользователя django:
echo 'export WORKON_HOME=~/env' >> ~/.bashrc
echo 'source /usr/bin/virtualenvwrapper.sh' >> ~/.bashrc
Это нужно для того чтобы при логине под юзвером django у нас восстанавливался "скелет" для виртуальных окружений. Актуально потом, когда ваши проекты будут меняться и, соответственно, могут меняться их требования (новые или иных версий python-пакеты, смена версии Python).
4.3. Собственно, создаём окружения для каждого проекта:
mkvirtualenv project1
deactivate
mkvirtualenv project2
deactivate
4.4. TIP: Для того чтобы перейти в конкретное окружение (например, для manage.py collectstatic или pip install) - надо выполнить комманду:
workon <имя проекта>
где <имя проекта> - название нужного окружения.
5. Переходим в папку с клонированным проектом:
cd ~/projects/project1
5.1. Активируем окружение согласно п. 4.4.
6. Устанавливаем требуемые для проекта пакеты питона:
pip install -r requirements.txt
Возможно, вы ставите пакеты для Django-проекта иначе (например, через pip install project1.bundle).
6.1. Повторяем это для каждого проекта, начиная с п. 4.4.
7. Для сервера uWSGI, в папке ~/vassals создадим для каждого проекта по файл:
cd ~/vassals
touch project1.ini
touch project2.ini
7.1. Содержимое каждого из файлов - одинаковое (благодаря макро-подстановке %n равной basename файла):
[uwsgi]
virtualenv = /home/django/env/%n
chdir = /home/django/projects/%n
plugins = python27
pythonpath = ..
socket = /var/run/uwsgi/%n.sock
logto = /var/log/uwsgi/%n.log
env = DJANGO_SETTINGS_MODULE=%n.settings
module = django.core.handlers.wsgi:WSGIHandler()
buffer-size = 32768
Внимание! Папки /var/run/uwsgi и /var/log/uwsgi должны быть доступны на запись пользователю django. В первой будут лежать сокеты для связи uWSGI и nginx, во второй - логи uWSGI по каждому проекту. Также обратите внимание на строчку plugins = python27 - здесь должна быть указана версия питона используемая в проекте.
8. Выходим обратно под пользователя root, чтобы отредактировать настройки uWSGI (для Gentoo, они расположены в /etc/conf.d/uwsgi). Приводим к следующему виду:
UWSGI_SOCKET=
UWSGI_THREADS=1
UWSGI_PROGRAM=
UWSGI_XML_CONFIG=
UWSGI_PROCESSES=1
UWSGI_LOG_FILE=
UWSGI_DIR=
UWSGI_USER=django
UWSGI_EMPEROR_PATH=/home/django/vassals
UWSGI_EXTRA_OPTIONS=
9. Необходимо создать папки /var/run/uwsgi, /var/log/uwsgi и сделать их владельцами пользователя django:
mkdir /var/run/uwsgi
mkdir /var/log/uwsgi
chown -R django:django /var/run/uwsgi /var/log/uwsgi
10. Добавляем uwsgi в автозагрузку и запускаем:
rc-update add uwsgi default
/etc/init.d/uwsgi start
11. И самое простое - поставим и настроим nginx. Тут самое главное - указать, что имя пользователя под которым запускается nginx. Обычно это системный пользователь www-data или nginx. Этот пользователь должен быть в одной группе с django-пользователем чтобы иметь доступ к статическим файлам (возможно даже на запись). Конфиг /etc/nginx/nginx.conf должен быть примерно такого содержания:
user nginx;
worker_processes 1;
error_log /var/log/nginx/error_log info;
events {
worker_connections 1024;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main
'$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio"';
client_header_timeout 10m;
client_body_timeout 10m;
send_timeout 10m;
connection_pool_size 256;
client_header_buffer_size 1k;
large_client_header_buffers 4 16k;
request_pool_size 4k;
gzip on;
gzip_min_length 1100;
gzip_buffers 4 8k;
gzip_types text/plain;
output_buffers 1 32k;
postpone_output 1460;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 75 20;
ignore_invalid_headers on;
index index.html;
include /etc/nginx/vhosts.d/*.conf;
}
12.1 Создадим подпапку /etc/nginx/vhosts.d и в ней по файлу для каждого проекта:
mkdir /etc/nginx/vhosts.d
cd /etc/nginx/vhosts.d
touch project1.conf
touch project2.conf
Вот содержимое project1.conf (для project2.conf он аналогичен):
upstream wsgi_project1 {
server unix:/var/run/uwsgi/project1.sock;
}
server {
listen 80;
server_name <доменное имя нашего сайта> default; << default означает, что если будут обращаться по IP к нашему серверу - то именно этот сайт будет там
charset utf8;
autoindex off;
access_log /var/log/nginx/project1_access.log;
error_log /var/log/nginx/project1_error.log error;
set $project_home /home/django/projects/project1;
location /images {
root $project_home/static;
expires 1d;
}
location /css {
root $project_home/static;
expires 1d;
}
location /js {
root $project_home/static;
expires 1d;
}
location /static {
root $project_home;
expires 1d;
}
location / {
try_files $uri @django;
}
location @django {
uwsgi_pass wsgi_project1;
include uwsgi_params;
}
}
12.2 Добавим nginx в автозагрузку и запустим его:
rc-update add nginx default
/etc/init.d/nginx start
Это пока всё. Если у кого-то будут замечания и дополнения - оставляйте их в комментариях. Вместе мы победим =)
В nginx.conf следует прописать
ОтветитьУдалитьlarge_client_header_buffers 4 16k;
а в project.ini
buffer-size = 32768
Иначе будет 502 ошибка выскакивать при добавления больших объектов (новости, галереи)
Ну автор и садист. У меня чуть кровь из клаз не потекла. Выкоючил бекграунд-полегчалою Ща буду читать
ОтветитьУдалитьПри использовании virtualenvwrapper`a можно вместо source писать `workon project1` . И deactivate для выхода.
ОтветитьУдалитьАга. Сейчас поправлю. Насчёт фона не согласен, видать не игрались на Спектруме - это полосочки при загрузке программ в турбо-режиме и стандартным загрузчиком =)
УдалитьВыполнил все как написано, за исключением того, что проект создавал только один и называл project. Запуск nginx закончился ошибкой
ОтветитьУдалитьnginx: [emerg] no port in upstream "wsgi_mtcrm" in /etc/nginx/vhosts.d/project.conf:40
В чем может быть дело? Спасибо.
упс =) нашли багу в конфиге =)
Удалитьвместо
location @django {
uwsgi_pass wsgi_mtcrm;
include uwsgi_params;
}
надо написать
location @django {
uwsgi_pass wsgi_project1;
include uwsgi_params;
}
Ok. Теперь приходит страница
Удалить"uWSGI Error
Python application not found"
В логах ничего интересного, никаких ошибок. Если делать из виртуальной среды ./manage.py runserver 8080 — успешно работает, показывает нужную страницу. Куда копать?
не может быть, что ничего интересного =)
УдалитьОчень похоже на ошибку создания сокета - либо порт занят, либо прав на создание сокета нет в указанном каталоге. По-возможности приведите лог тут, тогда ещё помогу.
ЗЫ: интересует часть лога где примерно такие строки:
*** Starting uWSGI 1.4.9 (32bit) on [Sun Jun 23 18:18:34 2013] ***
compiled with version: 4.6.3 on 26 April 2013 21:50:16
os: Linux-3.8.6-hardened #1 SMP Sun May 5 07:54:15 MSK 2013
nodename: web
machine: i686
clock source: unix
pcre jit disabled
detected number of CPU cores: 1
current working directory: /home/django/vassals
detected binary path: /usr/bin/uwsgi
your processes number limit is 16166
your memory page size is 4096 bytes
detected max file descriptor number: 1024
lock engine: pthread robust mutexes
uwsgi socket 0 bound to UNIX address /var/run/uwsgi/testproj.sock fd 3
Python version: 2.7.3 (default, Apr 23 2013, 11:51:59) [GCC 4.6.3]
Set PythonHome to /home/django/env/testproj
*** Python threads support is disabled. You can enable it with --enable-threads ***
Python main interpreter initialized at 0xb77d3a60
your server socket listen backlog is limited to 100 connections
mapped 184960 bytes (180 KB) for 1 cores
*** Operational MODE: single process ***
added ../ to pythonpath.
О. Теперь все получилось: после очередного перезапуска uwsgi и nginx сработало. Возможно какая-то особенность кэша nginx'а: выдавал страницу с ошибкой, но в логах никаких ошибок. Спасибо.
Удалитьну да, походу завис один из вассалов и не давал создавать сокет =)
Удалитьтам же есть 2 лога - один nginx а другой uwsgi, и в первый обычно не попадают ошибки уровня питона
Естественно я смотрел оба лога и перед последней проблемой это даже помогло мне решать одну проблему с питоном — путь до библиотек django.
УдалитьЕсли > django-1.6, то нужно в ini файле заменить
ОтветитьУдалитьmodule = django.core.handlers.wsgi:WSGIHandler()
на
module = django.core.wsgi:get_wsgi_application()
Этот комментарий был удален автором.
ОтветитьУдалитьЗдравствуй автор. Помоги разобраться настроил по мануалу один в один: Ошибка 502 Bad Gateway, в лог сыпется *11 connect() to unix:/var/run/uwsgi/blog.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.0.5, server: example.com, request: "GET / HTTP/1.1", upstream: "uwsgi://unix:/var/run/uwsgi/blog.sock:", host: "example.com"
ОтветитьУдалитьНу очевидно, что проблема с правами доступа. Если поможет - тут обсуждают возможные пути решения этой проблемы - http://stackoverflow.com/questions/22071681/permission-denied-nginx-and-uwsgi-socket
УдалитьРазобрался. Данный трабл был из-за module = django.core.handlers.wsgi:WSGIHandler() поставил себе module = my_project.wsgi:application
Удалитьи все работает. Спасибо за статью.