В этой статье я поделюсь собственным опытом построения веб-сервера, работающего на CentOS 5.3.
Что требовалось:
- Полностью избавиться от Apache. Сервер должен был выдерживать хорошую нагрузку, распределяя статику и динамику.
- Нужна была поддержка последней версии libxml, малейшее различие в версиях делало сайт абсолютно нерабочим.
- Нужен был gzip
- И еще некоторые особенности, о которых я расскажу в самой статье
Предыстория
В качестве «полигона для испытаний» у меня был в наличии физический
сервер, на борту которого стояли 2 процессора Xeon и 2 Гб оперативной
памяти. Более точный конфиг привести не могу — не помню, да и особо не
волновало.
Для работы сайта требовался php ветки 5.2.х. Когда я устанавливал из
стандартного репозитория, я столкнулся с такой проблемой, как libxml. По
умолчанию он ставился с версией 2.6.24, что делало проект абсолютно
нерабочим (требовалась версия 2.6.32). Даже с подключенным репозиторием
CentALT проблема не решалась.
Вероятно, можно было пересобрать готовый пакет и установить уже его, но у
меня нет в этом никакого опыта, поэтому php я решил собирать вручную.
Правильно собрать php с первого раза мне, разумеется, не удалось :).
Проект требовал учета небольшого количества тонкостей. В частности, это
поддержка pdo и freetype.
Изначально я решил сделать все на основе связки nginx+apache, процесс
установки и настройки ничем не отличался от того, как написано в
этой статье. Да и сам процесс мне казался проще, чем настройка работы с php-cgi.
Все работало прекрасно, но я решил не останавливаться на этом, тем более
сервер нужно было оптимизировать. Тут и пришла задумка убрать полностью
apache, взвесив все это на nginx и php-cgi.
Сборка PHP
Нужно было еще чем-то управлять самим процессами FastCGI, я решил
использовать php-fpm — PHP FastCGI Process Manager — это патч для PHP,
позволяющий более эффективно управлять процессами FastCGI для
обеспечения высокой стабильности работы. Почему именно он? Показался
прост в настройке и вообще по отзывам неплох.
Сказано — сделано, тянем последнюю версию с
http://php-fpm.org/downloads/. На тот момент у меня стоял php версии 5.2.10, поэтому я тянул
php-5.2.10-fpm-0.5.13.diff.gz. Казалось бы, далее все просто. Стягиваем, и делаем все в точности как указано в
вики самого проекта. Кратко приведу что нужно было сделать:
$ bzip2 -cd php-5.2.10.tar.bz2 | tar xf -
$ gzip -cd php-5.2.10-fpm-0.5.13.diff.gz | patch -d php-5.2.10 -p1
$ cd php-5.2.10 && ./configure --enable-fastcgi --enable-fpm
Как видите, ничего хитрого. Далее — я собирал php. Процесс сборки шел с учетом тех тонкостей, которые мне были необходимы:
./configure --enable-fastcgi --enable-fpm --with-zlib
--enable-pdo --with-pdo-mysql --with-mysql --with-config-file-path=/etc
--enable-calendar --with-iconv --enable-exif --enable-ftp --enable-wddx
--with-zlib --with-bz2 --with-gettext --with-xmlrpc --with-xml
--enable-soap --enable-filepro --enable-bcmath --enable-trans-sid
--enable-mbstring --enable-dbx --enable-dba --with-openssl --with-mhash
--with-mcrypt --with-xsl --with-curl --with-pcre-regex --with-gd
--enable-gd-native-ttf --with-ldap --enable-pdo --with-pdo-mysql
--with-mysql --with-sqlite --with-pdo-sqlite --enable-sqlite-utf8
--with-pear --with-freetype-dir=/usr --with-jpeg-dir=/usr
Болдом помечены обязательные параметры, которые необходимы для работы
php-fpm. --with-config-file-path=/etc — решил четко указать где держать
php-ini.
Ну, и затем:
make install all
Нужно еще отредактировать файл /etc/php-fpm.conf. В частности, я редактировал:
Pid file
<value name="pid_file">/var/run/php-fpm.pid</value>
Error log file
<value name="error_log">/var/log/php-fpm.log</value>
В первом случае мы задаем где будет лежать pid-файла процесса, во втором куда писать логи.
<value name="listen_address">127.0.0.1:9000</value>
Адрес и порт где будет слушать php. Это мы и будем использовать при
кофигурировании nginx. Либо, тут указывается путь к сокету — например:
<value name="listen_address">/tmp/php-fpm.sock</value>
И необходимо задать от чьего имени запускать сам процесс:
<code>Unix user of processes
<value name="user"></value>
Unix group of processes
<value name="group"></value>
Это уже на ваше усмотрение, главное, чтобы права были соответствующие.
Можно еще покопать конфиг, каждая строчка снабжена комментарием, разобраться несложно.
Nginx
Как я уже говорил выше, установка и установка nginx практически не
отличается от того, что написано в статье, ссылку на которую я указал
выше. Единственный момент — мы не используем проксирование, так как
apache у нас нет, соответственно строчки proxy_* не имеют для нас
никакого значения. Ну и сама специфика настройки, к примеру
worker_connections или worker_processes и т.п. зависит конкретно от
ваших нужд. Разумеется, я собирал вручную, потому что и тут нужно было
учесть некоторые тонкости. Без них было бы вполне достаточно:
yum install nginx
Приведу пример части конфига из ветки http:
include /etc/nginx/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"'
'"$gzip_ratio"'
'"$got" "$sent_http_set_coockie"';
access_log /var/log/nginx/access.log main;
'"$got" "$sent_http_set_coockie"'; — это мне требуется для логгирования с
установленным модулем custom-nginx-session-module (Модуль для
определения куки и установки уникальной сессии). О процессе установки и
настройки могу рассказать позже, если кому-то будет интересно. А то, что
выше — обычное логгирование.
Еще подразумевалось использование виртуальных хостов, поэтому для удобства я решил вынести это в отдельные файлы:
include /etc/nginx/sites-enabled/*;
Приведу пример — файл /etc/nginx/sites-enabled/example.com:
server {
listen 80;
server_name example.com www.example.com;
# Разумеется, мне нужен лог для каждого виртуального хоста
access_log /var/log/examplecom-access.log;
error_log /var/log/example.com-error.log;
# Указываем корень где будет лежать сайт
root /path/to/www;
# Всю статику отдаем nginx
location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|js|bmp)$ {
root /path/to/www;
}
UPD: Замечание от хабраюзера
AlexeyK:
строчки не имеют смысла, если у вас один и тот же root, да и
вообще nginx отдаст эти файлы так сказать по дефолту, если вы на них
handler не повесите :) имеет смысл поставить expires побольше в этот
location и возможно настроить размер буферов для отдачи (если
статических файлов действительно много)
# Помните прикол с свн? :) На всякий случай учел
location ~ /.svn/ {
deny all;
}
# Переписывание всех запросов к несуществующему документу на index.php,
if (!-e $request_filename) {
rewrite ^.*$ /index.php last;
}
# Передача файлов, имена которых заканчиваются на .php на интерфейс fastCGI (php-fpm)
location ~ \.php$ {
# Адрес и порт, который мы указали в конфиге php-fpm.conf
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param script_FILENAME /path/to/www$fastcgi_script_name;
include fastcgi_params;
}
}
UPD: Или, как
подсказал хабраюзер
darivush:
fastcgi_pass 127.0.0.1:9000;
заменить на
fastcgi_pass unix:/tmp/fastcgi_sock;
,
так как юникс сокеты предпочительнее 127.0.0.1. Ну, и соответственно
путь /tmp/fastcgi_sock должен быть правильным, конфигурится в
/etc/php-fpm.conf в разделе
<value name="listen_address">
Разумеется, это пример стандартного минимального конфига, все остальное
вписывается\убирается\редактируется в зависимости от поставленных задач.
Вроде ничего не забыл. Запускаем php-fpm и nginx:
/etc/init.d/php-fpm start
/etc/init.d/nginx start
И тут я столкнулся с проблемой — php у меня не пропатчился как нужно, в
итоге php-fpm напрочь отказывался запускаться, ругаясь на неверный
параметр при запуске php-cgi. Решение этой проблемы я так и не смог
найти на тот момент. Все решилось некоторое время спустя, когда вышла
версия php 5.2.11, которую я пропатчил тем же патчем, сконфигурировал и
установил так, как описано выше. После чего все запустилось и заработало
без проблем.
Так как мне нужно было собирать php вручную (из-за всех тонкостей, о
которых я писал выше), то я не пытался решать задачу установкой всего
необходимого из стандартных репозиториев. Возможно, это работает и
процесс установки становится проще.
Спасибо за внимание. Статью разместил у себя в блоге, потому что ни в
коем случае я не претендую на изобретение велосипеда в плане
поставленной задачи. Это больше вспомогательный мануал для меня, который
может понадобиться в случае необходимости. Ну, и ее окажется вполне
достаточно для новичков. Но, если статья покажется вам полезной, с
удовольствием перенесу это в блог
nginx. В планах — рассказать о настройке custom-nginx-session-module (я позже расскажу зачем он мне нужен), а так же memcached, и
pinba.
И да, пожелания, замечания и ценные советы приветствуются.
UPD: перенесено в nginx.