пятница, 28 декабря 2012 г.

MongoDB Установка и работа с базой данных

Установка MongoDB на Windows.

MongoDB - это пакет программного обеспечения с открытым исходным кодом, который можно загрузить с веб-сайта mongodb.com. Чтобы найти ссылки на скачивание набора двоичных файлов для Windows, достаточно открыть этот сайт в браузере; ищите вверху в правой части страницы ссылку Downloads. Или, если вы предпочитаете прямые ссылки, используйте mongodb.org/display/DOCS/Downloads. На момент написания этой статьи стабильной версией является выпуск 2.2.2. Это не более чем ZIP-архив файлов, поэтому его установка, фигурально выражаясь, смехотворно проста: просто распакуйте содержимое архива в подходящее вам место на диске.

Нет, серьезно. Это все.

ZIP-файл создает три каталога: bin, include и lib. Единственный интересный каталог — bin, в котором содержатся восемь исполняемых файлов. Никакие другие двоичные зависимости (или исполняющая среда) не нужны, а на данный момент нас интересуют лишь два из этих исполняемых файлов. Это mongod.exe (процесс самой базы данных MongoDB) и mongo.exe (клиент оболочки командной строки, который обычно используется для проверки правильно установки и корректности работы, прямого просмотра данных и выполнения административных задач.

Упрощенно процедура установки выглядит так:

1. Скачиваем архив mongodb с сайта.
2. Распаковываем (например, C:\mongodb)
3. Для сервера mongodb нужна папка db, при запуске сервер ищет директории data/db или db в той же директории, где распаковали. Соответственно, создаем папки data и db: C:\data\ и C:\data\db
4. Пробуем запустить через cmd:
C:\mongodb\bin\mongod.exe

(Замечание. Если при запуске в Windows XP у вас появилось сообщение об ошибке "The procedure entry point InterlockedCompareExchange64 could not be located in the dynamic link library KERNEL32.dll", то это означает, что вы скачали последнюю версию MongoDB, которая уже не поддерживает Windows XP. В этом случае вам необходимо скачать более старую версию MongoDB, имеющую номер 2.0.x, в которой поддержка Windows XP присутствует.)


Запуск Mongod.exe для проверки успешности установки.

Проверить корректность установки так же легко, как запустить mongod из клиента командной строки. По умолчанию MongoDB хранит данные по пути C:\data\db, но это можно изменить с помощью текстового файла, передаваемого по имени в командной строки через --config. Проверка правильности  установки осуществляется очень просто: если на момент запуска mongod существует подкаталог db, то все работает правильно.



Если этого каталога db нет, то MongoDB не станет создавать его. Заметьте, что в моей системе Windows 7 при запуске MongoDB обычно выскакивает окошко с «This application wants to open a port» («Это приложение собирается открыть порт»). Убедитесь, что порт доступен (по умолчанию - 27017), иначе подключение к нему будет сильно затруднено.

После запуска сервера подключение к нему с помощью оболочки весьма тривиально: приложение mongo.exe запускает среду командной строки, которая обеспечивает прямое взаимодействие с сервером.



По умолчанию оболочка соединяется с тестовой базой данных test. Так как сейчас нам нужно лишь проверить, что все работает, то test отлично подходит для наших целей. Конечно, с этого момента можно сравнительно легко создать какие-то данные для работы с MongoDB, например объект, описывающий некую персону.



По сути, MongoDB использует нотацию данных JSON (JavaScript Object Notation), что объясняет ее гибкость и то, как с ней взаимодействуют клиенты. На внутреннем уровне MongoDB хранит все в BSON - двоичном надмножестве JSON - для упрощения хранилища и индексации. Однако JSON остается предпочтительным форматом ввода-вывода MongoDB, и обычно именно этот формат используется между веб- и вики-сайтами MongoDB. Если вы не знакомы с JSON, советую подучить его, прежде чем всерьез браться за MongoDB. А пока, просто смеха ради, загляните в каталог, в котором mongod хранит данные, и вы увидите, что в нем появилась пара файлов с именами, начинающимися с test.

Для выхода из оболочки достаточно ввести exit, а для закрытия сервера нажмите Ctrl+C в окне или просто закройте окно; сервер захватывает уведомление о закрытии и корректно завершает все до прекращения работы своего процесса.

Работаем с MongoDB через консоль.

Теперь, когда сервер MongoDB установлен и запущен, попробуем поработать с этой базой данных. Запускаем cmd.exe, переходим в директорию с распакованной mongodb и запускаем mongo.exe:
 
C:\mongodb\bin\mongo.exe



Так мы запустили клиент-консоль MongoDB. По умолчанию у нас доступна база данных test. Создадим в ней коллекцию foo:

>db.foo.save(x)

Этой командой мы пробуем обновить запись в коллекции foo, с JSON объектом x, если такой не найдется, то запись будет создана. Данная команда эквивалентна следующей:

>db.foo.update({_id:x._id})

Еще пример:

>db.foo.save({name:"Andrew",_id: ObjectId(«4b9e4a1fc583fa1c76198319″)})

Данная команда обновит запись с _id = "4b9e4a1fc583fa1c76198319", либо создаст новую если не найдет.

Для нахождения всех записей проделаем следующее:

>db.foo.find()

Выдаст:
{ "_id" : ObjectId("4f40e0a30418c15c0189233b"), "name" : "Andrew" }

Не забываем, что все данные MongoDB хранит в JSON формате, что весьма удобно в работе с JavaScript.

В самой консоли mongo.exe все пишется на JavaScript - это значит, что вы можете писать так:

>var doc = db.foo.find()

В doc у вас будет хранится "объект объектов", чтобы преобразовать его в массив объектов можно написать следующее:

>var doc = db.foo.find().toArray()

Выборка записей в MongoDB.

Пример в SQL:

SELECT * FROM foo WHERE name = "Andrew"

В MongoDB будет писаться так:

>db.foo.find({name:"Andrew"})

SELECT age FROM users WHERE name = "Andrew"

Выглядит так:

>db.users.find({name:"Andrew"}, {age:true})

Выборка самой первой записи:

SELECT * FROM users WHERE foo = "bar" LIMIT 1

>db.foo.find({foo:"bar"}).limit(1)

Или еще короче:

>db.foo.findOne({foo:"bar"})

Срединение с MongoDB через Python с использованием библиотеки PyMongo.

PyMongo это простая библиотека на языке Python, которая позволяет получить доступ к MongoDB API из ваших приложений. Вы можете скачать PyMongo здесь: http://api.mongodb.org/python/current/.

После установки PyMongo откройте через консоль интерактивный инетрепретатор Python, набрав:

python

В отдельно окне консоли командной строки запустите сервер MongoDB, набрав:

C:\mongodb\bin\mongod.exe

В окне интерпретатора Python наберите следующие команды:

>>> import pymongo
>>> conn = pymongo.Connection("localhost", 27017)
>>> db = conn.example
>>> db.collection_names()

В результате в консоли появятся квадратнце скобки:
[]

Если все прошло успешно и сообщений об ошибках в консоли не появилось, то Python взаимодействует с сервером MongoDB правильно.

Теперь вы можете использовать MongoDB в ваших приложениях, написанных на Python.

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

Установка и настройка Django, Nginx и Tornado

Tornado (торнадо) - это неблокирующий, высоко производительный веб-сервер с открытыми исходным кодом. Сервер реализован средствами языка Python и в силу своей неблокирующей природы (используется epoll) легко выдерживает тысячи одновременных подключений. Помимо всего прочего, Tornado поддерживает протокол WSGI, хотя и с небольшими ограничениями (будут не доступны асинхронные фичи сервера).

Учитывая все это, можно предположить, что возможность запуска Django с помощью Tornado может стать достойной альтернативой описанному ранее способу запуска Django через FastCGI.

Механизм взаимодействия будет классическим:

front-end - nginx, проксирующий все соединения, кроме статических файлов, на back-end
back-end - tornado + django

Установка Nginx

В первую очередь необходимо установить front-end, коим будет являться весьма популярный http-сервер Nginx. Установка проста:

$ sudo aptitude install nginx

Установка Django

Далее необходимо установить фреймворк Django.

Получение исходного кода фреймворка:

$ mkdir ~/django
$ cd ~/django
$ wget http://www.djangoproject.com/download/1.1.1/tarball/
$ tar xzf Django-1.1.1.tar.gz

Установка Django:

$ python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
/usr/lib/python2.5/site-packages
$ sudo ln -s ~/django/Django-1.1.1/django /usr/lib/python2.5/site-packages/django
$ sudo ln -s ~/django/Django-1.1.1/django/bin/django-admin.py /usr/local/bin
$ python -c "import django; print django.VERSION;"
(1, 1, 1, 'final', 0)

Установка Tornado

Поэтому процесс установки будет выполняться непосредственно из исходных кодов. Подготовка к получению исходных кодов и компиляции:

# устанавливаем git, чтобы скачать исходный код tornado
$ sudo aptitude install git-core gitosis
# устанавливаем пакет необходимый для сборки в Debian / Ubuntu
$ sudo aptitude install python-dev build-essential

После этого необходимо получить исходный код tornado:

$ cd ~ && git clone git://github.com/facebook/tornado.git

И, наконец, выполнить установку tornado:

$ cd ~/tornado && sudo python setup.py install

Проверяем корректность установки:

$ python -c "import tornado; print 'tornado installation successfully completed';"
tornado installation successfully completed

Настройка wsgi

Чтобы заставить работать Django-код под Tornado, необходимо написать wsgi-прослойку, запускающую tornado-сервер на определенном порту и подключающую django-проект по протоколу wsgi. Код должен выглядеть приблизительно так:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# location: deploy/tornading.py

import os
import sys

# настройки
DJANGO_ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DJANGO_APPS_DIR = os.path.join(DJANGO_ROOT_DIR, 'apps')

def daemon(iport):
    import tornado.wsgi
    import tornado.ioloop
    import tornado.httpserver

    # настраиваем Django
    sys.path.insert(0, DJANGO_APPS_DIR)
    os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
    import django.core.handlers.wsgi
    application = django.core.handlers.wsgi.WSGIHandler()

    # подключаем Tornado
    container = tornado.wsgi.WSGIContainer(application)
    http_server = tornado.httpserver.HTTPServer(container)
    http_server.listen(iport)
    tornado.ioloop.IOLoop.instance().start()

if __name__ == "__main__":
    # на вход должен быть передан порт,
    # на котором будет запущен tornado-сервер
    daemon(int(sys.argv[1]))

При этом предполагается, что код проекта распределен следующим образом:

$ tree -d  -L 1
.               # корень django-проекта
|-- apps        # django-приложения
|-- cache
|-- deploy
|-- logs
|-- media
`-- templates   # django-шаблоны


Настройка nginx

После того, как tornado-сервер запущен, можно переходить к настройке nginx:

$ sudo vim /etc/nginx/sites-available/mysite.ru

Файл конфигурации должен выглядеть приблизительно следующим образом:

upstream backends {
    server 127.0.0.1:8001;
    server 127.0.0.1:8002;
}

server {
    listen   80;
    server_name tornado.mysite.ru;

    access_log /home/django-projects/mysite_ru/logs/nginx_access.log;
    error_log /home/django-projects/mysite_ru/logs/nginx_error.log;

    location = /robots.txt {
        alias /home/django-projects/mysite_ru/media/robots.txt;
    }

    location = /favicon.ico {
        alias /home/django-projects/mysite_ru/media/img/favicon.ico;
    }

    location /media/ {
        alias /home/django-projects/mysite_ru/media/;
        expires 30d;
    }

    location /media_admin/ {
        alias /usr/lib/python2.6/dist-packages/django/contrib/admin/media/;
        expires 30d;
    }

    location / {
        proxy_pass http://backends;
        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;
    }
}

Далее, необходимо включить хост:

$ sudo ln -s /etc/nginx/sites-available/mysite.ru \
         /etc/nginx/sites-enabled/mysite.ru

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

$ sudo /etc/init.d/nginx restart

Запуск демона Tornado

Для запуска Django-проекта осталось лишь запустить Tornado-сервер на нужном порту с помощью wsgi-прослойки, написанной ранее:

$ python deploy/tornading.py 8001 &
$ python deploy/tornading.py 8002 &

Все. Django-проект запущен под Nginx + Tornado.

Для того, чтобы убедиться, что все настроено правильно, необходимо открыть в браузере url: "http://tornado.mysite.ru" (или тот, который прописан в Вашем виртуальном хосте Nginx) и убедиться в наличии надписи:

It worked!
Congratulations on your first Django-powered page.

Остается лишь написать скрипт для автозапуска Tornado-серверов и мониторинга их работоспособности.

Nginx, Memcached и SSI (Server Side Include)

Многие из вас знают о прекрасном легковесном веб-сервере Nginx.
Некоторые также знают, что он умеет работать с Memcached.
Но лишь немногие в курсе, при чём здесь SSI (Server Side Include) и как его можно использовать в связке с Nginx и memcached.

Nginx

В классической схеме Nginx используется как load balancer или reverse proxy перед одним или несколькими серверами типа Apache.
Nginx отдает статические ресурсы - картинки, CSS и JS-файлы. Запросы к динамическим страницам он передает в Apache/Python, который самостоятельно обрабатывает их и возвращает результат.

Memcached

Nginx умеет работать с memcached при помощи модуля ngx_http_memcached_module.
Когда Nginx получает запрос на определенный URL, вначале он проверяет, есть ли результат запроса для данного URL'а в кэше. Если есть - отдает кэшированную страницу как есть, а если нету - передает обработку запроса в Apache/Python. Получив запрос, Python подготавливает ответ, сохраняет его в memcached, а затем отображает его пользователю. Таким образом, при следующем запросе по этому же URL'у Nginx сам найдет результат в кэше и вернет его пользователю, минуя ресурсоёмкое обращение к Apache/Python.
В теории всё просто и удобно, но на практике применение такого кэширования весьма ограничено.

Допустим, мы хотим закешировать главную страницу Хабрахабра.
Мы видим блок авторизации в правом верхнем углу (войти/зарегистрироваться, либо общие сведения о текущем пользователе), закладочки (все, коллективные, персональные...), ленту захабренных статей, облако тэгов и т.д.
Все блоки на странице можно условно разделить на статические и динамические. Условно - потому что на самом деле все блоки динамические, но некоторые кэшировать можно, а другие - нельзя. Подумайте сами, что будет, если мы закэшируем главную страницу для неавторизированного пользователя, а затем по тому же URL'у на неё зайдет авторизированный пользователь? Правильно, в верхнем правом углу он увидит приглашение войти в систему или зарегистрироваться и будет как минимум удивлён.

Что же делать? Один из вариантов - не кэшировать страницу целиком! У нас есть возможность исключить динамические блоки из кэширования. И помогут нам в этом…

SSI или Server Side Includes

Если кто-то ещё помнит, была раньше такая технология, задолго до JSP, ASP, PHP, Python и прочих Django'в с RoR'ами.
Смысл её в том, что обычная HTML-страница обрабатывалась определенным образом на сервере перед тем, как уйти клиенту. Например, обычная директива include выглядела так:

<!--#include file="header.html"-->

Вот нас как раз интересует именно эта директива, только не include file, а include virtual. Отличаются они тем, что include file вставляет вместо себя содержимое файла, а include virtual - результат виртуального запроса по указанному URL'у. В Nginx реализовать задуманное нам поможет модуль ngx_http_ssi_module.

Возвращаясь к примеру с главной страницей хабра, в кэш мы помещаем страницу как есть, только блок авторизации заменяем на такой вот include:

<!-- #include virtual="/auth" -->

Затем, когда Nginx получит данную страницу из кэша, он должен будет обработать все SSI-инструкции, прежде чем отдавать её клиенту. Таким образом, Nginx выполнит виртуальный запрос по URL'у "/auth" и, не найдя результатов для этого URL'а в кэше - передаст запрос в Apache/Python. Теперь, задача Python - проверить авторизацию текущего пользователя и вернуть HTML-код блока авторизации в зависимости от того, авторизирован ли пользователь.

Получив результат от Apache/Python, Nginx вставит его на место директивы include и вернет страницу клиенту. Таким образом, авторизированные и неавторизированные клиенты будут видеть разные страницы, контент которых будет по-прежнему кэширован и бедному серверу Хабрахабра не нужно будет на каждый запрос получать ленту захабренных статей, генерировать облако тэгов и т.д. - только простенький блок авторизации.

Сервер для 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

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