понедельник, 14 января 2013 г.

Cron и Crontab

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

При загрузке операционной системы, запускается демон cron, который проверяет очередь заданий at и заданий пользователей в файлах crontab. При запуске демон cron сначала проверяет каталог /var/spool/cron на наличие файлов crontab. Файлы crontab имеют имена пользователей соответствующие именам пользователей из /etc/passwd. Каждый пользователь может иметь только один файл crontab, записей в файле может быть несколько.

Другими словами, файлы crontab содержат инструкции для демона cron, который запустит задание(я) описанное в файле crontab. Все файлы crontab из каталога /var/spool/cron загружаются в память. Одновременно с ними загружаются файлы из /etc/cron.d. После этого демон cron загружает содержимое файла /etc/crontab

При стандартных настройках, содержимое /etc/crontab имеет следующий вид:

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
# run-parts
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly

Информация в данном файле указывает, что:

- содержимое каталога /etc/cron.hourly будет запускаться каждый час на первой минуте часа.

- содержимое каталога /etc/cron.daily будет запускаться каждый день на второй минуте четвертого часа.

- содержимое каталога /etc/cron.weekly будет запускаться каждое воскресенье на 22-ой минуте 4'го часа.

- содержимое каталога /etc/cron.monthly будет запускаться каждый первый день месяца на 42-ой минуте 4-го часа.

SHELL=/bin/bash означает: использовать для запуска команд /bin/bash. Если переменная не указана, то значение будет взято из /etc/passwd для пользователя являющегося владельцем файла.

HOME=/ это корневой каталог для пользователя. Данный араметр не обязателен. При необходимости доступа к специальным свойствам интерпретатора значения переменных SHELL и HOME можно изменить независимо от того, что прописано в /etc/passwd.

MAILTO=root означает кому отсылать сообщение о результате работы команд.

Все содержимое из этих каталогов будет запускаться с правами доступа пользователя root и файлы должны иметь права доступа на "выполнение". Поэтому перед размещением файлов в одном из этих каталогов необходимо убедиться, что сценарии не насесут вред системе.

После того, как демон cron запущен и прочел содержимое всех файлов crontab, он бездействует, просыпаясь каждую минуту и проверяя не требуется ли запуск какой-либо команды или не появился ли новый файл crontab, который необходимо обработать. Демон cron определяет изменения по времени модификации файлов или каталогов, такое его свойство избавляет от необходимости перезапуска демона.

Как файлы для cron располагаются в директориях:

/etc/cron.hourly
/etc/cron.daily
/etc/cron.weekly
/etc/cron.monthly

доступных только пользователю root. Для использования файлов crontab другими пользователями, необходимо использовать команду crontab. Команда crontab служит для создания, изменения и добавления файла для демона cron.

Пример.

Рассмотрим пример создания файла crontab для пользователя user, домашняя директория которого /home/user.

Задача: запускать каждую минуту файл /home/user/mail, который будет отправлять почту.

#содержимое файла mail
#!/bin/bash
mess="test cron"
echo "$mess" |mutt -s "subj" -m application/octet-stream bob@server.ru

1.Создаем временный файл /home/user/test:

SHELL=/bin/bash
MAILTO=user
0-59 * * * * /home/user/mail

2. Запускаем в терминале команду crontab /home/user/test

После этого в каталоге /var/spool/cron будет создан файл "user" примерно с таким содержимым:

# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/home/user/test installed on Mon Mar 29 02:31:34 2004)
# (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $)
SHELL=/bin/bash
MAILTO=user
0-59 * * * * /home/user/mail

Файл /home/user/mail будет запускаться демоном cron каждую минуту.

Доступ в каталог /var/spool/cron непривилегированному пользователю закрыт. Чтобы посмотреть пользователю "user" есть ли у него файл crontab, достаточно набрать команду crontab -l. Если файл существует, то будет показано его содержимое.

Для удаления файла используется команда crontab -r

Для редактирования файла crontab -e

Для управления файлами crontab пользователем "root" используется синтаксис:

-------------------------
crontab -u user_name file -создание файла crontab
-------------------------          из файла "file" для
                                        юзера "user_name"

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

-------------------------
crontab -u user_name -l  -просмотр файла crontab
-------------------------         юзера "user_name"

-------------------------
crontab -u user_name -r -удаление файла crontab
-------------------------       юзера "user_name"

-------------------------
crontab -u user_name -e  -редактирование файла crontab
-------------------------         юзера "user_name" используя
                                       редактор, заданный переменной
                                       окружения VISUAL или EDITOR

Формат и значения полей.

Каждая команда в пользовательском файле crontab занимает одну строку и состоит из шести полей. Пользовательские файлы crontab находятся в каталоге /var/spool/cron.

Общий формат команды:

------------------------------------------------
минута час день_месяца месяц день_недели команда
------------------------------------------------

Допустимые значения:
минута - от 0 до 59
час - от 0 до 23
день_месяца - от 1 до 31
месяц  - от 1 до 12 (можно три буквы из названия месяца, регистр не имеет значения от jan до dec)
день_недели - от 0 до 6  (0 это воскресенье, можно писать от sun до sat)

Каждое из полей даты и времени может быть обозначено символом *, что будет соответствовать любому возможному значению. Для этих полей можно указывать диапазоны значений, разделенных дефисом, например:

* 5 4-10 0-3 * echo "HELLO" -печать HELLO в 5:00 на 4, 5, 6, 7, 8, 9, 10 день января, февраля, марта и апреля.

Пошаговая запись

* */2 * * sat echo "HELLO" -печать HELLO каждый четный час каждую субботу.

Равнозначная предыдущему примеру запись (списком)

* 0,2,4,6,8,10,12,14,16,18,20,22 * * sat echo "HELLO"  -печать HELLO каждый четный час каждую субботу.

То же самое с указанием диапазона

* 0-23/2 * * sat echo "HELLO"  -печать HELLO каждый четный
                                час, каждую субботу

59 23 31 dec * echo "Happy new year" - поздравит с новым годом.

Для отладки задания cron можно перенаправить результат в файл.

Пример:

0-59 * * * * /home/user/mail 2>/tmp/tmp.cron

Если при запуске команды /home/user/mail возникнут ошибки, то они будут записаны в файл /tmp/tmp.cron и вы всегда сможете узнать причину. В случае перенаправленния вывода в файл письмо юзеру, указаному в переменной MAILTO, отправлено не будет.

Посмотреть информацию о всех командах, запускаемых демоном cron можно в каталоге /var/log (называются cron, cron1 и так далее).

В файле /var/log/cron записано время запуска всех заданий cron за предыдущий день:

Mar 29 04:03:00 rst CROND[4434]: (user) CMD (/home/user/mail)
Mar 29 04:03:59 rst CROND[4493]: (user) CMD (/home/user/mail)
Mar 29 04:05:00 rst CROND[4507]: (user) CMD (/home/user/mail)
Mar 29 04:06:00 rst CROND[4549]: (user) CMD (/home/user/mail)

В остальных файлах cron1, cron2 находится подобная информация, но более старая чем в cron.

Вот практически и все, что требуется знать для использования cron и crontab.

пятница, 11 января 2013 г.

Django на Nginx через FastCGI

Когда разрабатываешь сайт на Django, так легко просто открыть консоль и напечатать:

python manage.py runserver

С этой простой командой управления ваши медиа файлы админки сайта поддерживаются правильным образом, PYTHONPATH правильно настроен и включает корневую папку нашего проекта, а так же запущен автоматически перегружающийся веб-сервер на указанном нами порту (по умолчанию порт 8000). Так просто!

Не удивительно, что люди так разочаровываются, когда приходит время положить их сайт на боевой сервер: существует так много шагов в этом процессе и поэтому сложно все их выучить и сделать все правильно. Неудивительно, что вся эта сложность приводит к тому, что написано много статей о развертывании веб-сайта на Django. Но почти все из этих статей фокусируются на развертывании сайта используя Apache и mod_wsgi или mod_python.

Однако иногда Apache - не идеальное решение. Может быть ваш VPS имеет только 256 МБ памяти, а может быть вы хотите избежать сложности настройки Apache при установке. Или может быть вам просто не нравиться Apache. По любой из этих причин мы можем обратить свое внимание на FastCGI.

Прежде всего


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

Давайте установим основу системы, включая некоторые компиляторы, заголовочные файлы для питона и setuptools

sudo apt-get install build-essential python-dev python-setuptools

Поставим так же Nginx в качестве нашего веб-сервера. Это можно сделать так:

sudo apt-get install nginx

Так же следует поставить daemontools – это коллекция инструментов для управления сервисами. Мы будем использовать их, чтобы быть уверенными, что наши сервисы будут оставаться запущенными (или по крайней мере будут возвращаться к жизни) даже в случае ошибки или перезапуска сервера. Чтобы поставить daemontools напечатайте:

sudo apt-get install daemontools

К сожалению, пакет daemontools требует нашей небольшой дополнительной работы, чтобы автоматически перезапускаться при перезагрузке. Сначала создайте файл /etc/event.d/svscanboot со следующим содержимым:

start on runlevel 2
start on runlevel 3
start on runlevel 4
start on runlevel 5
stop on runlevel 0
stop on runlevel 1
stop on runlevel 6
respawn
exec /usr/bin/svscanboot


Затем создайте папку /etc/service , выполнив следующую команду:

sudo mkdir /etc/service

В конце запустим daemontools, выполнив эту команду:

sudo initctl start svscanboot

Создадим нового пользователя для нашего сайта:

adduser mysite

Если мы хотим использовать команду sudo с нашим пользователем, то нам так же нужно отредактировать /etc/sudoers. Найди в этом файле строку root ALL=(ALL) ALL и под ней добавь:

mysite ALL=(ALL) ALL

Сейчас мы можем переключиться на нашего пользователя:

su - mysite

Итак, основа нашей системы готова. Мы умышленно не рассказываем про базу данных, почтовые сервера, системы контроля версий, memcached и другие различные сервисы, потому что они могут сильно варьироваться в зависимости от персональных предпочтений.

Настройка нашей виртуальной среды для Python


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

sudo easy_install virtualenv

С нашей свежей копией virtualdev мы можем пойти дальше и настроить новую виртуальную среду:

mkdir ~/virtualenvs
virtualenv ~/virtualenvs/mysite


Мы создали директорию virtualenvs в нашей домашней папке и внутри нее мы создали виртуальную среду под названием mysite. Сейчас давайте начнем использовать ее и происталлируем pip, чтобы легко инсталлировать питоновские пакеты:

source ~/virtualenvs/mysite/bin/activate
easy_install pip


Сейчас нам необходимо убедиться, что у нас установлен пакет Flup. Это набор полезных инструментов для работы с WCGI приложениями, включая адаптер для превращения WSGI приложения в FastCGI (и SCGI, и AJP… но это за пределами данной статьи). Django требует, чтобы Flup был проинсталлирован до того, как вы сможете использовать команду управления runfcg. Используя pip мы можем легко проинсталлировать его:

pip install flup

Если мы хотим использовать адаптеры базы данных, графические библиотеки или xml парсеры, инсталлированные по системному пути Python, мы должны убедиться, что они доступны из нашей виртуальной среды. Для этого мы добавляем .pth файл в директорию виртуальной среды site-packages:

echo "/usr/lib/python2.6/dist-packages/" > ~/virtualenvs/mysite/lib/python2.6/site-packages/fix.pth

Следующий шаг – клонировать код Django на наш сервер (очевидно git может быть заменен на mercurial, svn или даже rsync):

git clone github.com/myusername/mysite.git

Если у вашего проекта есть pip requirements файл, сейчас вы можете его использовать:

pip install -U -r mysite/requirements.txt

Или, если у вас нет requirements file, вы можете проинсталлировать зависимости вручную. Например:

pip install -U Django simplejson python-memcached

Выбор опций для нашего FastCGI сервера


Мы прошли длинный путь настройки нашей системы и даже еще не рассказали о FastCGI части. Не бойся, мы готовы сделать это сейчас. Давай определимся, какие опции мы хотим иметь, когда мы запустим наш FastCGI сервер.

Первый выбор, который нужно сделать – какой метод распараллеливания мы хотим использовать:
  • threaded:
    Выполнение потокового сервера в одном процессе для всех HTTP запросов. Это сохраняет много памяти, но все потоки упираются в проблему одного Global Interpreter Lock (GIL). Это означает, что производительность может быть ограничена интенсивной процессорной загрузкой. Заметьте, что операции ввода-вывода происходят за пределами GIL, поэтому интенсивная загрузка операциями ввода-вывода не упирается в проблему GIL. Так же некоторые расширения питона не предполагались быть потоко-безопасными, что означает, что они не могут быть использованы с этим методом конкуренции.
  • prefork:
    Выполнение разветвляющего сервера порождающего пул процессов, каждый из которых со своей собственной копией джанги и питона загруженного в память. Это означает, что будет использоваться больше памяти, но нет вышеупомянутых проблем с GIL или потоко-безопасностью.

Давайте предположим, что нам интересен FastCGI, потому что у нас сервер с маленьким размером памяти. Так как разветвляющий (prefork) метод будет использовать больше памяти, поэтому мы выберем потоковый (threaded) метод.

Сейчас мы выберем несколько опций, которые говорят серверу, как ему действовать под нагрузкой:
  • minspare:
    Какое минимальное кол-во процессов/потоков сервер будет поддерживать готовыми и ожидающими будущих запросов?
  • maxspare:
    Какое максимальное кол-во процессов/потоков сервер будет поддерживать готовыми и ожидающими будущих запросов?
  • maxrequests (только для prefork метода):
    Как много запросов каждый процесс будет обслуживать до того, как он будет убит и запущен заново. Чтобы предотвратить утечки памяти, до того момента как это станет проблемой. Это хорошая идея установить эту опцию.
  • maxchildren (только для prefork метода):
    Как много дочерних процессов могут поддерживать запросы в любое заданное время?

Наш сервер работает на небольшом VPS с 265 МБ памяти, поэтому мы выберем очень скромные настройки: 2 для
minspare, 4 для maxspare, 6 для maxchildren и 500 для maxrequests.

В конце мы выбираем наши последние несколько настроек:
  • host
    Имя хоста (hostname), который будет слушать входящие соединения?
  • port
    На каком порту слушать входящие соединения?
  • pidfile
    Когда FastCGI сервер стартует, он создает файл со своим идентификатором процесса (process ID). Этот process ID – pid главного потока/процесса. Это процесс который будет поддерживать сигналы OS, например SIGHUP. Эта опция определяет расположение этого файла.

После того, как мы сделали наши выборы, мы можем запустить сервер выполнив runfcgi команду:

python manage.py runfcgi method=threaded host=127.0.0.1 port=8080 pidfile=mysite.pid minspare=4 maxspare=30 daemonize=false

Заметьте, что мы добавили флаг daemonize=false. Он всегда должен быть установлен (по мнению автора пропуск этой опции является просчетом в команде runfcgi). Так же заметьте, что результатом выполнения этой команды будет создан mysite.pid файл в нашей директории проекта, так что это хорошая идея удостовериться, что ваша система контроля версий игнорирует этот файл.

Сейчас, когда мы проверили, что наш FastCGI сервер запущен правильно, давайте остановим его и перейдем к следующему шагу: использование daemontools для запуска этой команды и поддержку работы сервера все время в фоновом режиме.

Daemontools выполняет наш FastCGI сервер


Daemontools будет смотреть во все поддиректории в /etc/service директории и в каждой из них он ищет исполняемый файл, называемый run. Если он находит такой файл, то он запускает его и перезапускает его, если он умирает. Итак, давайте создадим mysite директорию:

sudo mkdir /etc/service/mysite

Сейчас, давайте сделаем небольшой скрипт, который запускает наш fastcgi сервер. Используйте ваш любимый текстовый редактор, чтобы записать этот текст в /etc/service/mysite/run:

#!/usr/bin/env bash

source /home/mysite/virtualenvs/mysite/bin/activate
cd /home/mysite/mysite
exec envuidgid mysite python manage.py runfcgi method=threaded host=127.0.0.1 port=8080 pidfile=mysite.pid minspare=4 maxspare=30 daemonize=false


Тут нет ничего хитрого. Сначала мы проверяем, что мы в правильной виртуальной среде (virtualenv), затем мы изменяем текущую директорию на mysite и затем выполняем runfcgi команду, которую мы обсуждали раньше. envuidgid mysite просто убеждается, что следующая команда выполняется под пользователем mysite, вместо root.

Скрипт должен быть исполняемым, чтобы daemontools распознал его, поэтому давайте выполним следующую команду:

sudo chmod +x /etc/service/mysite/run

Сейчас мы можем проверить, что он выполняется, используя команду svstat:

sudo svstat /etc/service/mysite/

Результат должен выглядеть примерно так:

/etc/service/mysite/: up (pid 3610) 33 seconds

Это означает, что процесс поднят, ему присвоен process id = 3610 и он проработал 33 секунды. Вы можете использовать команду svc, чтобы остановить процесс:

sudo svc -d /etc/service/mysite/

Затем, если вы выполните снова svstat, то получите примерно такой вывод:

/etc/service/mysite/: down 4 seconds, normally up

Чтобы вернуть процесс обратно, просто выполните:

sudo svc -u /etc/service/mysite/

Полный список  svc команд можно найти online — это очень хороший источник, если вы собираетесь погрузиться глубже в daemontools.

Конфигурируем Nginx для работы с нашим сервером


Мы уже близко к финишной черте. Все что нам осталось сделать – сконфигурировать nginx для беседы с нашим FastCGI сервером, получения от него ответов и передачи их пользователю.

Ubuntu поставляется с полезным /etc/nginx/fastcgi_params файлом. К сожалению, он не совсем правильный. Он кодирует (encode) SCRIPT_NAME параметр, но то, что наш сервер реально хочет – PATH_INFO. Вы можете выполнить поиск и замену или скопировать содержимое ниже в /etc/nginx/fastcgi_params файл:

fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;

fastcgi_param PATH_INFO $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;

fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;

fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;


Сейчас мы создадим определение для нашего сайта. Используя текстовый редактор, давайте создадим файл /etc/nginx/sites-available/mysite со следующим содержанием:

server {
listen 80;
server_name mysite.com www.mysite.com;
access_log /var/log/nginx/mysite.access.log;

location /media {
autoindex on;
index index.html;
root /home/mysite/mysite;
break;
}
location / {
include /etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:8080;
break;
}
}


Он говорит: слушать порт 80 (стандарт для HTTP) для mysite.com/ и http://www.mysite.com/. Запросы для /media следует обрабатывать сразу с диска из /home/mysite/mysite/media директории. И самое важное: все остальные запросы будут передаваться через FastCGI нашему серверу.

Сейчас давайте подключим его через symlink:

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

Наконец перезапускаем nginx, чтобы новые настройки вступили в силу:

sudo /etc/init.d/nginx restart

Заключение


Мы настроили минимальный сервер, используя nginx, чтобы обслуживать media файлы на умопомрачительной скорости и чистый питоновский FastCGI сервер, чтобы обслуживать динамические запросы без каких-либо промежуточных слоев между ними. Используя daemontools мы имеем полный контроль над FastCGI процессом и можем останавливать его, перезапускать или изменять его настройки в любой момент.

По настоящему интересная вещь – достаточно только нескольких маленьких подстроек и этот же самый стэк мог бы использоваться для решений на базе gunicorn, spawning, или paste. Вместо использования fastcgi_pass мы могли бы использовать proxy_pass. Мы могли бы по прежнему использовать daemontools, чтобы поддерживать наш процесс в рабочем состоянии и контролировать его. Почти каждый шаг этой статьи останется тот же самый.
Это очень жизнеспособная альтернатива часто навязываемому стэку из Apache/mod_wsgi и надеюсь после прочтения этой статьи больше людей будут рассматривать его, как метод развертывания своего сайта на Django.

четверг, 10 января 2013 г.

Запуск Django из Apache

Создайте новый проект Django:

django-admin.py startproject testserver

В папку проекта testserver добавьте файл django.wsgi, имеющий следующий код:


import os, sys

sys.path.append('C:/django')
os.environ['DJANGO_SETTINGS_MODULE'] = 'testserver.settings'

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


Перейдите в папку сервера Apache, расположенную по адресу
C:\Program Files\Apache Software Foundation\Apache2.2\conf

Откройте файл httpd.conf и добавьте в него следующий код:


WSGIScriptAlias / "C:/django/testserver/django.wsgi"

<Directory "C:/django/testserver/">
    Options +Indexes FollowSymLinks +ExecCGI
    AllowOverride AuthConfig FileInfo
    Order allow,deny
    Allow from all
</Directory>


Запустите сервер Apache.

Перейдите в браузере по адресу http://localhost/

В результате вы увидите стартовую страницу Django.

Запуск Django из Tornado и проксирование через Nginx

Создайте новый проект Django:

django-admin.py startproject testserver

В папку проекта testserver добавьте файл django_tornado.py, имеющий следующий код:

# -*- coding: utf-8 -*-

import os
import tornado.httpserver
import tornado.ioloop
import tornado.wsgi
import sys
import django.core.handlers.wsgi
sys.path.append('C:/django')

def main():
    os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
    application = django.core.handlers.wsgi.WSGIHandler()
    container = tornado.wsgi.WSGIContainer(application)
    http_server = tornado.httpserver.HTTPServer(container)
    http_server.listen(8001, "127.0.0.1")
    tornado.ioloop.IOLoop.instance().start()

if __name__ == "__main__":
    main()

После этого запустите файл django_tornado.py из консоли.

Перейдите в браузере по адресу http://127.0.0.1:8001/

В результате вы увидите стартовую страницу Django.



Для того, чтобы проксировать Nginx --> Tornado --> Django в конфиге Nginx в файле nginx.conf из папки conf пропишите следующие настройки:

worker_processes  1;

events {
    worker_connections  1024;
}

http {

    include          mime.types;
    default_type  application/octet-stream;

    server {
  
        listen             80;
        server_name  localhost;

        location / {
            proxy_pass          http://127.0.0.1:8001;
            proxy_set_header X-Real-IP $remote_addr;
        }

    }
  
}

После этого запустите сервер Nginx и файл django_tornado.py

В браузере перейдите по адресу http://localhost/

В результате вы увидите стартовую страницу Django, но в этот раз она будет загружена через связку Nginx --> Tornado --> Django.

Для загрузки статичных файлов, таких как: css, javascript, images через Nginx изменим конфиг в файле nginx.conf следующим образом:

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile on;

    keepalive_timeout 65;

    server {
        listen       80;
        server_name  localhost;


        location / {
            proxy_pass http://127.0.0.1:8001;
            proxy_set_header X-Real-IP $remote_addr;
        }

        location /static/ {
            alias C:/django/testserver/static/;
            autoindex on;
            autoindex_exact_size on;
            autoindex_localtime on;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

    }

}

В результате Django сможет загружать файлы css, javascript, images из папки C:\django\testserver\static через сервер Nginx.



среда, 9 января 2013 г.

Настройка Nginx, Tornado, Django

# nginx.conf:

------------------------------------------------------------------------

user              nginx;

worker_processes  1;

error_log    /var/log/nginx/error.log;

#error_log  /var/log/nginx/error.log  notice;

#error_log  /var/log/nginx/error.log  info;

pid             /var/run/nginx.pid;

#----------------------------------------------------------------------

# Events Module

#

#   http://wiki.nginx.org/NginxHttpEventsModule

#

#----------------------------------------------------------------------

events {

    worker_connections  1024;

    use epoll;

}

#----------------------------------------------------------------------

# HTTP Core Module

#

#   http://wiki.nginx.org/NginxHttpCoreModule

#

#----------------------------------------------------------------------

http {

    upstream tornadoserver {

        server 127.0.0.1:8888;

        server 127.0.0.1:8889;

    }

    include       /etc/nginx/mime.types;

    #include    /etc/nginx/conf.d/virtual.conf;

    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '

                               '$status $body_bytes_sent "$http_referer" '

                               ' "$http_user_agent" "$http_x_forwarded_for" ';

    access_log  /var/log/nginx/access.log  main;

    sendfile              on;

    #tcp_nopush     on;

    #keepalive_timeout  0;

    keepalive_timeout  65;

    #gzip  on;

    

    # Load config files from the /etc/nginx/conf.d directory

    include /etc/nginx/conf.d/*.conf;

    #

    # The default server

    #

    server {

        listen             80;

        server_name  xlquest.web;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        error_page  404 /404.html;

        location = /404.html {

            root   /usr/share/nginx/html;

        }

    

        # redirect server error pages to the static page /50x.html

        #

        error_page   500 502 503 504  /50x.html;

        location = /50x.html {

            root   /usr/share/nginx/html;

    }

}

}

# /etc/nginx/conf.d/virtual.conf

------------------------------------------------------------------------

server {

    listen       80;

  

    server_name  ilugc.web;

        location / {

            proxy_pass      http://127.0.0.1:8888;

        }

        location /sitemedia/ {

            root /home/lawgon/ilugc/;

        }



        location /smedia/ {

            root /home/lawgon/;

        }



        location /media/ {

            root /home/lawgon/django-trunk/django/contrib/admin/;

        }

}

server {

    listen       80;

  

    server_name  conference.web;

        location / {

            proxy_pass      http://127.0.0.1:8889/;

        }

        location /2009/ {

            proxy_pass      http://127.0.0.1:8889/;

        }

        location /sitemedia/ {

            root /home/lawgon/conference/;

        }



        location /smedia/ {

            root /home/lawgon/;

        }



        location /media/ {

            root /home/lawgon/django-trunk/django/contrib/admin/;

        }

}

# python script to run django on tornado

------------------------------------------------------------------------

#! /usr/bin/env python

import os

import tornado.httpserver

import tornado.ioloop

import tornado.wsgi

import sys

import django.core.handlers.wsgi

sys.path.append('/home/lawgon/')

def main():

    os.environ['DJANGO_SETTINGS_MODULE'] = 'ilugc.settings'

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

    container = tornado.wsgi.WSGIContainer(application)

    http_server = tornado.httpserver.HTTPServer(container)

    http_server.listen(8888)

    tornado.ioloop.IOLoop.instance().start()

if __name__ == "__main__":

    main()

Nginx команды

Запуск, остановка и тестирование сервера.

nginx.exe - Запуск сервера
nginx -s stop - Остановка сервера
nginx -s reload - Перезапуск сервера
nginx -t - Проверка правильности файла конфига
nginx -v - Версия сервера

Настройка nginx.conf:

# -  это комментарий.

# Все директивы обязательно оканчиваются знаком ( ; ).

#user nobody;
worker_processes 1; # Число процессов равно числу ядер в процессоре.

include other_settings.conf; # include вставлет в это место настройки из другого файла конфига.

( Комментарии.

Содержимое other_settings.conf:

    error_log logs/error.log;
    pid logs/nginx.pid;

Примеры подключаемых файлов конфигов.

nginx.conf - главный конфигурационный файл сервера
mime.types - список расширений файлов и их соотвествий MIME types
fastcgi.conf - файл конфиг для FastCGI
proxy.conf - файл конфиг для Proxy
sites.conf -  файл конфиг для сайтов, обслуживаемых сервером Nginx, также известный как virtual hosts. Рекомендуется создавать отдельные файлы для каждого домена.

)

include sites/*.conf; # Подключать можно сразу все конфигурационные файлы из папки, используя символ ( * ), вместо имен файлов.

http {
    server {
        listen 80; # Слушать порт 80
        server_name example.com; # Домен http://www.example.com/
        access_log /var/log/nginx/example.com.log; # Лог для сайта записывать в файл example.com.log
        location ^~ /admin/ { # По адресу http://www.example.com/admin/ открывать файл index.php
            index index.php;
            access_log off; # Лог для страницы по адресу http://www.example.com/admin/ не записывать
        }
    }
}

(

Комментарии.

Единицы измерения.

k или K: Kilobytes
m или M: Megabytes

Примеры:

client_max_body_size 2M;
client_max_body_size 2048k;

Единицы времени.

ms: Milliseconds
s: Seconds
m: Minutes
h: Hours
d: Days
w: Weeks
M: Months (30 days)
y: Years (365 days)

Примеры:

client_body_timeout 3m;
client_body_timeout 180s;
client_body_timeout 180;

)

location ^~ /admin/ {
    access_log logs/main.log;
    log_format main '$pid - $nginx_version - $remote_addr'; # $pid, $nginx_version, $remote_addr - это подставляемые значения переменных. Как в PHP переменные начинаются со знака ( $ ).
}

Пример конфигурации сервера по умолчанию.

user boris admins; # Означает, что данный процесс будет главным - корневым, для всех других процессов. Процесс управляется из под аккаунта пользователя boris, находящегося в группе пользователей admins.

worker_processes 1; # Установка числа процессов по принципу 1 процесс на 1 ядро процессора или более.


worker_priority 0; # Установка приоритета работы программы Nginx над другими программами, запущенными в операционной системе. Приоритет работы изменяется от -20 (высший приоритет) до 19 (низший приоритет). 0 - обычный приоритет. Не стоит устанавливать значение меньше -5, так как это приоритет работы самой операционной системы.

error_log logs/error.log error; # Установка файла, куда записывать логи в случае возникновения ошибок.

log_not_found on; # Записывать ли в лог-файл ошибки 404 - Страница (или файл) не найдена или нет? on - записывать, off - не записывать. Для конкретных сайтов следует перезаписать эту директиву log_not_found off. Но стоит оставить её в режиме on для базовой конфигурации всего сервера. 

events {
    accept_mutex on;
    accept_mutex_delay 500ms;
    multi_accept off;
    worker_connections 1024; # Предельное число возможных установленных одновременных соединений с сервером. Если число worker_processes 4, то общее число возможных одновременныз соединений в этом случае будет 1024 * 4 = 4096. Чем больше значение RAM и CPU, тем большее число соединений вы можете поддерживать.
}

Примеры рекомендуемых значений для компьютеров разных мощностей.

Главное значение имеет число worker_processes и worker_connections.
worker_processes должно соответствовать числу ядер в процессоре.
worker_connections зависит от величины RAM. Если значение worker_connections мало, то некоторые запросы со стороны браузеров могут оказаться не обработаны сервером. Установка данного значения зависит от числа пользователей, посещающих ваш сайт.

Низкий трафик


CPU: Dual-core (2 ядра)
RAM: 2 GB
Requests: ~ 1/s

worker_processes 2;
worker_rlimit_nofile 1024;
worker_priority -5;
worker_cpu_affinity 01 10;
events {
    multi_accept on;
    worker_connections 128;
}

Средний трафик

CPU: Quad-core (4 ядра)
RAM: 4 GB
Requests: ~ 50/s

worker_processes 4;
worker_rlimit_nofile 8192;
worker_priority 0;
worker_cpu_affinity 0001 0010 0100 1000;
events {
    multi_accept off;
    worker_connections 1024;
}

Высокий трафик

CPU: 8-core (8 ядер)
RAM: 12 GB
Requests: ~1000/s

worker_processes 8;
worker_priority 0;
events {
    multi_accept off;
    worker_connections 8192;
}

Таким образом, в качестве настроек сперва:
1. Устанавливаем пользователя user, из-под которого работает сервер.
2. Устанавливаем число рабочих процессов и соединений в зависимости о CPU и RAM.
3. Устанавливаем приоритет процессов сервера в операционной системе.
4. Прописываем адрес лог-файла.
5. Создаем тестовый сервер.

Типичная структура сервера.

http {

    server {

        server_name localhost;
        listen 80;

        location /downloads/ {

        }

    }

}

Тестовый сервер.

http { # Для соединений через протокол http://
    include mime.types; # включаем файл-конфиг для mime.types
    default_type application/octet-stream; # устанавливаем тип передачи
    sendfile on;
    keepalive_timeout 65; # устанавливаем время поддержания соединения
    server {
        listen 80; # ожидаем соединения на порту 80
        server_name localhost; # домен сайта localhost (соотвествует ip-адресу сайта 127.0.0.1)
        location / { # по адресу localhost/ загружаем файлы
            root html; # загружаем html, если адрес localhost/
            index index.html index.htm; # загружаем index.html или index.htm, если адрес localhost/index.html или localhost/index.htm, перебираем все файлы по порядку пока не найдем тот, который можно будет загрузить.
        }
        error_page 500 502 503 504 /50x.html; # Страницы с ошибками 500, 502, 503, 504 загружаются из файла localhost/50x.html
        location = /50x.html {# по адресу localhost/50x.html загружаем файлы
            root html; # загружаем html, если адрес localhost/50x.html
        }
    }
}

Полный рабочий пример тестового сервера Nginx.

# user boris admins;

worker_processes 1;
worker_priority 0;

error_log logs/error.log error;

events {
    worker_connections 1024;
}

http {
    include mime.types;
    default_type application/cotet-stream;
    sendfile on;
    keepalive_timeout 65;
    log_not_found on;
    server {
        listen 80;
        server_name localhost;
        location / {
            root html;
            index index.html index.htm;
        }
        error_page 500 502 503 504 /50x.html;
        location /50x.html {
            root html;
        }
    }
}


Для проверки правильности конфигурации в консоли запускаем команду

nginx -t


Методология работы тут такая:
1. Изменить конфигурацию.
2. Запустить тест.
3. Перезапустить сервер.


Программы для тестирования нагрузки на сервер:

httperf
Autobench
OpenWebLoad

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

Апгрейд работающего сервера Nginx.

1. Заменить старый бинарник Nginx (по умолчанию он располагается в папке по адресу /usr/local/nginx/sbin/nginx) на новый.
2. Найти идентификатор процесса pid сервера Nginx в операционной системе по команде ps x | grep nginx | grep master или найдя его значение в pid-файле.
3. Послать сигнал USR2 (12) главному процессу —kill –USR2 ***, заменив *** на номер найденного pid в шаге 2. Эта процедура запустит обновление через переименование сторого .pid файла и запустит новый бинарник Nginx.
4. Послать сигнал WINCH (28) старому главному процессу —kill –WINCH ***, заменив ***  на номер найденного pid в шаге 2. Эта процедура отключит старый рабочий процесс сервера.
5. Убедитесь в том, что старый рабочий процесс сервера уничтожен и затем пошлите сигна QUIT старому главному процессу —kill –QUIT ***, заменив *** на номер найденного pid в шаге 2.

С этого момента ваш сервер Nginx считается обновленным без потерь соединения с браузерами пользователей.

Пример передачи серврером заархивированных данных в формате gzip.

http {
    # Включаем сжатие данных в gzip на уровне http блока
    gzip on;
    server {
       server_name localhost; # домен сайта localhost
       listen 80; # прослушиваем порт 80
       location /downloads/ {
            gzip off; # Отключаем отдачу архивированных данных для адреса localhost/downloads/
      }
    }
}

Как видно из примера, директивы внутри блока могут перезаписывать директивы внешнего блока.

Пример прописывания адресов.

http {
    server {
        server_name localhost; # домен
        listen 127.0.0.1:80; # вместо домена можно полностью прописать ip-адрес и порт

        root /var/www/website.com/html; # корневой адрес сайта, при переходе по адресу http://localhost/ файлы будут загружены их папки /var/www/website.com/html

        location /admin/ { # адрес страницы сайта, при переходе по адресу http://localhost/admin/ файлы будут загружены их папки /var/www/locked/
            alias /var/www/locked/;
        }

        error_page 404 /not_found.html; # при возникновении ошибки 404 будет загружена страница not_found.html
        error_page 500 501 502 503 504 /server_error.html; # при возникновении ошибок 500 501 502 503 504 будет загружена страница server_error.html
        error_page 403 http://website.com/; # при возникновении ошибки 403 будет загружена страница по адресу http://website.com/

        location / {
                try_files $uri $uri.html $uri.php $uri.xml
                @proxy;
        }
        # Следующий блок @proxy - это именованный блок, значения из которого будут подставлены в блок выше, через переменную @proxy
        location @proxy {
                proxy_pass 127.0.0.1:8080;
        }

    }
}

Установка Mime types.

http {

    include mime.types;

    location /downloads/ {

        default_type application/octet-stream;

        types {
                text/html html;
                image/gif gif;
                image/jpeg jpg;
        }

    }

}

Установка ограничений на ip-адреса.

location /admin/ {
    limit_except GET {
        allow 192.168.1.0/24;
        deny all;
    }
}

Установка базовой авторизации.

location /admin/ {

    allow 192.168.1.0/24;
    deny all;

    auth_basic "Authentication required";
    auth_basic_user_file conf/htpasswd;

}

Регулярные выражения в location.

server {
    server_name website.com;
    location ~ ^/abcd$ { # соответсвует, например, адресу http://website.com/abcd?param1&param2
    }
}

Приоритет адресов в location.

Nginx выбирает адреса в следующей приоритетной последовательности:

1. Есть модификатор ( = ), то есть четко указан точный адрес.
Например
location = /files/ {...}

2. Нет модификатора ( = ).
Например
location /files/ {...}

3. Есть модификатор ( ^~ ), то есть строка адреса должна начинаться с некоторой последовательности символов.
Например
location ^~ /doc {...}

4. Есть модификатор ( ~ ) или модификатор ( ~* ), то есть строка адреса должна соотвествовать условию регулярного выражения.
Например
location ~* ^/document$ {...}

5. Нет никакого модификатора.
Например 
location /doc {...}


Перезаписывание адресов модуль Rewrite.

rewrite hel{2,}o /hello.php; # invalid
rewrite "hel{2,}o" /hello.php; # valid
rewrite 'hel{2,}o' /hello.php; # valid

server {

    server_name website.com;

    location ~* ^/(downloads|files)/(.*)$ {
        add_header Capture1 $1;
        add_header Capture2 $2;
    }

}

server {

    server_name website.com;
    root /var/www/vhosts/website.com/httpdocs/;

    location /storage/ {
        internal;
        alias /var/www/storage/;
    }

    location /documents/ {
        rewrite ^/documents/(.*)$ /storage/$1;
    }

}

Часто используемые варианты перезаписи адресов через Rewrite.

Поиск данных на сайте.

URI в строке браузера
http://website.com/search/some-search-keywords

Переписанный на сервере URI
http://website.com/search.php?q=some-search-keywords

Правило для Rewrite
rewrite ^/search/(.*)$ /search.php?q=$1?;


Страница пользователя на сайте.

URI в строке браузера
http://website.com/user/31/James

Переписанный на сервере URI
http://website.com/user.php?id=31&name=James

Правило для Rewrite
rewrite ^/user/([0-9]+)/(.+)$ /user.php?id=$1&name=$2?;


Передача нескольких параметров в адресной строке.

URI в строке браузера
http://website.com/index.php/param1/param2/param3

Переписанный на сервере URI
http://website.com/index.php?p1=param1&p2=param2&p3=param3

Правило для Rewrite
rewrite ^/index.php/(.*)/(.*)/(.*)$ /index.php?p1=$1&p2=$2&p3=$3?;


Стиль Wikipedia.

URI в строке браузера
http:// website.com/wiki/Some_keyword

Переписанный на сервере URI
http://website.com/wiki/index.php?title=Some_keyword

Правило для Rewrite
rewrite ^/wiki/(.*)$ /wiki/index.php?title=$1?;


Стиль новостного сайта.

URI в строке браузера
http://website.com/33526/us-economy-strengthens

Переписанный на сервере URI
http://website.com/article.php?id=33526

Правило для Rewrite
rewrite ^/([0-9]+)/.*$ /article.php?id=$1?;


Стиль форума.

URI в строке браузера
http://website.com/topic-1234-50-some-keywords.html

Переписанный на сервере URI
http://website.com/viewtopic.php?topic=1234&start=50

Правило для Rewrite
rewrite ^/topic-([0-9]+)-([0-9]+)-(.*)\.html$ /viewtopic.php?topic=$1&start=$2?;


Условная переадресация.

server {

    if ($request_method = GET) {
       ...
    }

    if ($request_method = POST) {
       ...
    }

}
 
Server Side Includes (SSI)

server {

    server_name website.com;

    location ~* \.shtml$ {
        ssi on;
    }

}

<html>
<head>
    <!--# include file="header.html" -->
</head>
<body>
    <!--# include file="body.html" -->
    <!--# include virtual="/footer.php?id=123" -->
</body>
</html>

Установка главного файла Index (если никакой из файлов не указан в адресе, например, localhost/).

index file1 [file2…] [absolute_file];

Пример 1.

index index.php index.html index.htm;

Пример 2.

index index.php index2.php /catchall.php;

Показ всех файлов на сервере Autoindex.

autoindex on;



Включение базовой авторизации Basic Aithorization.

location /admin/ {
    auth_basic "Admin control panel";
    auth_basic_user_file access/password_file;
}

Разрешение доступа к содержимому страницы Access.

location {
    allow 127.0.0.1; # разрешить только ip-адрес 127.0.0.1
    deny all; # запретить все другие ip-адреса
}

Empty GIF.

location = /empty.gif {
    empty_gif;
}

FLV.

location ~* \.flv {
    flv;
}

Кэширование Memcached.

server {

    server_name example.com;

    location / {
        set $memcached_key $uri;
        memcached_pass 127.0.0.1:11211;
        error_page 404 @notcached;
    }

    location @notcached {
        internal;
        # Если файл не найден, то переадать запрос далее прокси-серверу
        proxy_pass 127.0.0.1:8080;
    }

}

Замена ip-адреса клиента на статичный ip-адрес Real IP.

Данный модуль просто заменяет ip-адрес клиента на адрес установленный в заголовке X-Real-IP HTTP header для клиентов посещающих сайт за прокси или для получения адресов с правильными заголовками, если Nginx используется, как backend server. Для использования этой опции необходимо вставить директиву  real_ip_header X-Real-IP или real_ip_header X-Forwarded-For. Затем необходимо определить доверенные ip-адреса, другими словами клиентов, которым дозволено использовать эти заголовки.

real_ip_header X-Forwarded-For;
set_real_ip_from 192.168.0.0/16;
set_real_ip_from 127.0.0.1;

SSL.

server {
    listen 443;
    server_name secure.website.com;
    ssl on;
    ssl_certificate /path/to/combined.crt;
    ssl_certificate_key /path/to/secure.website.com.key;
}

Страница с описанием текущего состояния сервера.

location = /nginx_status {
    stub_status on;
    allow 127.0.0.1; # вы возможно захотите ограничить доступ к данной странице
    deny all;
}

Взаимодействие Nginx с Django и Python.

server {

    server_name .website.com;
    listen 80;

    root /home/website/www;
    index index.html;

    location / {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_script_name;
        include fastcgi_params;
    }

}

Nginx как Reverse Proxy.

proxy_pass http://localhost:8080;
proxy_pass http://127.0.0.1:8080;
proxy_pass http://unix:/tmp/nginx.sock;
proxy_pass https://192.168.0.1;
proxy_pass http://localhost:8080/uri/;
proxy_pass http://unix:/tmp/nginx.sock:/uri/;
proxy_pass http://$server_name:8080;


--------------------------------------------------------------------------------------------------

# Используя upstream блок
upstream backend {
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;
}

location ~* \.php$ {
    proxy_pass http://backend;
}

--------------------------------------------------------------------------------------------------

server {

    server_name .example.com;
    root /home/example.com/www;

    location / {
        proxy_pass http://127.0.0.1:8080;
    }

}

--------------------------------------------------------------------------------------------------

upstream apache {
    server 192.168.0.1:80;
    server 192.168.0.2:80;
    server 192.168.0.3:80 weight=2;
    server 192.168.0.4:80 backup;
}

server {

    server_name .example.com;
    root /home/example.com/www;

    location / {
        proxy_pass http://apache;
    }

}