четверг, 27 декабря 2012 г.

Сервер для Django-приложений: Ubuntu Server 10.04 LTS + django 1.4 + nginx + gunicorn

Многие учебные пособия по разработке на Django раскрывают как быстро получить работающий отладочный сервер (python manage.py runserver), а вопрос развертывания в боевом режиме часто остается нераскрытым или освещаются далеко не самые простые и эффективные методы.
Ниже я расскажу о об одном из способов развернуть сайт на Django в боевом режиме, начиная от выбора хостинга, заканчивая развертыванием веб-сервера. Таким образом статья может быть полезна тем, кто освоил разработку на базе Django, но не имеет опыта развертывания серверов. Мой способ один из многих, но он достаточно прост, эффективен в работе и легок в поддержке. Используем VPS-хостинг, Ubuntu 10.04, nginx, gunicorn

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

Для дальнейшего повестования необходимо рассказать про структуру развертываемого проекта:
- myproject/ - корень проекта, обратите внимание, что это не корень исходников проекта; 
- env/ - вируальное окружение, создаваемое при помощи virtualenv;
- src/ - папка с иходниками, ее удобно добавить в пути IDE, для того, чтобы обращаться к пакету myproject по имени; 
    - myproject/ - корень исходников проекта, должна быть знакома Django-программистам;  
        - __init__.py - settings.py - manage.py 
        - urls.py  
        - myapp1/ 
        - myapp2/ ... 
    - static_content/ - папка для файлов, которые раздает веб-сервер первого эшелона (у нас - nginx), будучи параноиком, я боюсь передавать веб-серверу папку, содержащую исходники проекта; 
        - static/ - статические файлы проекта (то что храним в репозитории); 
        - media/ - media-файлы, то что создается сайтом в ходе его функционирования;  
- docs/ - тут лежат полезные документы, комментарии, примеры конфигов;  
- logs/ - папка, куда складываю логи, касающиеся работы сайта; 
- pids/ - тут pid-файлы.
 
На первый взгляд глубина вложенности исходников может показаться избыточной. Однако мой опыт показывает, что издержки на работу при такой глубине невелики, а достоинства большей структурированности значительны.

О хранении исходников

В рамках статьи не раскрывается вопрос хранения исходников проекта, поскольку выбор, организация, настройка доступа репозитория — отдельная тема для статьи.

Хостинг

Для себя я давно выяснил, что наиболее удобный хостинг для django — это VPS хостинг. Перепробовав несколько VPS-хостингов, я остановился на наиболее приемлемом в соотношении цена/качество — FirstVDS. Я пользуюсь тарифом за 400 рублей в месяц — 1500 MB RAM, 24000 MB HDD. Но сначала обходился тарифом за 150 рублей (в этом случае нужно будет научить некоторые приложения потреблять меньше ресурсов).
Итак, для того, чтобы начать нужно заказать и оплатить VPS, выбрав при этом тип виртуализации OpenVZ — неполная имитация физической машины, но для наших задач вполне достаточная, стоит заметить, что при такой виртуализации за те же деньги памяти дают больше, пригодится для memcached. В качестве операционной системы рекомендую выбирать Ubuntu Server 10.04 LTS#. Доступна также и Ubuntu Server 12.04 LTS, мне без особого труда удалось ввести ее в строй, однако шаблон на хостинге появился недавно, да и специалисты поддержки хостинг-провайдера не рекомендуют пока ее ставить на боевые сервера. Сейчас использую ее только на тестовом сервере.

Альтернативные Ubuntu Server операционные системы для хостинга

Наверняка найдутся адвокаты более стабильных систем для хостинга: FreeBSD, Debian, RedHat, CentOS. Не буду ввязываться в холивар. Замечу лишь, что мой опыт показывает, что для разработки на Django, часто требуются довольно новые версии пакетов и приложений. На перечисленные системы эти пакеты встают после подпирания множеством костылей, что, в итоге, сводит на нет ее надежность. В Ubutnu же новые версии пакетов принимаются в репозитории гораздо быстрее.

После заказа и оплаты на почту приходит SSH-доступ, теперь можно приступать к настройке операционной системы.

Ubuntu server

Получив доступ, я, первым делом, обновляю систему, затем отключаю root-доступ по SSH.
Подключиться по SSH в Windows можно широкоизвестной программой Putty, но я использую ее более “накрученную” модификацию — kitty. В качестве IP-адреса сервера вводим высланный хостером адрес, подключаемся, вводим root в качестве user и пароль при запросе.
Для подключения в Линукс-подобных системах используем родной терминал (Terminal, Konsole, etc.), набрав в нем нехитрую команду:
ssh root@1.2.3.4
где 1.2.3.4 — IP-адрес, высланный хостером, при запросе вводим пароль, высланный хостинг-провайдером.
Первым делом сменим пароль рута, паранойи ради:
passwd
по запросу вводим новый пароль дважды, генерировать и хранить советую в KeePassX, не стесняйтесь сделать его посложнее (>20 символов), использовать его почти не придется.
Обновляем пакеты в системе:
apt-get update apt-get upgrade
Добавляем пользователя, от лица которого будем развертывать сервер:
adduser myuser
можно ничего не вводить кроме пароля, но лучше его придумать посложнее
Теперь понадобится редактор для правки конфигов, я предпочитаю nano:
apt-get install nano
Добавляем пользователю права исполнять команды от имени root (sudo):
nano /etc/sudoers # находим строку 
root ALL=(ALL:ALL) ALL  
# сразу после нее вставляем 
myuser ALL=(ALL:ALL) ALL
Теперь отключаем возможность пользователю root логиниться по SSH (делать необязательно, мера безопасности):
nano /etc/ssh/sshd_config  
# ищем 
PermitRootLogin yes  
# меняем на 
PermitRootLogin no
после этого я перезагружаю машину, чтобы убедиться, что все прошло как надо:
reboot
Спустя минуту можно логиниться как myuser (или можете предварительно проверить, что логин рутом больше не работает):
ssh myuser@1.2.3.4
Теперь я ставлю ряд системных пакетов, необходимых для работы Django-приложения и инфраструктуры:
sudo apt-get install gcc mysql-server python-mysqldb memcached mercurial python-profiler w3m python-setuptools libmysqlclient-dev git-core python-dev rabbitmq-server supervisor nginx
Давайте разберем, что есть что:
  • gcc — компилятор C, C++, чего-то еще до кучи, определенно понадобится для сборки некоторых пакетов;
  • python-setuptools — установка команды easy_install, понадобится только для установки virtualenv, дело в том, что из системных пакетов virtualenv устанавливается не последней версии, с чем возникает ряд раздражающих проблем;
  • mysql-server — из названия ясно, что это MySQL-сервер, понадобится нам, раз мы собираемся поднимать сервер баз данных на хосте веб-приложения;
  • libmysqlclient-dev — этот пакет понадобиться для того, чтобы собрать интерфейс доступа к MySQL для python;
  • python-dev — API python’а, определенно понадобится для сборки некоторых пакетов;
  • supervisor — это программа — контроллер демонов, понадобится для приручения веб-сервера и, возможно, ряда других программ;
  • nginx — веб-сервер nginx, выражаю свою признательность Игорю Сысоеву;
  • rabbitmq-server — необязательно, AMQP-сервер, пригодится, если потребуется использовать celery;
  • memcached — необязательно, известная реализация кеша в оперативной памяти;
  • git-core — необязательно, клиент для системы контроля версий git, потребуется, если нужные пакеты хранятся в git-репозитории;
  • mercurial — необязательно, клиент для системы контроля версий mercurial (hg), потребуется, если нужные пакеты хранятся в mercurial-репозитории.

Развертывание проекта

Для развертывания воспользуемся виртуальным окружением, при помощи инструмента virtualenv.
В предыдущей главе мы установили полезную утилиту easy_install, с помощью которой установим теперь virtualenv последней версии:
sudo easy_install virtualenv
Примечание. Я намеренно не ставил pip глобально, чтобы не было случайных конфликтов с ним у pip’ов в виртуальных окружениях.
Теперь можно приступить к развертыванию проекта. Для начала нужно разместить его где-то в домашней директории, пусть это будет:
/home/myuser/web/myproject
Я пользуюсь системой контроля версий git. Но вы можете добиться этого простым копированием по SCP. В Windows можно использовать WinSCP, в линуксах файловые менеджеры поддерживают формат адреса sftp://myuser@1.2.3.4, как вы наверное догадались, в качестве аутентификационных используются данные для доступа по SSH.
В моем проекте в корне лежит файл для сборки виртуального окружения — build_env.sh:

#!/bin/bash  
echo $0: Creating virtual environment 
virtualenv --prompt="<myenv>" ./env 

mkdir ./logs 
mkdir ./pids 
mkdir ./db 
mkdir ./static_content 
mkdir ./static_content/media  

echo $0: Installing dependencies 
source ./env/bin/activate 
export PIP_REQUIRE_VIRTUALENV=true 
./env/bin/pip install --requirement=./requirements.conf --log=./logs/build_pip_packages.log  

echo $0: Making virtual environment relocatable 
virtualenv --relocatable ./env  

echo $0: Creating virtual environment finished.
 
и файл requirements.conf, который содержит пакеты, необходимые для работы приложения:

django 
git+git://github.com/sehmaschine/django-grappelli.git#egg=django-grappelli  
git+git://github.com/django-mptt/django-mptt.git#egg=django-mptt 
git+git://github.com/krvss/django-social-auth.git#django-social-auth  
git+git://github.com/gabrielhurley/django-wymeditor.git#django-wymeditor  
git+git://github.com/jtauber/django-mailer.git#django-mailer git+git://github.com/tweepy/tweepy.git#tweepy  
django-celery django-debug-toolbar  
django-pdb  
python-memcached  
MySQL-python xlrd  
unidecode  
anyjson  
gunicorn  
pillow 
south  
fabric 
requests  
xlwt
 
Это возможный набор пакетов, как-нибудь расскажу подробнее про некоторые из них, но мы не углубляемся в аспекты разработки в этой теме.
Итак, после запуска в папке проекта /home/myuser/web/myproject:
./build_env.sh
устанавливается виртуальное окружение для работы нашего сервера.
Теперь нужно позаботиться о создании базы данных. В наших проектах мы используем MySQL. Запускаем консоль MySQL:
mysql -uroot -pROOTPASSWORD
где создаем базу и пользователя:
CREATE DATABASE myproject CHARACTER SET utf8 COLLATE utf8_general_ci; CREATE USER 'myproject'@'localhost' IDENTIFIED BY 'USERPASSWORD'; GRANT ALL PRIVILEGES ON myproject.* TO ‘myproject'@'localhost';
теперь настройки доступа можно внести в файл настроек проекта (settings.py или local_settings.py).
Если у вас есть дамп базы — вы знаете, что делать. Если нет, то создаем в ней схему и необходимые данные:
cd ~/web/myproject # возвращаемся в папку проекта source env/bin/activate # активируем виртуальное окружение python manage.py syncdb # синхронизируем модели с базой данных теперь соберем статические файлы:
python manage.py collectstatic
На этом приложение готово к запуску.

Настройка веб-сервера Nginx

Для настройки веб-сервера Nginx нужно разместить конфиг myproject.conf (суффикс должен быть .conf) в папке /etc/nginx/sites-available/.
Создать и отредактировать файл можно в консоле SSH через nano:
sudo nano /etc/nginx/sites-available/myproject.conf
затем вставляем содержимое примера ниже (Shift+Insert), исправляем под свои нужды, сохраняем (Ctrl+O), выходим (Ctrl+X).
Пример содержания файла myproject.conf:

upstream myproject.ru {
    server localhost:12345 fail_timeout=0;
}

server {
    listen 80;
    server_name  www.myproject.ru;
    rewrite ^/(.*) http://myproject.ru/$1 permanent;
}

server {
    listen 80;
    client_max_body_size 4G;
    server_name myproject.ru;
    access_log  /home/myuser/web/myproject/logs/myproject.access.log;
    keepalive_timeout 5;

    root /home/myuser/web/myproject/static_content;
   
    location / {
        proxy_pass http://myproject.ru;
    }

    error_page 500 502 503 504 /500.html;
    location = /500.html {
        root /home/myuser/web/myproject/static_content/static/html;
    }

    location ~ ^/(static|media)/ {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        if (!-f $request_filename) {
            proxy_pass http://myproject.ru;
            break;
        }
     }
}


Попробуем разобраться в общих словах, что здесь к чему.
В данном примере upstream — сокет localhost:12345, в который будем пересылать все запросы, которые не удовлетворяют следующим url:
/static/* — статические файлы сайта;
/media/* — медиа-файлы, файлы, которые создаются в процессе функционирования сайта;
На этом сокете мы повесим на прослушивание наш gunicorn в следующей части статьи. Имя апстрима, теоретически, выбирается произвольно, однако я сталкивался с проблемами, в случае, если имя апстрима отличалось от доменного имени сайта (не помню текста ошибок Django, чтобы описать подробнее).

Еще интересные части конфига:
редирект с поддомена www.myproject.ru на myproject.ru, можете сделать наоборот, если вам больше нравится;
обработка ошибок 5XX орагнизована выдачей статического файла 500.html. Получить такой файл довольно просто: заставить сайт показать страницу 404, сохранить в браузере как 500.html и отредактировать текст ошибки;
в случае, если статический файл не найден, запрос направляется gunicorn’у, чтобы тот мог выдать стандартную ошибку 404.

После того, как файл конфига размещен где следует (можно проверить командой cat /etc/nginx/sites-available/myproject.conf), нужно проставить на него симлинк:
sudo ln -s /etc/nginx/sites-available/myproject.conf /etc/nginx/sites-enabled/
и перезапустить nginx:
sudo service nginx restart

Настройка gunicorn и supervisor

При развертывании проекта мы установили пакет gunicorn, теперь мы используем его для формирования динамичеких HTTP-ответов (HTTP-response) Django-приложением. Сам gunicorn умеет принимать запросы и формировать ответы на них, однако нужно поддерживать сам gunicorn запущенным, например стартовать при перезапуске системы, это мы поручим специализирующейся в этом программе supervisor.
Заметьте, что разработчики gunicorn крайне не рекомендуют ставить его на линию фронта, а поручить прием запросов от пользователей специализированным серверам, например nginx, как это делаем мы.
Итак, создаем в папке /etc/supervisor/conf.d/ файл myproject.conf следующего содержания:
[program:myproject]
command=/home/myuser/web/myproject/env/bin/python /home/myuser/web/myproject/src/myproject/manage.py run_gunicorn --bind=localhost:12345 --workers=3 --pid=/home/myuser/web/myproject/pids/gunicorn.pid --log-file /home/myuser/web/myproject/logs/gunicorn.log
directory=/home/myuser/web/myproject/src/myproject
umask=022
autostart=true
autorestart=true
startsecs=10
startretries=3
exitcodes=0,2
stopsignal=TERM
stopwaitsecs=10
user=myuser

Заметьте, что в параметрах gunicorn’у мы передаем для прослушки тот же порт (в нашем примере 12345), что указывали в конфиге nginx’а. Количество рабочих процессов установлено в значение 3, подбирал этот параметр субъективно для одного из сайтов, исходя из своих нагрузок, и пока не могу порекомендовать какое-либо значение.
После того как конфиг размещен в нужной папке (можно проверить запуском cat /etc/supervisor/conf.d/myproject.conf) нужно перечитать файл либо просто перезапустить supervisor, я использую второй вариант для надежности:
sudo supervisorctl reload
проверить успешность запуска можно командой:
sudo supervisorctl status
в случае успеха статус процесса myproject через несколько секунд станет RUNNING.

Устранение проблем

perl: warning: Setting locale failed.
С самого начала работы, при вводе команд, система начинает выдавать warning:
perl: warning: Setting locale failed. perl: warning: Please check that your locale settings: решается добавлением правильной локали:
locale-gen ru_RU.UTF8
по мотивам: http://askubuntu.com/questions/76013/how-do-i-add-locale-to-ubuntu-server


sudo: must be setuid root
При первом применении sudo из-под нового пользователя возможна ошибка:
sudo: must be setuid root
решается например так:
chmod 4755 /usr/bin/sudo

E: Unable to correct problems, you have held broken packages.
при установке некоторых пакетов в Ubuntu 12.04 (например python-dev или libmysql-dev) возможна ошибка:
libc6-dev : Depends: libc6 (= 2.15-0ubuntu10.2) but 2.15-0ubuntu10+openvz0 is to be installed E: Unable to correct problems, you have held broken packages. Для ее решения достаточно модифицировать файл /etc/apt/preferences.d/99ovz-libc-pin:
заменив
libc-bin libc6
на
libc-bin libc6 libc6-dev libc-dev-bin

Couldn't open /dev/null: Permission denied
При создании пользователя может возникать ошибка:
Couldn't open /dev/null: Permission denied
решал так:
sudo chmod 666 /dev/null
не знаю, насколько это корректно, но я опасностей не увидел.


Заключение

Отметим положительные моменты такого развертывания:
  • Развертывание решения на VPS, виртуальная машина дает практически неограниченные возможности в администрировании.
  • Независимость nginx от gunicorn, как это часто предлагается при использовании Apache и mod_python, например. В частности довольно легко подменить, например для отладки, gunicorn разработческим сервером:
    sudo supervisorctl stop myproject python manage.py runserver localhost:12345 # из папки с исходниками
    теперь nginx будет передавать запросы на сервер разработчика, даже не узнав про изменения.
  • Nginx в качестве раздавальщика статических файлов признан одним из лучших, может даже лучшим.
  • virtualenv позволяет легко и непринужденно изолировать виртуальные окружения разных проектов друг от друга. В наше время издержки дискового пространства несравнимо дешевле возни с конфликтами версий пакетов.
  • gunicorn под контролем supervisor значительно удобнее и надежнее способов запуска gunicorn под контролем скриптов в /etc/init.d/ и некоторых других способов запуска, так как дает способ мониторинга запущенных программ, заботливо перезапускает программы в случае сбоев.

В сатье расмотрен лишь один из множества вариантов развертывания Django-приложения, я пришел к нему путем многих проб и ошибок. Мои рекомендации не претендуют на истину в последней инстанции. Более того, буду рад любой конструктивной критике.


Полезные ссылки

  1. FirstVDS — дешевый VPS-хостинг, по ссылке заказ на четверть дешевле.
  2. Putty и Kitty — SSH-клиенты под Windows.
  3. WinSCP — SCP-клиент под Windows, не нужно поднимать FTP-сервер, просто используйте имеющийся SSH-аккаунт.
  4. KeePassX — утилита хранения паролей, кроссплатформенная.
  5. Ubuntu LTS — политика выпусков релизов Ubuntu Long Term Support.
  6. Ubuntu Security — настройка для параноиков для десктопа, но что-то можно почерпнуть для сервера.
  7. Django Deployement — другие способы развертывания сайтов на Django.
  8. virtualenv — использование virtualenv.
  9. Nginx — много интересного о настройке nginx.
  10. Supervisor+gunicorn — об использовании gunicorn через nginx.

среда, 26 декабря 2012 г.

Установка Tornado

Скачиваем архив tornado-2.4.1.tar.gz и распаковываем его на диск С.

Открываем консоль командной строки и вводим следующие команды:

cd tornado-2.4.1
python setup.py build
python setup.py install

После этого сервер Tornado будет установлен на ваш компьютер.

Проверяем работу сервера.

Открываем в консоли командной строки интерпретатор Python:

python

и вводим следующие команды:

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

application = tornado.web.Application([
    (r"/", MainHandler),
])

application.listen(8888)
tornado.ioloop.IOLoop.instance().start()

После этого открываем браузер и переходим в нем по адресу http://127.0.0.1:8888/

В результате открывается страница с сообщением "Hello, world".



Это означает, что сервер Tornado работает.

Использование Nginx вместе с Tornado

Установка.

Устанавливаем Tornado:

cd /usr/ports/www/py-tornado
make install clean

Устанавливаем Nginx, если он у вас не установлен:

cd /usr/ports/www/nginx-devel
make install clean

Настройка.

Теперь настроим Nginx для проксирования на Tornado:

server {

    listen 80;
    server_name liburg.ru;

    location ^~ /admin-media {
        alias /usr/local/lib/python2.6/site-packages/django/contrib/admin/media;
    }

    location = /robots.txt {
        root /www/liburg/static/;
    }

    location ~* \.(jpg|jpeg|gif|png|ico|css|zip|js|swf)$ {
        root /www/liburg/static/;
        expires 7d;
    }

    location / {
        proxy_pass http://127.0.0.1:8001/;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

В корень проекта (рядом с manage.py, settings.py и т.д.) кладем файл "tornading.py":

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sys
import signal
import fcntl
import time
from subprocess import Popen
import logging
import logging.handlers

import tornado.httpserver
import tornado.ioloop
import tornado.wsgi

PORT = 8001
HOST = 'liburg.ru'  # видно в top, htop, ps, etc
LOG_FILE = '/var/log/tornado.log'  # '' for not write log
LOG_LEVEL = 'INFO'  # INFO (все статусы), WARNING (>=404), ERROR (>=500)

# настраиваем Django
sys.path.insert(0, '/'.join(os.path.dirname(__file__).split('/')[:-1]))
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

# если сайт не на Django, просто импортируем wsgi-объект как aplication
#~ from wsgi_app import application

# настраиваем логирование в файл
os.chdir(os.path.dirname(os.path.abspath(__file__)))
if LOG_FILE:
    try:
        os.makedirs(os.path.split(LOG_FILE)[0])
    except OSError:
        pass
    file_handler = logging.handlers.RotatingFileHandler(
        filename = LOG_FILE, mode='a+',  # имя файла
        maxBytes = 1000000,  # максимально байт в файле
        backupCount = 2)  # максимум файлов
    file_handler.setLevel(getattr(logging, LOG_LEVEL))
    file_handler.setFormatter(
        logging.Formatter('%(asctime)s\t%(levelname)-8s %(message)s',
            datefmt = '%d-%m-%Y %H:%M:%S'))
    logging.getLogger('').setLevel(logging.NOTSET)
    logging.getLogger('').addHandler(file_handler)

# блокируемый файл для проверки активности сервера
PID_FNAME = '/tmp/' + '_'.join((os.path.abspath(__file__).strip('/').split('/'))) + '.pid'
COMMANDS = ['start', 'stop', 'restart']


def daemon():
    logging.critical('--- SERVER (RE)STARTED')
    f = open(PID_FNAME, 'w')
    fcntl.flock(f.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
    f.write('%-12i' % os.getpid())
    f.flush()

    container = tornado.wsgi.WSGIContainer(application)
    http_server = tornado.httpserver.HTTPServer(container)
    http_server.listen(PORT)
    tornado.ioloop.IOLoop.instance().start()


def start():
    started = alegry_started()
    if not started:
        pid = Popen([HOST, os.path.abspath(__file__), 'daemon'],
            executable='python').pid
        print 'Server started at port %s (pid: %i)...' % (PORT, pid)
    else:
        print 'Server alegry started (pid: %i)' % started


def stop():
    started = alegry_started()
    if started:
        os.kill(started, signal.SIGKILL)
        print 'Server stoped (pid %i)' % started
    else:
        print 'Server not started'


def restart():
    stop()
    time.sleep(1)
    start()


def alegry_started():
    '''
    Если сервер запущен, возвращает pid, иначе 0
    '''
    if not os.path.exists(PID_FNAME):
        f = open(PID_FNAME, "w")
        f.write('0')
        f.flush()
        f.close()

    f = open(PID_FNAME, 'r+')
    try:
        fcntl.flock(f.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
    except IOError:
        started = int(f.read())
    else:
        started = 0
    f.close()
    return started


if len(sys.argv) == 2 and sys.argv[1] in (COMMANDS + ['daemon']):
    cmd = sys.argv[1]
    globals()[cmd]()
else:
    print 'Error: invalid command'
    print 'Usage: python tornading.py {%s}.' % '|'.join(COMMANDS)

Стартуем Nginx и Tornado:

/usr/local/etc/rc.d/nginx start
cd /www/liburg/ && python tornading.py start

На случай падения Tornado - добавьте в крон задание на запуск сервера:

* * * * * cd /www/liburg/ && /usr/local/bin/python tornading.py start

Установка Nginx под Windows

Чтобы установить nginx/Windows, скачайте дистрибутив с сайта nginx.org. Затем распакуйте дистрибутив, перейдите в каталог nginx-1.3.10 и запустите nginx. Вот пример для корневого каталога на диске C:

cd c:\
unzip nginx-1.3.10.zip
cd nginx-1.3.10
start nginx

(Опытным путем было выяснено, что в тарых версиях под Windows Nginx должен быть обязательно установлен на диск C, иначе он не запускается. Но в новых версиях (проверил на nginx/Windows-1.0.11) это замечание не актульно. Устанавливать можно на любой диск.)

В результате выполнения данных команд запустится сервер Nginx.
Проверить его работу вы можете в браузере, перейдя по адресу http://localhost





Чтобы увидеть процессы nginx, запустите утилиту командной строки tasklist:

C:\nginx-1.3.10>tasklist /fi "imagename eq nginx.exe"
C:\nginx-1.3.10>tasklist /fi "imagename eq nginx.exe"

Image Name           PID Session Name     Session#    Mem Usage
=============== ======== ============== ========== ============
nginx.exe            652 Console                 0      2 780 K
nginx.exe           1332 Console                 0      3 112 K



Один из процессов основной, другой - рабочий. Если nginx не запускается, нужно искать причину в в файле лога ошибок logs\error.log. Если же лог-файл не создался, то причину этого следует искать в Windows Event Log. Если вместо ожидаемой страницы выводится страница с ошибкой, нужно также искать причины ошибки в файле logs\error.log.

nginx/Windows использует каталог, в котором он был запущен, в качестве префикса для относительных путей в конфигурации. В вышеприведённом примере префиксом является C:\nginx-1.3.10\. Пути в конфигурационном файле должны задаваться в UNIX-стиле с использованием прямых слэшей:

access_log   logs/site.log;
root         C:/web/html;

nginx/Windows работает как стандартное консольное приложение (не сервис) и управляется при помощи следующих команд:

nginx -s stop     быстрое завершение
nginx -s quit     плавное завершение
nginx -s reload     изменение конфигурации, запуск новых рабочих процессов с новой конфигурацией, плавное завершение старых рабочих процессов
nginx -s reopen     переоткрытие лог-файлов


Для простоты управления веб-сервером nginx создадим несколько bat файлов в папке сервера C:\nginx-1.3.10:

Файл start.bat

@ECHO OFF
start C:\nginx-1.3.10\nginx.exe

ping 127.0.0.1 > NUL
echo Starting nginx
ping 127.0.0.1 > NUL
EXIT

Файл stop.bat

@ECHO OFF
start C:\nginx-1.3.10\nginx.exe -s stop


Файл reload.bat

@ECHO OFF
start C:\nginx-1.3.10\nginx.exe -s reload


http://coder.v-tanke.ru/download/file.php?id=168&mode=view&h=/pic.png

При запуске файла start.bat на некоторое время появится окно, показывающее, что серевер запускается.

http://coder.v-tanke.ru/download/file.php?id=169&mode=view&h=/pic.png


Установка MySQL.

Создадим папку C:\nginx-1.3.10\mysql

Скачиваем MySQL установщик mysql-5.1.41-win32.msi и запускаем его.

http://coder.v-tanke.ru/download/file.php?id=423&mode=view&h=/pic.png

Нажимаем "Next".

http://coder.v-tanke.ru/download/file.php?id=424&mode=view&h=/pic.png

Выбираем режим "Custom", чтобы иметь возможность указать папки для установки и исключаем из установки документацию ("Documentation").

http://coder.v-tanke.ru/download/file.php?id=425&mode=view&h=/pic.png

Затем выбираем пункт "MySQL Server" и нажимаем кнопку "Change...", после чего выбираем созданную нами ранее директорию C:\nginx-1.3.10\mysql.

Повторяем выбор директории и для пункта "MySQL Server Datafiles". После этого нажимаем "Next".


http://coder.v-tanke.ru/download/file.php?id=180&mode=view&h=/pic.png

Просматриваем, что все верно и жмем "Install".
Теперь ждем пока MySQL установится.

http://coder.v-tanke.ru/download/file.php?id=426&mode=view&h=/pic.png

Далее появляется рекламка, но она нам неинтересна, поэтому пролистываем ее нажимая кнопку "Next".

После этого появляется окно с приглашением выполнить настройку MySQL и зарегистрировать его.

Регистрировать не будем, поэтому снимаем эту галочку и жмем кнопку "Finish".

http://coder.v-tanke.ru/download/file.php?id=427&mode=view&h=/pic.png

Открывается окно настройки MySQL, жмем кнопку "Next".

http://coder.v-tanke.ru/download/file.php?id=428&mode=view&h=/pic.png

Выбираем "Standard Configuration", жмем кнопку "Next".

http://coder.v-tanke.ru/download/file.php?id=429&mode=view&h=/pic.png

Далее ничего не меняем, жмем кнопку "Next".

http://coder.v-tanke.ru/download/file.php?id=430&mode=view&h=/pic.png

После этого нас просят указать пароль для пользователя root имеющего полные права на доступ и управление MySQL.

http://coder.v-tanke.ru/download/file.php?id=431&mode=view&h=/pic.png

Запомните, а лучше даже запишите эти данные (логин - root, пароль - который Вы укажите), так как они потребуются нам позже, при установке на веб-сервер какого-либо php-скрипта, работающего с базой данных.

http://coder.v-tanke.ru/download/file.php?id=432&mode=view&h=/pic.png

Все готово к применению настроек жмем "Execute".

Если никаких проблем не возникло, должно результат должен быть как на картинке ниже.

http://coder.v-tanke.ru/download/file.php?id=433&mode=view&h=/pic.png

Жмем кнопку "Finish"

На этом установка MySQL оканчивается.

Установка PHP.

Скачаем и распакуем php-5.2.12-Win32-VC6-x86.zip в  C:\nginx-1.3.10\php

Скопируем C:\nginx-1.3.10\php\php.ini-recommended в C:\nginx-1.3.10\php\php.ini
Далее переходим к редактированию C:\nginx-1.3.10\php\php.ini

Внимание! По умолчанию вывод ошибок на страницах отключен.
Вывод ошибок рекомендуется включать только для тестирования и отладки скриптов. Для включения необходимо заменить

  Код:
    display_errors = Off

на

  Код:
    display_errors = On


Далее увеличиваем ограничения на вложения
заменить

  Код:
    post_max_size = 8M

на

  Код:
    post_max_size = 30M


заменить

  Код:
    upload_max_filesize = 2M

на

  Код:
    upload_max_filesize = 20M


Затем указываем директорию с расширениями - заменяем

  Код:
    extension_dir = "./"

на

  Код:
    extension_dir = "./ext"


После этого подключаем необходимые расширения, найдя и раскомментировав (убрав ";" вначале строки) следующие строки

  Код:
    ;extension=php_gd2.dll
    ;extension=php_mbstring.dll
    ;extension=php_sockets.dll
    ;extension=php_mysql.dll
    ;extension=php_mcrypt.dll
    ;extension=php_zip.dll


Дорабатываем .bat файлы созданные на первом этапе.

Файл start.bat

@ECHO OFF
start C:\nginx-1.3.10\nginx.exe
start C:\nginx-1.3.10\php\php-cgi.exe -b 127.0.0.1:521 -c c:\nginx\php\php.ini
ping 127.0.0.1 > NUL
echo Starting nginx
ping 127.0.0.1 > NUL
EXIT


Файл stop.bat

@ECHO OFF
taskkill /f /IM nginx.exe
taskkill /f /IM php-cgi.exe
EXIT


Теперь при запуске start.bat вместе с Nginx будет запускаться и PHP.
Внимание! После запуска start.bat появляется консольное окно php-cgi, которое не надо закрывать!

Если открытое окно мешает можно воспользоваться следующим способом:

Вариант скрытого запуска php-cgi.

1. Скачать программу chp.exe http://www.commandline.co.uk/chp/
2. Разместить chp.exe в каталоге с nginx ( C:\nginx-1.3.10\chp.exe)
3. Модифицировать start.bat следующим образом:

  Код:
    @ECHO OFF
    start  C:\nginx-1.3.10\nginx.exe
    chp.exe " C:\nginx-1.3.10\php\php-cgi.exe -b 127.0.0.1:521 -c  C:\nginx-1.3.10\php\php.ini"
    ping 127.0.0.1 > NUL
    echo Starting nginx
    ping 127.0.0.1 > NUL
    EXIT

Еще один вариант (но chp.exe под Windows 7 не заработал).

1. Скачать программу Hidden Start http://www.ntwind.com/software/hstart.html
2. Разместить hstart.exe в каталоге с nginx (C:\nginx-1.3.10\hstart.exe)
3. Модифицировать start.bat следующим образом:

  Код:
    @ECHO OFF
    start C:\nginx-1.3.10\nginx.exe
    start C:\nginx-1.3.10\hstart.exe /NOCONSOLE "C:\nginx-1.3.10\php\php-cgi.exe -b 127.0.0.1:521 -c C:\nginx-1.3.10\php\php.ini"
    ping 127.0.0.1 > NUL
    echo Starting nginx
    ping 127.0.0.1 > NUL
    EXIT

Далее создадим в папке C:\nginx-1.3.10\html (являющеюся на данный момент корневой для веб-сервера) файл test.php следующего содержания:

<?php phpinfo(); ?>

После запускаем наш веб-сервер, через файл start.bat и открываем в браузере адрес http://localhost/test.php

http://coder.v-tanke.ru/download/file.php?id=172&mode=view&h=/pic.png

Как вы можете видеть nginx отдал php-файл как обычный текстовый,
потому что мы еще не сказали ему как с ними работать.

Итак, на этом этап настройки php можно считать оконченным, остановить веб-сервер, используя файл stop.bat и переходить к настройке nginx.

Настройка Nginx.

Так как, скорее всего, наиболее популярным будет вопрос по созданию виртуальных хостов в Nginx, то сразу рассмотрим как их сделать на примере установки phpMyAdmin на отдельный хост.

Файл с основным конфигом nginx у нас находится в папке C:\nginx-1.3.10\conf и называется nginx.conf.

Создадим папки, которые будут корневыми для наших виртуальных хостов: C:\nginx-1.3.10\html\default и C:\nginx-1.3.10\html\pma

Итак приступим к настройке.
Пропишем в C:\WINDOWS\system32\drivers\etc\hosts имя хоста для доступа к phpMyAdmin.

Код:

127.0.0.1       pma

Может потребовать перезагрузить браузер или компьютер, если изменения в файле hosts не подхватятся сразу.

Заменим содержимое C:\nginx-1.3.10\conf\nginx.conf на код:

    worker_processes  1;

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

    events {
        worker_connections  64;
    }

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

        log_format  main  '$remote_addr - $remote_user "$request" $status "$http_referer" "$http_user_agent"';
      
        sendfile        on;
        #tcp_nopush     on;
      
        client_header_timeout  3m;
        client_body_timeout    3m;
        send_timeout           3m;
      
        #keepalive_timeout  0;
        keepalive_timeout  65;
        #gzip  on;


        server {
            root                 html/default/;
            set  $root_for_cgi   "C:/nginx-1.3.10/html/default/";
            listen               80;
            server_name          _;
          
            access_log logs/default.access.log main;
            error_log logs/default.error.log error;
      
            location / {
                index index.php;
            }
          
            location ~* .php$ {
                include fastcgi;
            }
        }
      
        server {
            root                 html/pma/;
            set  $root_for_cgi   "C:/nginx-1.3.10/html/pma/";
            listen               80;
            server_name          pma;
          
            access_log logs/pma.access.log main;
            error_log logs/pma.error.log error;
      
            location / {
                index index.php;
            }
          
            location ~* .php$ {
                include fastcgi;
            }
        }
      
      
        upstream  backend  {
            server   127.0.0.1:521;
        }

    }

И создадим файл C:\nginx-1.3.10\conf\fastcgi с кодом:

fastcgi_connect_timeout 1;
fastcgi_next_upstream timeout;

fastcgi_param  SCRIPT_FILENAME  $root_for_cgi$fastcgi_script_name;

fastcgi_pass   backend;

fastcgi_param  QUERY_STRING     $query_string;
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  SCRIPT_NAME        $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;

Для теста в папке C:\nginx-1.3.10\html\default создадим файл C:\nginx-1.3.10\html\test.php с кодом:

<?php phpinfo(); ?>

А в папке C:\nginx-1.3.10\html\pma создадим файл test2.php с кодом:

<?php echo 'For phpMyAdmin'; ?>

Теперь запускаем наш веб-сервер (через файл start.bat) и смотрим что получилось:

http://coder.v-tanke.ru/download/file.php?id=173&mode=view&h=/pic.png

http://coder.v-tanke.ru/download/file.php?id=174&mode=view&h=/pic.png

Теперь у нас есть работающий вер-сервер.

Установка связки Nginx + Apache.

Выше рассматривался вариант установки чистой связки Nginx + PHP + MySQL. Далее мы рассмотрим установку Nginx как front-end к Apache. То есть все запросы изначально будут обрабатываться Nginx - это значит, что статичные файлы будут отдаваться сразу, а обработка остальных файлов будет передаваться серверу Apache.

http://coder.v-tanke.ru/download/file.php?id=1057&sid=6b8979befe3d91ca4d58e4ee6e548073&mode=view&h=/pic.png

 Для установки нам понадобится:

    - установленный Apache
    - актуальная версия Nginx

Вместо чистого Apache можно применять любую сборку веб-сервера основанную на Apache: например Denwer (Денвер), TopServer, XAMPP и тому подобное, либо собрать связку Apache + PHP + MySQL самому вручную.

Итак, порядок установки:
Этап 1. Перенос Apache на порт отличный от 80-го.
Этап 2. Настройка Nginx для работы с Apache.
Этап 3. Установка и настройка RPAF в Apache.

Этап 1. Перенос Apache на порт отличный от 80-го.

Изначально Apache настроен на прослушивание 80-го порта, что вполне логично и правильно, но в нашем случае 80-й порт будет прослушиваться Nginx'ом, поэтому и требуется перенести Apache на другой порт.

Открываем C:\Program Files\Apache Software Foundation\Apache2.2\conf\httpd.conf и ищем в нем строчку Listen 80 (либо свой номер порта, если у Вас веб-сервер был установлен на другом порту) и заменяем ее на Listen 127.0.0.1:81
Также просматриваем строчки задания виртуальных хостов (если они есть) и меняем их тоже:
находим NameVirtualHost *:80 и меняем на NameVirtualHost *:81
находим все <VirtualHost *:80> и меняем на <VirtualHost *:81>

После этого сохраняем изменения и перезапускаем Apache.

Теперь можно проверить, что веб-сервер отвечает на порту 81 (Для проверки был создан файл test.php содержащий <?php phpinfo(1); ?>).

http://coder.v-tanke.ru/download/file.php?id=1053&sid=6b8979befe3d91ca4d58e4ee6e548073&mode=view&h=/pic.png

Этап 2. Настройка Nginx для работы с Apache.

Открываем файл конфига  C:\nginx-1.3.10\conf\nginx.conf и заменяем его на код:

#2 рабочих процесса
worker_processes  2;

# лог для ошибок
error_log   C:/nginx-1.3.10/logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

events {
    # максимум рабочих соединений
    worker_connections   2000;
}

http {
    include       mime.types;
    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  logs/access.log  main;

    # Таймаут при чтении заголовка запроса клиента
    client_header_timeout  3m;
    # Таймаут при чтении тела запроса клиента
    client_body_timeout    3m;
    # Таймаут при передаче ответа клиенту
    send_timeout           3m;
    # Таймаут keep-alive соединения
    keepalive_timeout      2m;
   
    #gzip  on;
   
    server {
        # Слушать 80 порт
        listen       80;
        # Использовать следующие хосты.
        server_name  _;

        # Лог доступа для конкретного виртуального хоста
        #access_log  logs/host.access.log  main;

        # Отдаем статику напрямую
        location ~* \.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|js)$ {
            root         C:/Program Files/Apache Software Foundation/Apache2.2\htdocs;
            access_log   off;
            expires      30d;
        }
        # Запрещаем обращение к файлам .htaccess и .htpasswd
        location ~ /\.ht {
                deny  all;
        }
        # Передаем запрос Apache
        location / {
                # Адресс и порт Apache
                proxy_pass http://127.0.0.1:81/;
                proxy_redirect     off;

                proxy_set_header   Host             $host;
                proxy_set_header   X-Real-IP        $remote_addr;
                proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

                # Максимальный размер тела запроса клиента
                client_max_body_size       10m;
                client_body_buffer_size    128k;
                #client_body_temp_path      tmp/client_body_temp;

                proxy_connect_timeout      90;
                proxy_send_timeout         90;
                proxy_read_timeout         90;

                proxy_buffer_size          4k;
                proxy_buffers              4 32k;
                proxy_busy_buffers_size    64k;
                proxy_temp_file_write_size 64k;
                #proxy_temp_path            tmp/proxy_temp;

                charset  koi8-r;
        }

        #error_page  404              /404.html;

        # При перечисленных ошибках показывать статическую страницу /50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

Комментарии по тексту есть, но все же поясню пару мест.

Если на сервере будет находиться не один сайт, как в конфиге выше, а несколько, то для каждого должен быть указан свой блок server. Причем первый блок server считается сервером по умолчанию и он будет вызываться при обращении по IP или хосту не описанному ни в одном server_name.
В server_name может быть указано: "_" - аналог default в Apache; один или несколько хостов через пробел; хост начинающийся с точки - описывает все его поддомены

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

...
http {
    ...
    server {
        # хост по умолчанию
        server_name  _;
        ...
    }

    server {
        # несколько перечисленных хостов
        server_name  pupkin.ru www.pupkin.ru;
        ...
    }

    server {
        # все поддомены vasia.ru
        server_name  .vasia.ru;
        ...
    }

}

Этап 3. Установка и настройка RPAF в Apache.

Так как у нас обращение к Apache идет не напрямую, а через Nginx, то теперь в REMOTE_ADDR у нас не пользовательский IP, а IP-адрес сервера, на котором расположен Nginx. Поэтому на помощь приходит RPAF, он берет тело заголовка X-Forwarded-For, присланного от фронтенда и формирует в Apache из него REMOTE_ADDR.

Таким образом заголовок REMOTE_ADDR снова имеет пользовательский IP.

Скачиваем mod_rpaf
mod_rpaf.rar
и распаковываем в папку модулей Apache (C:\Program Files\Apache Software Foundation\Apache2.2\modules). После этого открываем C:\Program Files\Apache Software Foundation\Apache2.2\conf\httpd.conf и добавляем в конец файла следующий код:

LoadModule rpaf_module modules/mod_rpaf.so

RPAFenable On
RPAFsethostname On
RPAFheader X-Forwarded-For
RPAFproxy_ips 192.168.1.26 127.0.0.1

Вместо 192.168.1.26 укажите IP адрес сервера, на котором расположен Nginx.
Теперь сохраняем изменения и перезапускаем Apache.

Также желательно перенести папку C:\Program Files\Apache Software Foundation\Apache2.2\icons в папку C:\Program Files\Apache Software Foundation\Apache2.2\htdocs. Без этого при просмотре содержимого каталогов (опция Indexes в Apache) Nginx будет пытаться загрузить несуществующие иконки для файлов.

Теперь можно запустить Nginx (start.bat) и проверить работу веб-сервера в браузере.

Введем в адресной строке http://localhost/test.php (файл test.php мы создали на первом шаге) и увидим страницу.

http://coder.v-tanke.ru/download/file.php?id=1056&sid=6b8979befe3d91ca4d58e4ee6e548073&mode=view&h=/pic.png

На этом можно и остановиться.