<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Юникс и другие &#187; web-servers</title>
	<atom:link href="http://boombick.org/blog/posts/category/web-servers/feed" rel="self" type="application/rss+xml" />
	<link>http://boombick.org/blog</link>
	<description>Just another WordPress weblog</description>
	<lastBuildDate>Tue, 29 Nov 2011 22:14:38 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Немного о mod_perl</title>
		<link>http://boombick.org/blog/posts/83</link>
		<comments>http://boombick.org/blog/posts/83#comments</comments>
		<pubDate>Thu, 01 Oct 2009 13:18:24 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[Debian]]></category>
		<category><![CDATA[web-servers]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/83</guid>
		<description><![CDATA[Apache &#8211; это очень популярный и широко используемый web-сервер. Есть множество альтернатив, но по возможностям настройки, гибкости и количеству доступных расширений Apache прочно держится в топе. В этой небольшой статье я расскажу как можно контролировать фактически все аспекты работы вашего web-сервера при помощи Perl и mod_perl mod_perl &#8211; это обычный модуль для Apache, который устанавливается [...]]]></description>
			<content:encoded><![CDATA[<p>Apache &#8211; это очень популярный и широко используемый web-сервер. Есть множество альтернатив, но по возможностям настройки, гибкости и количеству доступных расширений Apache прочно держится в топе. В этой небольшой статье я расскажу как можно контролировать фактически все аспекты работы вашего web-сервера при помощи Perl и <code>mod_perl</code><br />
<span id="more-83"></span><br />
<code>mod_perl</code> &#8211; это обычный модуль для Apache, который устанавливается также, как и все остальные модули. Но ключевое отличие в том, что этот модуль содержит в себе встроенный интерпретатор Perl, с помощью которого можно писать расширения и управлять фактически всеми аспектами работы сервера. Даже если вы никогда не писали (и не собираетесь писать) расширений для сервера, <code>mod_perl</code> пригодится вам чтобы, например, ускорить работу CGI-скриптов. А сам процесс описан ниже</p>
<p><b>Установка <code>mod_perl</code></b><br />
Все примеры показаны для ОС Linux Debian<br />
Устанавливаем пакет libapache2-mod-perl2</p>
<blockquote><pre>
lenny:~# apt-get install libapache2-mod-perl2
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
  libapache2-reload-perl libbsd-resource-perl libperl5.10
The following NEW packages will be installed
  libapache2-mod-perl2 libapache2-reload-perl libbsd-resource-perl libperl5.10
0 upgraded, 4 newly installed, 0 to remove and 2 not upgraded.
Need to get 1201kB of archives.
After this operation, 3891kB of additional disk space will be used.
...
Processing triggers for man-db ...
Setting up libperl5.10 (5.10.0-19) ...
Setting up libapache2-mod-perl2 (2.0.4-5) ...
Enabling module perl.
Run '/etc/init.d/apache2 restart' to activate new configuration!
Setting up libapache2-reload-perl (0.10-2) ...
Setting up libbsd-resource-perl (1.28-1+b1) ...
</pre>
</blockquote>
<p>Как можно увидеть, модуль уже активирован.. Но никто не мешает сделать это еще раз (для надежности :) ) Или, например, после изменения конфигурации сервера, да и вообще, чтобы убедиться</p>
<blockquote><pre>lenny:~# a2enmod perl
Module perl already enabled
lenny:~# /etc/init.d/apache2 restart
Restarting web server: apache2 ... waiting .
</pre>
</blockquote>
<p>Модуль установлен, давайте займемся его настройкой. Самое простое &#8211; это добавить хендлер <code>perl-status</code> и посмотреть, что же происходит с нашим сервером. Создайте файл <code>/etc/apache2/conf.d/perl-status</code> со следующим содержимым:</p>
<blockquote><pre>
 #
 # make status information available at
 #   http://example.com/perl-status/
 #
 &lt;Location /perl-status&gt;
    SetHandler perl-script
    PerlHandler +Apache2::Status
&lt;/Location&gt;

 #
 # But only from the local host, and our trusted
 # remote IP.
 #
 &lt;Location /perl-status&gt;
    order deny,allow
    deny from all
    allow from 127.0.0.1
    allow from your.ip.address
&lt;/Location&gt;
</pre>
</blockquote>
<p>Перезапустите сервер и зайдите на адрес /perl-status. Узнаете несколько интересных вещей об окружении сервера и о загруженных модулях Perl<br />
<em><strong>Внимание!</strong></em> Эта информация содержит много такого, что не стоило бы показывать всем и каждому. Поэтому не стоит делать ее доступной для всех. Ограничьте доступ!</p>
<p><b>Ускорение Perl CGI-скриптов</b><br />
Так как <code>mod_perl</code> уже содержит встроенный интерпретатор Perl, то мы можем использовать его для запуска CGI-скриптов, вместо вызова внешней команды. Это позволит снизить накладные расходы на вызов отдельной копии интерпретатора при поступлении запроса на обработку скрипта. Есть способы добиться более внушительного ускорения, но это потребует внесения изменений в исходный код сценариев. В Debian CGI-скрипты по умолчанию располагаются в <code>/usr/lib/cgi-bin</code> Мы укажем Apache, что хотели бы запускать встроенный интерпретатор вместо внешнего для сценариев из этой директории.</p>
<blockquote><pre>
  PerlModule Apache::Registry
  Alias /cgi-bin/ /usr/lib/cgi-bin
  &lt;Location /cgi-bin&gt;
    SetHandler perl-script
    PerlHandler Apache::Registry
    PerlSendHeader On
    Options +ExecCGI
  &lt;/Location&gt;
</pre>
</blockquote>
<p>Перезапустите сервер (<code>/etc/init.d/apache2 restart</code>) и посмотрите, насколько быстрее стали работать скрипты :)</p>
<p><b>Загрузка модулей</b><br />
Продолжим. Давайте напишем код, который Apache мог бы использовать в процессе обработки страницы и пересылки ее клиенту. Нам необходимо разместить этот код так, чтобы встроенный интерпретатор смог загрузить его. По умолчанию в путь для поиска уже включены большинство системных директорий, но я считаю, что имеет смысл расположить его в очевидном месте :) <code>/etc/apache2/perl</code> Для добавления директории в путь поиска добавьте следующую директиву в <code>/etc/apache2/conf/00-mod-perl</code></p>
<blockquote><p>
#<br />
#  Load the startup script<br />
#<br />
PerlRequire /etc/apache2/perl/startup.pl</p>
</blockquote>
<p>Теперь при старте севера будет запускаться указанный скрипт. Давайте создадим его и поместим туда вот такой код</p>
<blockquote><p>
#<br />
#  Add /etc/apache2/perl to the mod_perl search path.<br />
#<br />
use lib  qw( /etc/apache2/perl );</p>
<p>#<br />
#  This script had no errors (?!)<br />
#<br />
1;
</p></blockquote>
<p>После перезапуска сервера путь для поиска будет обновлен и будет включать в себя нужную нам директорию.</p>
<p><b>Сделаем что-то полезное?</b><br />
Очень часто я вижу на своих проектах &#8220;пауков&#8221;, которые методично обшаривают страницу за страницей, качая содержимое. Вообщем я не возражаю против &#8220;зеркалирования&#8221; своих сайтов, но пока это все происходит незаметно для меня, в один поток и без съедания львиной доли ресурсов. А плохие &#8220;пауки&#8221; очень часто делают запросы, подобные следующим:</p>
<blockquote><p>
1.2.3.4 &#8211; [30/Apr/2009:19:36:29 +0100] &#8220;GET /articles/535#comment_2 HTTP/1.0&#8243;<br />
1.2.3.4 &#8211; [30/Apr/2009:19:36:30 +0100] &#8220;GET /articles/535#comment_3 HTTP/1.0&#8243;<br />
1.2.3.4 &#8211; [30/Apr/2009:19:36:30 +0100] &#8220;GET /articles/535#comment_5 HTTP/1.0&#8243;<br />
1.2.3.4 &#8211; [30/Apr/2009:19:36:31 +0100] &#8220;GET /articles/535#comment_4 HTTP/1.0&#8243;
</p></blockquote>
<p>Т.е. по якорям методично и многократно вытягивают одну и туже страницу, съедая ресурсы и трафик. Чтоже делать, будем их ловить с помощью вот такого модуля на Perl: <a href="http://boombick.org/DropClients.pm">DropClients</a><br />
Это сценарий на Perl, который обрабатывается <code>mod_perl</code>. Он выполняется для каждого входящего запроса и делает следующее:</p>
<ul>
<li>Выделяет из запроса IP-адрес и User-Agent</li>
<li>Если UA и IP &#8211; &#8220;плохие&#8221;, то отклоняет запрос</li>
<li>В нашем случае запрос отклоняется и тогда, когда в нем содержится &#8220;#&#8221;</li>
</ul>
<p>Если все хорошо, то запрос проходит</p>
<p>Чтобы запустить этот сценарий мы должны</p>
<ol>
<li>Загрузить его</li>
<li>И заставить его выполняться :)</li>
</ol>
<p>Сохраним модуль как <code>/etc/apache2/perl/DropClients.pm</code> и создадим файл <code>/etc/apache2/conf/dropclients</code> со следующим содержимым:</p>
<blockquote><p>
#<br />
#  Load the module<br />
#<br />
PerlModule DropClients</p>
<p>#<br />
#  Ensure it is invoked as an access handler<br />
#<br />
&lt;Location /&gt;<br />
     PerlAccessHandler DropClients<br />
&lt;/Location&gt;
</p></blockquote>
<p>После перезапуска метод <code>DropClients::request()</code> будет выполняться для каждого входящего запроса и нежелательные запросы будут отклоняться.</p>
<p>Нормальный запрос</p>
<blockquote><p>
user@notebook:~$ echo -e &#8220;GET / HTTP/1.0\n&#8221; | nc lenny 80 |grep ^HTTP<br />
HTTP/1.1 200 OK
</p></blockquote>
<p>&#8220;Плохой&#8221; запрос</p>
<blockquote><p>
user@notebook:~$ echo -e &#8220;GET /#foo HTTP/1.0\n&#8221; | nc lenny 80 |grep ^HTTP<br />
HTTP/1.1 403 Forbidden
</p></blockquote>
<p>Поскольку мы только что сделали &#8220;плохой&#8221; запрос, дальнейший доступ к серверу будет закрыт</p>
<blockquote><p>
user@notebook:~$ echo -e &#8220;GET / HTTP/1.0\n&#8221; | nc lenny 80 |grep ^HTTP<br />
HTTP/1.1 403 Forbidden
</p></blockquote>
<p>Если заглянете в код модуля, то увидите, что эта блокировка очень просто и снимается командой <code>rm -rf /tmp/blah</code></p>
<p><b>Различные типы обработчиков</b><br />
Для нашего модуля мы использовали обработчик <code>PerlAccessHandler</code>, который запускал скрипт при входящих соединениях. Но это лишь один из многих типов обработчиков. Есть также, например:</p>
<ul>
<li><code>PerlResponseHandler</code> &#8211; запускает сценарий после прохождения запроса</li>
<li><code>PerlOutputFilterHandler</code> &#8211; позволяет выполнить фильтрацию контента, отдаваемого пользователю (заменить слова, добавить футер&#8230; Сфера применения ограничена лишь вашей фантазией)</li>
</ul>
<p>Полный список обработчиков доступен в документации к <code>mod_perl</code> и <noindex><a href="http://perl.apache.org/docs/2.0/user/handlers/http.html">здесь</a></noindex> Там же можно найти и примеры кода</p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/83/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Установка nginx, php5 CGI и MySQL</title>
		<link>http://boombick.org/blog/posts/79</link>
		<comments>http://boombick.org/blog/posts/79#comments</comments>
		<pubDate>Tue, 18 Aug 2009 13:40:19 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[*NIX]]></category>
		<category><![CDATA[Debian]]></category>
		<category><![CDATA[Network]]></category>
		<category><![CDATA[web-servers]]></category>
		<category><![CDATA[Для начинающих]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/79</guid>
		<description><![CDATA[Nginx (произносится как &#8220;энджин икс&#8221;) &#8211; это легкий высокопроизводительный веб-сервер с открытым исходным кодом. Он известен своей стабильностью, большим набором функций, сравнительной простотой конфигурации, а также весьма низкой требовательностью к ресурсам. В этой статье я опишу процесс установки nginx, PHP5 в CGI-режиме и MySQL на Debian Lenny. В нашем примере установка будет производится на сервер [...]]]></description>
			<content:encoded><![CDATA[<p>Nginx (произносится как &#8220;энджин икс&#8221;) &#8211; это легкий высокопроизводительный веб-сервер с открытым исходным кодом. Он известен своей стабильностью, большим набором функций, сравнительной простотой конфигурации, а также весьма низкой требовательностью к ресурсам. В этой статье я опишу процесс установки nginx, PHP5 в CGI-режиме и MySQL на Debian Lenny.<br />
<span id="more-79"></span><br />
В нашем примере установка будет производится на сервер с доменным именем <code>server1.example.com</code> и IP-адресом <code>192.168.1.100</code></p>
<p><strong>Установка MySQL 5.0</strong></p>
<blockquote><p>aptitude install mysql-server mysql-client</p></blockquote>
<p>В процессе установки вас попросят ввести пароль для пользователя root. Этот пользователь не имеет ничего общего с системным пользователем root. Этот пароль будет использован для пользователя, обладающего суперпривелегиями для самой MySQL:</p>
<blockquote>
<pre>
New password for the MySQL "root" user: &lt;-- yourrootsqlpassword
Repeat password for the MySQL "root" user: &lt;-- yourrootsqlpassword</pre>
</blockquote>
<p><strong>Установка Nginx</strong><br />
Nginx есть в репозитории Debian, что существенно упрощает нашу задачу :)<br />
Установим и запустим его:</p>
<blockquote><p>aptitude install nginx<br />
/etc/init.d/nginx start</p></blockquote>
<p>Наберите в браузере IP-адрес или хостнейм сервера (например <code>http://192.168.0.100</code>) и вы увидите стартовую страницу nginx<br />
<a href="http://boombick.org/blog/wp-content/uploads/2009/08/1.png" title="1.png"><img src="http://boombick.org/blog/wp-content/uploads/2009/08/1.thumbnail.png" alt="1.png" /></a></p>
<p><strong>Установка PHP5</strong><br />
Для &#8220;общения&#8221; между nginx и PHP мы будем использовать FastCGI. К счастью, в репозиториях Debian есть пакет, обеспечиващий поддержку FCGI в PHP. Установим PHP</p>
<blockquote><p>aptitude install php5-cgi php5-mysql php5-curl php5-gd php5-idn php-pear php5-imagick php5-imap php5-mcrypt php5-memcache php5-mhash php5-ming php5-pspell php5-recode php5-snmp php5-sqlite php5-tidy php5-xmlrpc php5-xsl</p></blockquote>
<p>Отредактируйте файл <code>/etc/php5/cgi/php.ini</code> добавив в его конец следующую строку:</p>
<blockquote>
<pre>
cgi.fix_pathinfo = 1</pre>
</blockquote>
<p>В Debian нет самостоятельного приложения для FastCGI, поэтому мы воспользуемся <code>spawn-fcgi</code>, которая входит в состав lighttpd:</p>
<blockquote><p>aptitude install lighttpd</p></blockquote>
<p>И после установки получим сразу же получим ошибку:</p>
<blockquote>
<pre>Starting web server: lighttpd2009-03-19 15:58:09: (network.c.300) can't bind to port: 80 Address already in use
 failed!</pre>
</blockquote>
<p>Логично, 80-й порт у нас занят nginx-ом. Поэтому сделаем так, чтобы Лайти не запускался при загрузке системы:</p>
<blockquote><p>update-rc.d -f lighttpd remove</p></blockquote>
<p>Мы установили Лайти только для того, чтобы воспользовать крайне полезной для наших целей программой, идущей с ним в комплекте: <code>/usr/bin/spawn-fcgi</code>, именно ее мы будем использовать для запуска процессов FastCGI. Для краткого ознакомления с ее возможностями выполните команду</p>
<blockquote><p>spawn-fcgi &#8211;help</p></blockquote>
<p>Для запуска PHP FastCGI-демона на 9000 порту на сервере <code>localhost</code> от пользователя <code>www-data</code> выполните</p>
<blockquote>
<pre>
/usr/bin/spawn-fcgi -a 127.0.0.1 -p 9000 -u www-data -g www-data -f /usr/bin/php5-cgi -P /var/run/fastcgi-php.pid
</pre>
</blockquote>
<p>И чтобы каждый раз не приходилось вводить это вручную, команду можно прописать в <code>/etc/rc.local</code></p>
<p><strong>Настройка Nginx</strong><br />
Конфигурационный файл nginx расположен здесь: <code>/etc/nginx/nginx.conf</code>. Для начала (необязательно) увеличим количество рабочих процессов и поменяем параметр <code>keepalive_timeout</code>:</p>
<blockquote>
<pre>[...]
worker_processes  5;
[...]
    keepalive_timeout   2;
[...]</pre>
</blockquote>
<p>Настройки виртуальных хостов расположены в секции <code>server {}</code>, хост по умолчанию описан в <code>/etc/nginx/sites-available/default</code>, модифицируйте его следующим образом:</p>
<blockquote>
<pre>
[...]
server {
        listen   80;
        server_name  _;

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

        location / {
                root   /var/www/nginx-default;
                index  index.php index.html index.htm;
        }

        location /doc {
                root   /usr/share;
                autoindex on;
                allow 127.0.0.1;
                deny all;
        }

        location /images {
                root   /usr/share;
                autoindex on;
        }

        #error_page  404  /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
                root   /var/www/nginx-default;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
                #proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        location ~ \.php$ {
                fastcgi_pass   127.0.0.1:9000;
                fastcgi_index  index.php;
                fastcgi_param  SCRIPT_FILENAME  /var/www/nginx-default$fastcgi_script_name;
                include        fastcgi_params;
        }

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        location ~ /\.ht {
                deny  all;
        }
}
[...]</pre>
</blockquote>
<p><code>server_name _;</code> &#8211; имя хоста &#8220;по умолчанию&#8221; (конечно же, никто не мешает явно указать имя хоста, например <code>example.com</code>)<br />
В выражении <code>location /</code> мы указываем индексный файл (<code>index.php</code>) и document root (<code>/var/www/nginx-default</code>)<br />
Важная часть для PHP &#8211; это <code>location ~ \.php$ {}</code>, раскомментируйте ее. Не забудьте проверить, что вы изменили строку <code>fastcgi_param</code> на <code>fastcgi_param SCRIPT_FILENAME /var/www/nginx-default$fastcgi_script_name</code> (замените <code>/var/www/nginx-default</code> на ваш реальный путь к document root), иначе интерпретатор PHP может не найти запрашиваемый вами через браузер скрипт.<br />
Удостоверьтесь, что между <code>include</code> и <code>fastcgi_params</code> есть пробел, в оригинальном файле они записаны как одно слово &#8211; это ошибка.<br />
Перезапустите <code>nginx</code></p>
<blockquote><p>/etc/init.d/nginx restart</p></blockquote>
<p>Создайте тестовый файл PHP со следующим содержанием</p>
<blockquote>
<pre>
&lt;?php
phpinfo();
?&gt;</pre>
</blockquote>
<p>Сохраните в вашей document root и откройте его в браузере (<code>http://192.168.0.100/info.php</code>)<br />
<a href="http://boombick.org/blog/wp-content/uploads/2009/08/2.png" title="2.png"><img src="http://boombick.org/blog/wp-content/uploads/2009/08/2.thumbnail.png" alt="2.png" /></a><br />
Обратите внимание на строку ServerAPI</p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/79/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Построение виртуального массового хостинга на базе Apache2 + mod_rewrite + mod_userdir + mod_suexec</title>
		<link>http://boombick.org/blog/posts/75</link>
		<comments>http://boombick.org/blog/posts/75#comments</comments>
		<pubDate>Sat, 20 Jun 2009 05:00:32 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[*NIX]]></category>
		<category><![CDATA[web-servers]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/75</guid>
		<description><![CDATA[В этой статье описан один из методов построения системы виртуального хостинга с использованием mod_rewrite для определения соответствий виртуальных хостов физическим директориям на сервере. Вдобавок, используя сопоставление хоста имени пользователя мы сможем запускать CGI-скрипты с правами юзера через suEXEC В качестве ОС мы используем CentOS 5.3. Адрес виртуального хоста www.example.com, IP-адрес сервера 192.168.1.1, сайт физически расположен [...]]]></description>
			<content:encoded><![CDATA[<p>В этой статье описан один из методов построения системы виртуального хостинга с использованием mod_rewrite для определения соответствий виртуальных хостов физическим директориям на сервере. Вдобавок, используя сопоставление хоста имени пользователя мы сможем запускать CGI-скрипты с правами юзера через suEXEC<br />
<span id="more-75"></span><br />
В качестве ОС мы используем CentOS 5.3.<br />
Адрес виртуального хоста <code>www.example.com</code>, IP-адрес сервера <code>192.168.1.1</code>, сайт физически расположен в директории <code>/home/vhosts/example.com/public_html</code></p>
<p>Установим apache</p>
<blockquote><p> yum install httpd</p></blockquote>
<p>В пакет httpd в CentOS уже включены модули mod_rewrite, mod_userdir и mod_suexec</p>
<p><strong>Настройка Apache</strong></p>
<blockquote><p>vim /etc/httpd/conf/httpd.conf</p></blockquote>
<p>Добавьте загрузку модуля rewrite</p>
<blockquote>
<pre>
LoadModule rewrite_module modules/mod_rewrite.so</pre>
</blockquote>
<p>В конец файла добавьте следующие строки</p>
<blockquote>
<pre>
## get the server name from the Host: header
UseCanonicalName Off
## splittable logs
LogFormat "%{Host}i %h %l %u %t \"%r\" %s %b" vcommon
CustomLog logs/access_log vcommon
RewriteEngine On
## Create a handle to convert upper or mixed-case to lower-case
RewriteMap lowercase int:tolower
##-----------------------------------
## where hostname has www prefix
##-----------------------------------
## Firstly create custom variable that contains the host without the www prefix
RewriteCond %{HTTP_HOST} ^www\.(.*)$
RewriteRule .? - [E=noWWWHost:%1]
## Map the virtualhost to the documentroot
RewriteCond %{REQUEST_URI} !^/~
RewriteCond %{HTTP_HOST} ^www\.
RewriteRule ^/(.*)$ /home/vhosts/${lowercase:%{ENV:noWWWHost}}/public_html/$1
##-----------------------------------
## where hostname *does not* have www prefix
##-----------------------------------
## Map the virtualhost to the documentroot
RewriteCond %{REQUEST_URI} !^/~
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^/(.*)$ /home/vhosts/${lowercase:%{HTTP_HOST}}/public_html/$1</pre>
</blockquote>
<p>Рассмотрим подробнее</p>
<ul>
<li>Наши сайты располагаются в директории <code>/home/vhosts</code> &#8211; каждая поддиректория &#8211; это доменное имя сайта (без www), например <code>/home/vhosts/example.com</code></li>
<li>Если запрашивается <code>www.example.com</code>, то произойдет перенаправление на <code>example.com</code></li>
<li>document_root имеет имя <code>public_html</code>, это необходимо для suEXEC, как мы увидим позже. Если вы не планируете использовать suEXEC, то можете изменить имя на любое другое, но не забудьте поправить правила rewrite</li>
</ul>
<p>Перезапустите apache</p>
<blockquote><p>/etc/init.d/httpd restart</p></blockquote>
<p>Создайте файл index.html в директории виртуального хоста</p>
<blockquote><p> echo &#8220;index.html Hello World&#8221; &gt; /home/vhosts/example.com/public_html/index.html</p></blockquote>
<p>Теперь зайдите браузером на <code>www.example.com</code>, вы должны увидеть строку index.html Hello World. Если ее нет, то посмотрите log-файл apache</p>
<blockquote><p>tail /var/log/httpd/error_log</p></blockquote>
<p><strong>Выполняем CGI-скрипты с помощью mod_suexec и mod_userdir</strong><br />
На массовой хостинг-площадке расположено много сайтов и зарегестрировано много пользователей. Естественно, что мы хотим, чтобы пользователи выполняли CGI-скрипты со своими правами, а не правами web-сервера. suEXEC позволяет реализовать нам это либо вручную, при помощи конфигурирования виртуального хоста, либо динамически, с помощью mod_userdir</p>
<p>Во-первых, имя каждого пользователя в системе должно совпадать с именем виртуального хоста. Например, наш <code>example.com</code></p>
<blockquote><p>useradd -d /home/vhosts/example.com example.com</p></blockquote>
<p>Эта команда создаст пользователя <code>example.com</code> с домашней директорией <code>/home/vhosts/example.com</code>. Все файлы, доступные через web должны располагаться в <code>/home/vhosts/example.com/public_html</code><br />
Вы можете добавлять каждого пользователя в <code>/etc/passwd</code> вручную или настроить LDAP на вашем хосте.<br />
Включим mod_userdir</p>
<blockquote>
<pre>
LoadModule userdir_module modules/mod_userdir.so
&lt;ifmodule&gt;
    UserDir public_html
&lt;/ifmodule&gt;</pre>
</blockquote>
<p>Теперь, при запросе вида <code>http://192.168.1.1/~example.com</code> Apache будет искать директорию <code>public_html</code> в домашней директории пользователя <code>example.com</code> Не очень красиво, что пользователям придется использовать <code>~</code> в адресах, поэтому мы &#8220;молча&#8221; будем выполнять перенаправление. Но не для всех страниц, лишь для CGI-скриптов. Для &#8220;обычных&#8221; файлов мы используем rewrite-правила, описанные выше<br />
Добавьте следующие строки в конфиг Apache после существующих</p>
<blockquote>
<pre>
## Rewrite script to userdir so we can use suEXEC
RewriteCond %{REQUEST_URI} !^/~
RewriteCond %{SCRIPT_FILENAME} /home/vhosts/(.*)/public_html/(.*\.(pl|cgi))
RewriteRule .* /~%1/%2 [PT,L]
&lt;directory&gt;
	AddHandler cgi-script .pl .cgi
	Options +ExecCGI
&lt;/directory&gt;</pre>
</blockquote>
<p>И перезагрузите web-сервер</p>
<blockquote><p>/etc/init.d/httpd restart</p></blockquote>
<p>Создайте тестовый perl-скрипт со следующим содержанием</p>
<blockquote>
<pre>
#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "
&lt;h1&amp;gtltest.pl Hello World&lt;/h1&gt;
\n";</pre>
</blockquote>
<p>Дайте ему права на выполнение и смените владельца</p>
<blockquote><p>chmod +x test.pl<br />
chown example.com:example.com test.pl</p></blockquote>
<p>Теперь, зайдя по адресу <code>http://www.example.com/test.pl</code> вы должны увидеть строку test.pl Hello World. Если что-то не так, то, как обычно, смотрите логи</p>
<blockquote><p> tail /var/log/httpd/error_log<br />
tail /var/log/httpd/suexec.log</p></blockquote>
<p><strong>Оригинал:</strong> <noindex><a href="http://howtoforge.org/how-to-set-up-mass-virtualhosting-with-apache2-mod_rewrite-mod_userdir-mod_suexec-on-centos-5.3">http://howtoforge.org/how-to-set-up-mass-virtualhosting-with-apache2-mod_rewrite-mod_userdir-mod_suexec-on-centos-5.3</a></noindex></p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/75/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Собственный видеохостинг</title>
		<link>http://boombick.org/blog/posts/72</link>
		<comments>http://boombick.org/blog/posts/72#comments</comments>
		<pubDate>Thu, 21 May 2009 15:40:56 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[*NIX]]></category>
		<category><![CDATA[Debian]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[highload]]></category>
		<category><![CDATA[web-servers]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/72</guid>
		<description><![CDATA[Статья описывает процесс построения собственного видеохостинга (как, например, YouTube) на базе lighttpd с модулем mod_flv_streaming для трансляции потокового видео в формате .flv и модулем mod_secdownload для предотвращения хотлинкинга. В качестве проигрывателя мы возьмем FlowPlayer, который поддерживает mod_flv_streaming. Также мы опишем процесс перекодировки видео различных форматов (.mp4 .mov .mpg .3gp .mpeg .wmv .avi) в формат FLV, [...]]]></description>
			<content:encoded><![CDATA[<p>Статья описывает процесс построения собственного видеохостинга (как, например, YouTube) на базе lighttpd с модулем <em>mod_flv_streaming</em> для трансляции потокового видео в формате .flv и модулем<br />
<em>mod_secdownload</em> для предотвращения хотлинкинга. В качестве проигрывателя мы возьмем <noindex><a href="http://flowplayer.org/">FlowPlayer</a></noindex>, который поддерживает <em>mod_flv_streaming</em>. Также мы опишем процесс перекодировки видео различных форматов (.mp4 .mov .mpg .3gp .mpeg .wmv .avi) в формат FLV, который будет использоваться на нашем сайте<br />
<span id="more-72"></span><br />
<strong>Необходимые замечания</strong><br />
Перед описанием непосредственно процесса давайте определим используемые в статье некоторые параметры, которые могут отличаться от ваших (и наверняка отличаются :))<br />
Все происходит на сервере с адресом <code>server1.example.com</code> и IP-адресом <code>192.168.0.100</code>. Предполагается, что на сервере уже установлен lighttpd и php с поддержкой MySQL<br />
В Лайти также включена поддержка PHP. В качестве операционной системы мы используем Debian Etch<br />
Итак, приступим</p>
<p><strong>Устанавливаем LAME</strong><br />
<noindex><a href="http://lame.sourceforge.net/">LAME</a></noindex> &#8211; это mp3-декодер. Он необходим нам для того, чтобы в наших сконвертированных видеофайлах сохранялась аудиодорожка. В репозитриях Etch LAME отсутствует, поэтому мы будем собирать его вручную.<br />
Установим необходимые пакеты:</p>
<blockquote><p> apt-get install build-essential</p></blockquote>
<p>Затем скачаем и скомпилируем LAME</p>
<blockquote>
<pre>
cd /tmp
wget http://mesh.dl.sourceforge.net/sourceforge/lame/lame-3.97.tar.gz
tar xvfz lame-3.97.tar.gz
cd lame-3.97
./configure --enable-shared --prefix=/usr
make
make install</pre>
</blockquote>
<p><strong>Устанавливаем ffmpeg</strong><br />
Для перекодирования видео мы будем использовать <code>ffmpeg</code>. Установим его и плагины к нему</p>
<blockquote><p> apt-get install ffmpeg libavcodec0d libavformat0d libavifile-0.7c2 libpostproc0d libasound2-plugins avifile-player avifile-utils avifile-mad-plugin avifile-mjpeg-plugin avifile-vorbis-plugin</p></blockquote>
<p>Проблема LAME в Debian заключается в том, что он не поддерживает кодирование mp3 из-за патентных ограничений, а значит наше видео превратится в &#8220;немое кино&#8221;. Чтож, немного поправим пакет</p>
<blockquote><p> cd /usr/src/<br />
apt-get source ffmpeg<br />
cd ffmpeg-0.cvs20060823</p></blockquote>
<p>Отредактируем файл <code>debain/rules</code>. В начале файла есть две строки <code>confflags</code> с опциями сборки. Добавим в одну из них <code>--enable-mp3lame</code> и сохраним файл</p>
<blockquote>
<pre>
[...]
confflags += --enable-gpl --enable-pp --enable-pthreads --enable-mp3lame
confflags += --enable-vorbis --enable-libogg --enable-a52 --enable-dts --enable-libgsm
[...]</pre>
</blockquote>
<p>Соберем пакет</p>
<blockquote><p> dpkg-buildpackage</p></blockquote>
<p><code>dpkg-buildpackage</code>, скорее всего, будет &#8220;ругаться&#8221; на отсутствующие пакеты, которые нужны ему для сборки <code>ffmpeg</code></p>
<blockquote>
<pre>
server1:/usr/src/ffmpeg-0.cvs20060823# dpkg-buildpackage
dpkg-buildpackage: source package is ffmpeg
dpkg-buildpackage: source version is 0.cvs20060823-8
dpkg-buildpackage: source changed by Sam Hocevar (Debian packages) <sam+deb@zoy.org>
dpkg-buildpackage: host architecture i386
dpkg-buildpackage: source version without epoch 0.cvs20060823-8
dpkg-checkbuilddeps: Unmet build dependencies: debhelper (&gt;= 4.0) quilt libogg-dev libvorbis-dev liba52-dev libdts-dev zlib1g-dev libsdl1.2-dev libfreetype6-dev libimlib2-dev texi2html libraw1394-dev libdc1394-13-dev libtheora-dev (&gt;&gt; 0.0.0.alpha4) libgsm1-dev
dpkg-buildpackage: Build dependencies/conflicts unsatisfied; aborting.
dpkg-buildpackage: (Use -d flag to override.)
server1:/usr/src/ffmpeg-0.cvs20060823#
</sam+deb@zoy.org></pre>
</blockquote>
<p>Если вы видите что-то подобное, то просто доставьте недостающие пакеты</p>
<blockquote><p> apt-get install debhelper quilt libogg-dev libvorbis-dev liba52-dev libdts-dev zlib1g-dev libsdl1.2-dev libfreetype6-dev libimlib2-dev texi2html libraw1394-dev libdc1394-13-dev libtheora-dev libgsm1-dev</p></blockquote>
<p>и запустите <code>dpkg-buildpackage</code> снова</p>
<blockquote><p> dpkg-buildpackage</p></blockquote>
<p>Процесс создания нового пакета займет некоторое время, а результатом его будут *.deb-файлы в директории <code>/usr/src</code>. Установим их командой</p>
<blockquote><p> cd ..<br />
dpkg -i *.deb</p></blockquote>
<p><strong>Устанавливаем flvtool2</strong><br />
При перекодировке видео неплохо было добавить некоторые метаданные в конечные файлы, например информацию о длительности, чтобы наш плеер смог корректно показывать счетчик времени. Для этого воспользуемся утилитой <noindex><a href="http://rubyforge.org/projects/flvtool2/">flvtool2</a></noindex>. Она написана на Ruby, поэтому сначала установим его</p>
<blockquote><p> apt-get install ruby</p></blockquote>
<p>Затем скачаем и установим flvtool2</p>
<blockquote><p> cd /tmp<br />
wget http://rubyforge.org/frs/download.php/17497/flvtool2-1.0.6.tgz<br />
tar xvfz flvtool2-1.0.6.tgz<br />
cd flvtool2-1.0.6<br />
ruby setup.rb config<br />
ruby setup.rb setup<br />
ruby setup.rb install</p></blockquote>
<p><strong>Подгототавливаем директории для видео</strong><br />
Корневой директорией для Лайти в нашем случае является <code>/var/www</code> (по умолчанию в Debian так и есть). Конечно же мы не хотим хранить оригинальные и сконвертированные видеофайлы в этой директории, иначе их смогут скачать все, кто захочет (зная прямую ссылку). Поэтому директорию с оригинальными видео (<code>/var/videos/incoming</code>) и сконвертированными (<code>/var/videos/flv</code>) мы расположим <strong>вне</strong> DocumentRoot</p>
<blockquote><p> mkdir -p /var/videos/incoming<br />
mkdir -p /var/videos/flv</p></blockquote>
<p>Вы (или ваши пользователи) смогут загружать файлы в <code>/var/videos/incoming</code> через FTP или WEB-интерфейс, а вы будете их перекодировать (вручную или автоматически) в FLV-формат и хранить в <code>/var/videos/flv</code></p>
<p><strong>Перекодирование видео</strong><br />
Предположим, что у нас есть файл <code>video.avi</code> в директории <code>/var/videos/incoming</code> (или .mp4 .mov .mpg .3gp .mpeg .wmv). Мы хотим сконвертировать его в <code>fideo.flv</code> и сохранить в <code>/var/videos/flv</code>. Разрешение конечного файла должно быть 320&#215;240, звук 44100 Hz и частота кадров 12 fps</p>
<blockquote><p> ffmpeg -i /var/videos/incoming/video.avi -s 320&#215;240 -ar 44100 -r 12 /var/videos/flv/video.flv</p></blockquote>
<p>(для дополнительной информации рекомендую обратиться к <code>man ffmpeg</code>). Это займет некоторое время, а вывод будет похож на</p>
<blockquote>
<pre>
server1:~# ffmpeg -i /var/videos/incoming/video.avi -s 320x240 -ar 44100 -r 12 /var/videos/flv/video.flv
FFmpeg version SVN-rUNKNOWN, Copyright (c) 2000-2004 Fabrice Bellard
  configuration:  --enable-gpl --enable-pp --enable-pthreads --enable-mp3lame --enable-vorbis --enable-libogg
 --enable-a52 --enable-dts --enable-libgsm --enable-dc1394 --disable-debug --enable-shared --prefix=/usr
  libavutil version: 0d.49.0.0
  libavcodec version: 0d.51.11.0
  libavformat version: 0d.50.5.0
  built on Aug 14 2007 15:02:25, gcc: 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)
Input #0, avi, from '/var/videos/incoming/video.avi':
  Duration: 00:10:53.8, start: 0.000000, bitrate: 5455 kb/s
  Stream #0.0: Video: mpeg4, yuv420p, 1024x576, 24.00 fps(r)
  Stream #0.1: Audio: ac3, 48000 Hz, 5:1, 448 kb/s
Output #0, flv, to '/var/videos/flv/video.flv':
  Stream #0.0: Video: flv, yuv420p, 320x240, q=2-31, 200 kb/s, 12.00 fps(c)
  Stream #0.1: Audio: mp3, 44100 Hz, stereo, 64 kb/s
Stream mapping:
  Stream #0.0 -&gt; #0.0
  Stream #0.1 -&gt; #0.1
No accelerated IMDCT transform found
Press [q] to stop encoding
frame= 7847 q=2.0 Lsize=   21682kB time=653.8 bitrate= 271.7kbits/s
video:16061kB audio:5108kB global headers:0kB muxing overhead 2.427536%
server1:~#</pre>
</blockquote>
<p>Обратите особое внимание на секцию <code>Output</code> &#8211; там должно быть два потока: видео и аудио. Если вы видите там только видеопоток, то значит какие-то проблемы с аудиокодированием, внимательно проверьте наши инструкции по подключению LAME<br />
После кодирования добавим метаданные</p>
<blockquote><p> cat /var/videos/flv/video.flv | flvtool2 -U stdin /var/videos/flv/video.flv</p></blockquote>
<p><strong>Настройка Lighttpd</strong><br />
Теперь приступим к настройке Лайти. Откроем главный конфигурационный файл <code>/etc/lighttpd/lighttpd.conf</code>  активируем в нем модули <code>mod_secdownload</code> и <code>mod_flv_streaming</code>. Обратите внимание: крайне важно, чтобы модуль <code>mod_secdownload</code> шел <em>перед</em> модулем <code>mod_flv_streaming</code> в секции <code>server.modules</code>. В обратном случае будут проблемы с отображением видео FlowPlayer&#8217;ом</p>
<blockquote>
<pre>
[...]
server.modules              = (
            "mod_access",
            "mod_alias",
            "mod_accesslog",
            "mod_fastcgi",
#           "mod_rewrite",
#           "mod_redirect",
#           "mod_status",
#           "mod_evhost",
#           "mod_compress",
#           "mod_usertrack",
#           "mod_rrdtool",
#           "mod_webdav",
#           "mod_expire",
            "mod_secdownload",
            "mod_flv_streaming",
#           "mod_evasive"
 )
[...]</pre>
</blockquote>
<p>Также добавьте в конец конфига следующие строки</p>
<blockquote>
<pre>
[...]
flv-streaming.extensions = ( ".flv" )
secdownload.secret          = "somesecret"
secdownload.document-root   = "/var/videos/flv/"
secdownload.uri-prefix      = "/dl/"
secdownload.timeout         = 120</pre>
</blockquote>
<p>Не забудьте заменить <code>somesecret</code> на реальную парольную фразу<br />
Как работает <code>mod_secdownload</code>:<br />
На web-странице расположена ссылка примерно следующего вида:<br />
<em>&lt;uri-prefix&gt;/&lt;token&gt;/&lt;timestamp-in-hex&gt;/&lt;rel-path&gt; </em> (например: <em>/dl/d8a8cb150f7e5962f6a8443b0b6c6cc2/46c1d9f6/video.flv</em>)<br />
Где &lt;token&gt; &#8211; это md5-хэш от</p>
<ul>
<li>Секретной строки</li>
<li>&lt;rel-path&gt; (начинающегося с /)</li>
<li></li>
<li>&lt;timestamp-in-hex&gt;</li>
<p><code>mod_secdownload</code> перенаправит эту ссылку на файл, расположенный в  <code>secdownload.document-root</code> (который вне основного корня веб-сервера) и обеспечит доступ к нему в течении <code>secdownload.timeout</code> секунд. По истечении времени ссылка перестанет быть валидной и доступ будет закрыт.<br />
После установки FlowPalyer мы будем генерировать валидные сслыки для <code>mod_secdownload</code> при помощи PHP-скрипта. Дополнительную информацию по <code>mod_secdownload</code> можно получить <noindex><a href="http://trac.lighttpd.net/trac/wiki/Docs%3AModSecDownload">здесь</a></noindex><br />
Не забудьте перезапустить Лайти</p>
<blockquote><p> /etc/init.d/lighttpd restart</p></blockquote>
<p><strong>Установка FlowPlayer</strong><br />
Скачайте последнюю версию плеера с <noindex><a href="http://flowplayer.org/download">http://flowplayer.org/download</a></noindex> и приготовьте его к работе</p>
<blockquote><p> cd /tmp<br />
wget http://belnet.dl.sourceforge.net/sourceforge/flowplayer/flowplayer-1.19.zip<br />
unzip flowplayer-1.19.zip<br />
mv flowplayer /var/www/</p></blockquote>
<p><strong>Настройка FlowPlayer</strong><br />
Плеер установлен, теперь давайте создадим файл, с помощью которого можно будет посмотреть наше видео. В нашем примере это <code>/var/www/flowplayertest.php</code>, в котором расположены все параметры для запуска плеера и генерируются валидные ссылки для <code>mod_secdownload</code></p>
<blockquote>
<pre>
&lt;?php
$secret = "somesecret";
$uri_prefix = "/dl/";

# filename
$f = "/video.flv";

# current timestamp
$t = time();

$t_hex = sprintf("%08x", $t);
$m = md5($secret.$f.$t_hex);

?&gt;

&lt;object type="application/x-shockwave-flash" data="/flowplayer/FlowPlayerThermo.swf"&gt;
    width="320" height="256" id="FlowPlayer"&gt;
&lt;param name="allowScriptAccess" value="sameDomain"&gt;&lt;/param&gt;
&lt;param name="movie" value="/flowplayer/FlowPlayerThermo.swf"&gt;&lt;/param&gt;
&lt;param name="quality" value="high"&gt;&lt;/param&gt;
&lt;param name="scale" value="noScale"&gt;&lt;/param&gt;
&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;
&lt;param name="flashvars" value="config={videoFile: '&lt;?php printf('%s%s/%s%s', $uri_prefix, $m, $t_hex, $f, $f); ?&gt;', streamingServer: 'lighttpd', loop: 'false', useNativeFullScreen: true}"&gt;&lt;/param&gt;
&lt;/object&gt;</pre>
</blockquote>
<p>Не забудьте позаботиться о том, чтобы переменная <code>$secret</code> совпадала со значением, указанным в конфиге Лайти. Также должны совпадать <code>$uri_prefix</code> и <code>secdownload.uri-prefix</code>. Если все верно, то ссылки точно будут рабочими. В переменной <code>$f</code> содержится имя видеофайла, начинающееся со слеша (&#8220;/&#8221;). В нашем примере имя &#8220;жестко&#8221; зашито в код, но вы можете получать его из БД, например.<br />
В тэгах <code>&lt;object&gt;&lt;/object&gt;</code> содержатся конфигурационные параметры для FlowPlayer. Плеер может использовать разные скины (в нашем примере это <code>FlowPlayerThermo</code>), видео имеет размер 320&#215;240 и панель управления имеет высоту 16px. Пожтому мы указали ширину равной 320px и высоту (240+16) 256px. Если вы используете другой скин, поправьте эти параметры. За документацией по FlowPlayer обращайтесь на <noindex><a href="http://flowplayer.org/demos/index.html">официальный сайт</a></noindex><br />
В параметре <code>&lt;param name="flashvars"...</code> содержатся настройки окружения плеера. Важным параметром является <code>videoFile</code> &#8211; это ссылка на файл, которую генерирует наш скрипт. Другая важная опция &#8211; это <code>streamingServer: 'lighttpd'</code>, которая указывает, что для потоковой трансляции файла мы используем <code>mod_flv_streaming</code> Остальные опции (<code>loop, useNativeFullScreen</code>) являются необязательными. Например, если вы установите опцию <code>useNativeFullScreen</code> в <code>true</code> (это поддержка нативного полноэкранного режима для Flash Player 9), то вы должны включить в object строку &lt;param name=&#8221;allowFullScreen&#8221; value=&#8221;true&#8221; /&gt; и не можете использовать &lt;param name=&#8221;wmode&#8221; value=&#8221;transparent&#8221; /&gt;<br />
За дополнительными настройками FlowPlayer обратитесь к документации</p>
<p><strong>Проверим?</strong><br />
Зайдем браузером на <code>http://192.168.0.100/flowplayertest.php</code> &#8211; видео должно работать (со звуком)<br />
<a href="http://boombick.org/blog/wp-content/uploads/2009/05/2.png" title="2.png"><img src="http://boombick.org/blog/wp-content/uploads/2009/05/2.thumbnail.png" alt="2.png" /></a><br />
И даже в полноэкранном режиме<br />
<a href="http://boombick.org/blog/wp-content/uploads/2009/05/3.png" title="3.png"><img src="http://boombick.org/blog/wp-content/uploads/2009/05/3.thumbnail.png" alt="3.png" /></a><br />
Enjoy.</p>
<p><strong>Оригинал:</strong> <noindex><a href="http://howtoforge.org/video_streaming_lighttpd_flowplayer">http://howtoforge.org/video_streaming_lighttpd_flowplayer</a></noindex></ul>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/72/feed</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Виртуальные хосты на lighttpd с хранением конфигурации в MySQL</title>
		<link>http://boombick.org/blog/posts/49</link>
		<comments>http://boombick.org/blog/posts/49#comments</comments>
		<pubDate>Wed, 28 Jan 2009 10:29:07 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[*NIX]]></category>
		<category><![CDATA[Debian]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[web-servers]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/49</guid>
		<description><![CDATA[Статья посвящена настройке виртуальных хостов для lighttpd, работающего под управлением Debian, с хранением всех конфигурационных данных в MySQL. Главная особенность в том, что мы не будем использовать модуль для Лайти mod_mysql_vhost, который позволяет хранить в базе лишь имя хоста и его корневой раздел. Наша конфигурация более гибкая и позволяет хранить в БД все директивы для [...]]]></description>
			<content:encoded><![CDATA[<p>Статья посвящена настройке виртуальных хостов для lighttpd, работающего под управлением Debian, с хранением всех конфигурационных данных в MySQL. Главная особенность в том, что мы не будем использовать модуль для Лайти <code>mod_mysql_vhost</code>, который позволяет хранить в базе лишь имя хоста и его корневой раздел. Наша конфигурация более гибкая и позволяет хранить в БД все директивы для каждого виртуального хоста<br />
<span id="more-49"></span><br />
<b>Установка MySQL 5.0</b><br />
Устанавливаем MySQL:</p>
<blockquote><p>apt-get install mysql-server mysql-client</p></blockquote>
<p>Задаем пароль для пользователя <code>root</code> (замените <code>yourrootsqlpassword</code> на ваш пароль)</p>
<blockquote><p>mysqladmin -u root password yourrootsqlpassword</p></blockquote>
<p>Проверим, какие адреса слушает MySQL, при помощи команды</p>
<blockquote><p>netstat -tap | grep mysql</p></blockquote>
<p>Вывод должен быть примерно таким:</p>
<blockquote><pre>
tcp        0      0 localhost.localdo:mysql *:*                     LISTEN     2713/mysqld
</pre>
</blockquote>
<p>Это значит, что MySQL слушает только <code>localhost.localdomain</code> и вы установили пароль. Если  же вывод похож на:</p>
<blockquote><pre>
tcp        0      0 *:mysql *:*                     LISTEN     2713/mysqld
</pre>
</blockquote>
<p>вам необходимо также установить пароль для вашего хоста (в нашем примере это <code>server1.example.com</code>), иначе кто-угодно сможет подключиться к БД и манипулировать данными</p>
<blockquote><pre>
mysqladmin -h server1.example.com -u root password yourrootsqlpassword
</pre>
</blockquote>
<p><b>Устанавливаем Lighttpd, Python и python-mysqldb</b><br />
Мы будем использовать скрипт, написанный на Python, для чтения конфигурации из БД. Устанавливаем все необходимое:</p>
<blockquote><p>
apt-get install lighttpd python python-mysqldb
</p></blockquote>
<p><b>Подготовка базы данных</b><br />
Подключаемся к MySQL:</p>
<blockquote><p>mysql -u root -p</p></blockquote>
<p>создаем базу данных и пользователя. А также даем пользователю привилегии SELECT для запросов к нашей базе</p>
<blockquote><pre>
CREATE DATABASE lighttpd;
GRANT SELECT ON lighttpd.* TO lighttpd@localhost IDENTIFIED BY 'secret';
GRANT SELECT ON lighttpd.* TO lighttpd@localhost.localdomain IDENTIFIED BY 'secret';
FLUSH PRIVILEGES;
</pre>
</blockquote>
<p>Не забудьте заменить &#8220;<code>secret</code>&#8221; на реальный пароль<br />
Осталось создать таблицу для наших виртуальных хостов и подготовка БД на этом закончена</p>
<blockquote><pre>
USE lighttpd;
CREATE TABLE IF NOT EXISTS domains (
domain varchar(64) NOT NULL PRIMARY KEY,
docroot varchar(128) NOT NULL,
config text
);
quit;
</pre>
</blockquote>
<p><b>Сценарий для получения данных из БД</b><br />
Создаем скрипт на python, который будет читать из БД конфигурацию виртуальных хостов</p>
<blockquote><pre>
#!/usr/bin/env python
import sys
import MySQLdb

# load configuration data from the database
db=MySQLdb.connect(host='localhost', db=sys.argv[1], user=sys.argv[2], passwd=sys.argv[3])
cur = db.cursor()
cur.execute("SELECT * FROM domains")
rs=cur.fetchall()
db.close()

for domain in rs:

    print "$HTTP[\"host\"] == \"%s\" {\nserver.document-root = \"%s\"\n%s\n}" % (domain[0], domain[1], domain[2])
</pre>
</blockquote>
<p>и сохраняем его в <code>/usr/share/lighttpd/mysql_vhost.py</code><br />
Делаем скрипт исполняемым</p>
<blockquote><p>chmod 755 /usr/share/lighttpd/mysql_vhost.py</p></blockquote>
<p>Теперь надо настроить Лайти для использования нашего срипта. Для этого открываем конфиг <code>/etc/lighttpd/lighttpd.conf</code> и добавляем в конец следующую строчку</p>
<blockquote><pre>
[...]
include_shell "/usr/share/lighttpd/mysql_vhost.py lighttpd lighttpd secret"
</pre>
</blockquote>
<p>(первый параметр &#8211; это имя БД, второй &#8211; имя пользователя БД, третий &#8211; пароль для доступа к БД)<br />
После всех изменений перезапустим lighttpd</p>
<blockquote><p>/etc/init.d/lighttpd restart</p></blockquote>
<p><b>Настройка виртуальных хостов</b><br />
В примере мы настроим два виртуальных хоста: <code>www.example.com</code> (с корневым разделом в <code>/var/www/www.example.com/web</code>) и <code>www.example.org</code> (с корневым разделом в <code>/var/www/www.example.org/web</code>). Мы будем использовать различные параметры для каждого хоста для демонстрации возможностей :)<br />
Для <code>www.example.com</code> мы разрешим листинг директорий и создадим алиас <code>test</code>, который будет указывать на DocumentRoot. Для <code><br />
www.example.org</code> листинг директорий будет отключен.</p>
<p>Если корневые разделы еще не существуют, то создадим их:</p>
<blockquote><p>
mkdir -p /var/www/www.example.com/web<br />
mkdir -p /var/www/www.example.org/web</p></blockquote>
<p>Подключаемся к MySQL и добавим описание наших хостов</p>
<blockquote><pre>
INSERT INTO domains VALUES ('www.example.com','/var/www/www.example.com/web/','dir-listing.activate = "enable"\nalias.url = ( "/test" => "/var/www/www.example.com/web" )');
INSERT INTO domains VALUES ('www.example.org','/var/www/www.example.org/web/','dir-listing.activate = "disable"');
</pre>
</blockquote>
<p>Обратите внимание на первый запрос <code>INSERT</code>. Если вы хотите использовать более одной директивы, то поместите между ними управляющий символ &#8220;\n&#8221;<br />
Все, виртуальные хосты настроены. Для проверки корректности работы нашего скрипта, запустим его из командной строки:</p>
<blockquote><p>/usr/share/lighttpd/mysql_vhost.py lighttpd lighttpd secret</p></blockquote>
<p>В выводе должна содержаться корректная информация о наших хостах:</p>
<blockquote><pre>
server1:~# /usr/share/lighttpd/mysql_vhost.py lighttpd lighttpd secret
$HTTP["host"] == "www.example.com" {
server.document-root = "/var/www/www.example.com/web/"
dir-listing.activate = "enable"
alias.url = ( "/test" => "/var/www/www.example.com/web" )
}
$HTTP["host"] == "www.example.org" {
server.document-root = "/var/www/www.example.org/web/"
dir-listing.activate = "disable"
}
server1:~#</pre>
</blockquote>
<p>В отличие от <code>mod_mysql_vhost</code>, наш способ требует перезапуска сервера</p>
<blockquote><p>/etc/init.d/lighttpd restart</p></blockquote>
<p><b>Тестируем</b><br />
Пришло время проверить, верно ли работают наши виртуальные хосты. В корневых директориях хостов нет индексных файлов<br />
<code>http://www.example.com</code> (листинг директорий включен)<br />
<a href='http://boombick.org/blog/wp-content/uploads/2009/01/11.png' title='11.png'><img src='http://boombick.org/blog/wp-content/uploads/2009/01/11.thumbnail.png' alt='11.png' /></a></p>
<p><code>http://www.example.com/test</code> Директории <code>test</code> не существует, но мы прописали алиас для этого пути. Поэтому мы видим содержимое DocumentRoot<br />
<a href='http://boombick.org/blog/wp-content/uploads/2009/01/21.png' title='21.png'><img src='http://boombick.org/blog/wp-content/uploads/2009/01/21.thumbnail.png' alt='21.png' /></a></p>
<p><code>http://www.example.org</code> Мы получаем ошибку 404, потому что индексного файла нет, а листинг директорий отключен<br />
<a href='http://boombick.org/blog/wp-content/uploads/2009/01/31.png' title='31.png'><img src='http://boombick.org/blog/wp-content/uploads/2009/01/31.thumbnail.png' alt='31.png' /></a></p>
<p><code>http://www.example.org/test</code> Листинг директорий отключен, и мы не делали алиасов для этого хоста. Поэтому все та же ошибка 404<br />
<a href='http://boombick.org/blog/wp-content/uploads/2009/01/4.png' title='4.png'><img src='http://boombick.org/blog/wp-content/uploads/2009/01/4.thumbnail.png' alt='4.png' /></a></p>
<p><noindex><b>Оригинал:</b> <a href="http://howtoforge.org/creating-advanced-mysql-based-vhosts-on-lighttpd-debian-etch">http://howtoforge.org/creating-advanced-mysql-based-vhosts-on-lighttpd-debian-etch</a></noindex></p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/49/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Интеграция APC (Alternative PHP Cache) с PHP5 и lighttpd</title>
		<link>http://boombick.org/blog/posts/44</link>
		<comments>http://boombick.org/blog/posts/44#comments</comments>
		<pubDate>Mon, 26 Jan 2009 20:23:11 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[*NIX]]></category>
		<category><![CDATA[highload]]></category>
		<category><![CDATA[web-servers]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/44</guid>
		<description><![CDATA[Эта статья описывает установку и настройку APC для PHP5 и lighttpd, работающих на Debian Etch. APC &#8211; это свободная и бесплатная система кэширования и оптимизации байт-кода PHP. Похожие системы &#8211; это, например, eAccelerator и XCache Установка проводилась на Debian Etch с IP-адресом 192.168.0.100. Подразумевается, PHP и lighttpd уже установлены и настроены. Я использовал домашнюю директорию [...]]]></description>
			<content:encoded><![CDATA[<p>Эта статья описывает установку и настройку APC для PHP5 и lighttpd, работающих на Debian Etch. APC &#8211; это свободная и бесплатная система кэширования и оптимизации байт-кода PHP. Похожие системы &#8211; это, например, eAccelerator и XCache<br />
<span id="more-44"></span><br />
Установка проводилась на Debian Etch с IP-адресом <code>192.168.0.100</code>. Подразумевается, PHP и lighttpd уже установлены и настроены. Я использовал домашнюю директорию lighttpd по умолчанию (<code>/var/www</code>), но вы можете использовать любой виртуальный хост :) Правда, в этом случае, путь к info.php придется скорректировать в соответствии с настройками вашего сервера.</p>
<p><strong>Начнем</strong><br />
Перед установкой APC, мы посмотрим на конфигурацию PHP. Для этого мы создадим файл <code>info.php</code> в домашней директории Лайти (<code>/var/www</code> в нашем примере):</p>
<blockquote><p>vim /var/www/info.php</p></blockquote>
<p>Со следующим содержанием:</p>
<blockquote>
<pre>
&lt;?php
phpinfo();
?&gt;</pre>
</blockquote>
<p>И вызовем его через браузер, у нас он находится по адресу <code>http://192.168.0.100/info.php</code>:<br />
<a href="http://boombick.org/blog/wp-content/uploads/2009/01/1.png" title="1.png"><img src="http://boombick.org/blog/wp-content/uploads/2009/01/1.thumbnail.png" alt="1.png" /></a><br />
Как мы видим, у нас установлен PHP версии 5.2.0&#8230; Но APC нет :(<br />
<a href="http://boombick.org/blog/wp-content/uploads/2009/01/2.png" title="2.png"><img src="http://boombick.org/blog/wp-content/uploads/2009/01/2.thumbnail.png" alt="2.png" /></a></p>
<p><strong>Установка APC</strong><br />
APC &#8211; это расширение для PHP, доступное через <noindex><a href="http://pecl.php.net/">PECL</a></noindex>. PECL можно установить через php-pear, поэтому сначала давайте установим pear:</p>
<blockquote><p>apt-get install php-pear</p></blockquote>
<p>Кроме того, мы должны установить некоторые зависимости APC, чтобы PECL смог его собрать</p>
<blockquote><p>apt-get install php5-dev build-essential</p></blockquote>
<p>Ну вот и все, зависимости установлены, ставим APC</p>
<blockquote><p>pecl install apc</p></blockquote>
<p>Нюанс: на следующий вопрос ответьте &#8220;Нет&#8221; (No):</p>
<blockquote><p> [...]<br />
Use apxs to set compile flags (if using APC with Apache)? [yes] : <span style="color: #ff0000">&lt;&#8211; no</span><br />
[...]</p></blockquote>
<p>Теперь, когда APC установлен, создадим конфигурационный файл <code>/etc/php5/cgi/conf.d/apc.ini</code> Единственно необходимая опция &#8211; это, собственно, активация самого APC: <code>extension=apc.so</code> Остальные опции являются необязательными, подробнее можно прочитать на <noindex><a href="http://php.net/manual/en/ref.apc.php">http://php.net/manual/en/ref.apc.php</a></noindex></p>
<blockquote><p>vim /etc/php5/cgi/conf.d/apc.ini</p></blockquote>
<blockquote>
<pre>
extension=apc.so
apc.enabled=1
apc.shm_size=30</pre>
</blockquote>
<p>Это все :) Давайте снова зайдем на нашу информационную страничку (<code>http://192.168.0.100/info.php</code>) и убедимся, что APC работает<br />
<a href="http://boombick.org/blog/wp-content/uploads/2009/01/3.png" title="3.png"><img src="http://boombick.org/blog/wp-content/uploads/2009/01/3.thumbnail.png" alt="3.png" /></a></p>
<p><noindex><strong>Оригинал:</strong> <a href="http://howtoforge.org/integrating-apc-into-php5-and-lighttpd-debian-etch">http://howtoforge.org/integrating-apc-into-php5-and-lighttpd-debian-etch</a></noindex></p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/44/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Локализация внутренних проблем Apache</title>
		<link>http://boombick.org/blog/posts/24</link>
		<comments>http://boombick.org/blog/posts/24#comments</comments>
		<pubDate>Wed, 12 Dec 2007 11:39:43 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[*NIX]]></category>
		<category><![CDATA[web-servers]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/24</guid>
		<description><![CDATA[Веб-сервер Apache установлен на большинстве серверов в мире. Его выбирают из-за отличной настраиваемости, расширяемости и превосходной функциональности. Однако большое количество модулей и, к сожалению, не всегда качественно написаные приложения порождают проблемы, которые бывает непросто решить. Поэтому очень важно иметь под рукой инструментарий для быстрой локализации и устранения неполадки. В этой статье я постараюсь помочь вам. [...]]]></description>
			<content:encoded><![CDATA[<p>Веб-сервер Apache установлен на большинстве серверов в мире. Его выбирают из-за отличной настраиваемости, расширяемости и превосходной функциональности. Однако большое количество модулей и, к сожалению, не всегда качественно написаные приложения порождают проблемы, которые бывает непросто решить. Поэтому очень важно иметь под рукой инструментарий для быстрой локализации и устранения неполадки. В этой статье я постараюсь помочь вам.<br />
<span id="more-24"></span><br />
<strong>Запустите сервер в единственном экземпляре</strong><br />
Другими словами, запретите ему форкаться :)<br />
При локализации причины сбоя это самый первый и необходимый шаг. Обычно apache порождает несколько своих копий при запуске, которые ожидают запросов от пользователей. Запуск сервера в единственном экземпляре облегчит отладку. Есть два способа запустить &#8220;одиночный&#8221; сервер: первый заключается в ручном изменении количества форков и нитей в конфиг-файле. Второй проще, можно запустить сервер с опцией &#8220;-X&#8221;</p>
<blockquote><p># httpd -X</p></blockquote>
<p>В таком режиме работы сервер не порождает новых форков и не теряет связи с родительским терминалом. Благодаря этому все коммуникации идут через один процесс, к которому легко можно подключить какой-нибудь отладчик (например, gdb)</p>
<p><strong>Проверка конфигурационного файла</strong><br />
Для некоторых веб-проектов конфигурационные файлы Apache разрастаются в геометрической прогрессии и локализовать ошибки в них становится все труднее. Сам сервер предлагает два способа решения этой проблемы. Первый &#8211; это запуск сервера с ключом <strong>-t</strong>, который активирует проверку конфигурационного файла:</p>
<blockquote><p> $ httpd -t -c httpd.conf<br />
Syntax error on line 236 of /etc/httpd/httpd.conf: LogLevel requires level keyword: one of emerg/alert/crit/error/warn/notice/info/debug</p></blockquote>
<p>Если ошибка найдена, то apache предложит возможные способы ее устранения. В приведенном примере неверно задано значение для директивы LogLevel.<br />
Если проверка говорит, что с конфигами все в порядке, но сервер, тем не менее, не стартует, то можно включить вывод более подробной информации в error_log: для этого установите директиву LogLevel в значение Debug в конфигурационном файле.</p>
<p><strong>Отладка cgi-сценариев</strong><br />
Apache позволяет выполнять сценарии, написанные практически на любом языке, при помощи mod_cgi. Эти сценарии могут формировать динамический контент по запросу клиента. Но вот локализация ошибок в подобных программах может стать не очень тривиальной задачей.<br />
Один из способов отладки таких скриптов &#8211; это директива ScriptLog модуля mod_cgi. Когда директива активирована, то сервер записывает в лог-файл вывод любого скрипта, работа которого завершилась неудачно. Вывод включает в себя код ответа сервера, запрос от клиента и ответ клиенту (если он имел место быть). Это великолепный отладочный инструмент для сценариев, которые не пишут ошибки в &#8220;традиционный&#8221; error_log или для быстрого выяснения проблемы, когда &#8220;что-то не работает&#8221;<br />
Для активирования логирования CGI-скриптов необходимо добавить директиву ScriptLog и указать расположение лог-файла в конфигурационном файле Apache. Когда логирование включено, mod_cgi пишет примерно вот такие логи:</p>
<blockquote><p> %% [Tue Dec 26 14:47:21 2006] GET /cgi-bin/print HTTP/1.1<br />
%% 500 /var/tmp/apache/cgi-bin/print<br />
%request<br />
Accept: */*<br />
Accept-Language: en<br />
Accept-Encoding: gzip, deflate<br />
User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.9.1 (KHTML, like Gecko) Safari/419.3<br />
Connection: keep-alive<br />
Host: 192.168.1.3:8080<br />
%response<br />
Script /cgi-bin/print<br />
%stdout<br />
Script Location /var/tmp/apache/cgi-bin/print</p></blockquote>
<p>Для нагруженных веб-сайтов или нехватке дискового пространства размер лога можно ограничивать с помощью директивы ScriptLogLength</p>
<p><strong>Отладка запросов и ответов</strong><br />
При поддержке веб-приложений необходимо четко локализовать место ошибки: это может сервер приложений, прокси-сервер или же сам веб-сервер. Для облегчения этого процесса хорошо помогает полный дамп диалога сервера с клиентом (то есть все запросы клиента и ответы сервера). Модуль mod_dumpio предназначен как раз для записи заголовков запроса и ответа в error_log. Настройка mod_dumpio выполняется очень быстро и просто: для логирования запросов директива DumpIOInput должна быть установлена в значение On; для логирования ответов установите в On директиву DumpIOOutput. Когда логирование активно, то в error_log появятся примерно вот такие строки:</p>
<blockquote><p> Sat Oct 28 10:52:31 2006] [debug] mod_dumpio.c(103): mod_dumpio: dumpio_in [getline-blocking] 0 readbytes<br />
[Sat Oct 28 10:52:31 2006] [debug] mod_dumpio.c(51): mod_dumpio: dumpio_in (data-HEAP): 16 bytes<br />
[Sat Oct 28 10:52:31 2006] [debug] mod_dumpio.c(67): mod_dumpio: dumpio_in (data-HEAP): GET / HTTP/1.1rn<br />
&lt; &#8230;.. &gt;</p></blockquote>
<p>Модуль mod_dumpio создает небольшую дополнительную нагрузку при обработке запросов и включение/выключение директив потребует его перезапуска. Вы можете мягкую перезагрузку (graceful restart) чтобы не потерять активных соединений.</p>
<p><strong>Локализация причин &#8220;зависания&#8221; сервера</strong><br />
Apache прекрасно оттестирован, но, тем не менее, ошибки все равно есть. Они могут выражаться в &#8220;подвисаниях&#8221; сервера, внезапных остановках или в неверном контенте, переданном пользователю. Когда случаются подобные ситуации, главное &#8211; это быстро найти модуль, который вызвал ошибку.<br />
Один из способов локализации ошибок такого рода &#8211; это просмотр стека вызовов подвисшего процесса. Стек вызовов содержит список функций, вызванных до той, которая породила ошибка. После зависания вам, вероятно, захочется узнать имя некорректно работающей функции, хотя бы для того, чтобы использовать его в качестве аргумента при поиске ошибки в багтрекерах и в качестве отправной точки при анализе кода сбойного модуля.</p>
<p>Одна из утилит, позволяющих получить такой стек, называется <em>pstack</em>. Она возвращает стек вызовов для процесса, номер которого передается ей в качестве аргумента.</p>
<blockquote><p> $ pstack 18756</p>
<p>18756:  bin/httpd -k start<br />
ff040628 accept   (3, 11c560, 11c54c, 1)<br />
0004c3c4 unixd_accept (ffbff904, 7d490, 11c3a0, 0, 2710, 0) + 10<br />
0004a3c0 child_main (7d490, 74400, 4e2e, 74000, 0, 74000) + 2ec<br />
0004a6c8 make_child (4a000, 0, 1, 5, 72c00, 74000) + ec<br />
0004b0e8 ap_mpm_run (72c00, 74000, 74000, 74000, 74000, 74400) + 934<br />
000272d8 main     (7ef18, 71c00, 73800, 73800, 0, 0) + 710<br />
00026618 _start   (0, 0, 0, 0, 0, 0) + 5c</p></blockquote>
<p>На платформах, где нет pstack можно воспользоваться утилитами <em>gdb</em> и <em>gcore</em> для получения стека вызовов. Для подключения к процессу напрямую и получению стека вызовов gdb должен быть запущен с ключом <strong>-p</strong>, идентификатором процесса и вызовом backtrace уже внутри оболочки отладчика</p>
<blockquote><p> #0  0x0046e7a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2<br />
#1  0x0063b681 in accept () from /lib/tls/libpthread.so.0<br />
#2  0x00b14814 in apr_socket_accept (new=0xbff85740, sock=0&#215;9671538,<br />
connection_context=0x97115d8) at network_io/unix/sockets.c:187<br />
#3  0x080819ce in unixd_accept (accepted=0xbff85774, lr=0&#215;9671518, ptrans=0x97115d8) at unixd.c:466<br />
#4  0x0807fd2e in child_main (child_num_arg=Variable &#8220;child_num_arg&#8221; is not available.) at prefork.c:621<br />
#5  0x0807ffc2 in make_child (s=Variable &#8220;s&#8221; is not available.) at prefork.c:736<br />
#6  0&#215;08080050 in startup_children (number_to_start=5) at prefork.c:754<br />
#7  0x0808089b in ap_mpm_run (_pconf=0x96730a8, plog=0x96a1160, s=0x9674f48) at prefork.c:975<br />
#8  0x08061b08 in main (argc=3, argv=0xbff85a84) at main.c:717</p></blockquote>
<p>Каждый дамп стека вызовов содержит несколько фрагментов отладочной информации, однако для полноценного устранения проблемы необходимо бОльшее количество информации и выборочный дамп структур данных сервера. Это может оказаться неприемлемым для проектов, не позволяющих даже кратковременных остановок. В этом слкчае на помощь приходит утилита gcore. Она может сгенерировать core-файл для зависшего процесса, который может быть использован для анализа ситуации системными администраторами и производителями операционных систем. В примере показано использование gcore для получения core-файла и использование gdb для анализа полученной информации:</p>
<blockquote><p> $ gcore 5649<br />
$ gdb -q /usr/sbin/httpd core.5649 (gdb) backtrace</p>
<p>#0  0x0046e7a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2<br />
#1  0x0063b681 in accept () from /lib/tls/libpthread.so.0<br />
#2  0x00b14814 in apr_socket_accept (new=0xbff85740, sock=0&#215;9671538,<br />
connection_context=0x97115d8) at network_io/unix/sockets.c:187<br />
#3  0x080819ce in unixd_accept (accepted=0xbff85774, lr=0&#215;9671518, ptrans=0x97115d8) at unixd.c:466<br />
#4  0x0807fd2e in child_main (child_num_arg=Variable &#8220;child_num_arg&#8221; is not available.) at prefork.c:621<br />
#5  0x0807ffc2 in make_child (s=Variable &#8220;s&#8221; is not available.) at prefork.c:736<br />
#6  0&#215;08080050 in startup_children (number_to_start=5) at prefork.c:754<br />
#7  0x0808089b in ap_mpm_run (_pconf=0x96730a8, plog=0x96a1160, s=0x9674f48) at prefork.c:975<br />
#8  0x08061b08 in main (argc=3, argv=0xbff85a84) at main.c:717</p></blockquote>
<p>В приведенных выше примерах можно увидеть, что выполнялась функция accept(), когда был получен системный сигнал SIGSEGV, которая, в свою очередь, была вызвана из метода apr_socket_accept(). Если эта проблема известна и описана, то выможете использовать эту информацию для поиска по базам данных ошибок. Для более подробной информации обратитесь к официальной документации.</p>
<p><strong>Локализация причин аварийных остановок сервера</strong><br />
Если процесс Apache аварийно завершился, то pstack и gcore будут бесполезны, так как процесс уже завершен. Теоретически, core-файл должен записываться в директорию, определенную в ServerRoot, но у пользователя, под которым запущен сервер, должны быть права на запись в эту директорию, должно быть достаточное количество дискового пространства. Если политики безопасности запрещают запись в ServerRoot, то можно определить местоположение core-файла при помощи директивы CoreDumpDirectory</p>
<p>На некоторых платформах нет возможности автоматически генерировать core-файл. Если вы используете именно такую платформу, то вам поможет модуль mod_backtrace. Этот модуль срабатывает при получении любого сигнала, останавливающего работу приложения (например SIGSEGV, SIGBUS итд.) При получении подобного сигнала mod_backtrace вызывает платформо-зависимую функцию для генерации стека вызовов и пишет его в error_log.</p>
<p>Этот модуль распространяется в исходных кодах и может быть загружен с сайта Apache</p>
<blockquote><p>$ wget http://people.apache.org/~trawick/mod_backtrace.c</p></blockquote>
<p>Для установки и подключения модуля утилита Apache <em>apxs</em> c ключом <strong>-c</strong> для сборки модуля и с ключом <strong>-i</strong> для его установки.</p>
<blockquote><p>$ apxs -ci mod_backtrace.c</p></blockquote>
<p>Для использования mod_backtrace apache должен быть собран с поддержкой ExceptionHook. Для этого можно указать &#8220;&#8211;enable-exception-hook&#8221; при сборке сервера. Когда модуль установлен, загружен и exception hook активен, то активировать модуль можно при помощи директивы LoadModule и установки директивы EnableExceptionHook в значение On:</p>
<blockquote><p> LoadModule backtrace_module modules/mod_backtrace.so<br />
EnableExceptionHook On</p></blockquote>
<p>После активации модуля при получении сервером критического сигнала в error_log окажутся похожие строки:</p>
<blockquote><p> $ kill -SIGSEGV 18745</p>
<p>[Wed Dec 20 16:48:32 2006] pid 18745 mod_backtrace backtrace for sig 11 (thread &#8220;pid&#8221; 18745)<br />
[Wed Dec 20 16:48:32 2006] pid 18745 mod_backtrace main() is at 26bc8<br />
/var/tmp/apache/modules/mod-backtrace.so:bt_exception_hook+0&#215;108<br />
/var/tmp/apache/bin/httpd:ap_run_fatal_exception+0&#215;34<br />
/var/tmp/apache/bin/httpd:0&#215;32788<br />
/lib/libc.so.1:0xc01dc<br />
/lib/libc.so.1:0xb52d4<br />
/lib/libc.so.1:_so_accept+0&#215;8 [ Signal 11 (SEGV)]<br />
/var/tmp/apache/bin/httpd:unixd_accept+0&#215;10<br />
/var/tmp/apache/bin/httpd:0x3a3c0<br />
/var/tmp/apache/bin/httpd:0x3a6c8<br />
/var/tmp/apache/bin/httpd:0x3a798<br />
/var/tmp/apache/bin/httpd:ap_mpm_run+0x9d4<br />
/var/tmp/apache/bin/httpd:main+0&#215;710<br />
/var/tmp/apache/bin/httpd:_start+0x5c<br />
[Wed Dec 20 16:48:32 2006] pid 18745 mod_backtrace end of backtrace</p></blockquote>
<p>mod_backtrace использует backtrace() на GNU системах и printstack() на платформах Solaris для получения корректного стека вызовов. В некоторых случаях дамп может содержать некорректные символы. В этом случае вам помогут утилиты <em>nm</em>, <em>readelf</em> и <em>elfdump</em>. Для использования mod_backtrace на хостах с Solaris на него необходимо наложить патч (ссылка на патч приведена в конце статьи)</p>
<p><strong>Отладка в &#8220;режиме разработчика&#8221; и макросы gdb для apache</strong><br />
Отладка на основе core-файлов &#8211; это искусство, требующее недюжинных знаний отлаживаемого кода и технологий его написания и сопровождения. Разработчики Apache это понимают и поэтому они реализовали несколько отличных инструментов для отладки сервера и включили два ключевых приема отладки в сервер. Первый &#8211; это так называемый &#8220;режим разработчика&#8221; (maintainer mode). Для его активации необходимо собрать сервер с ключом &#8211;enable-maintainer-mode. Этот режим включает отладочную информацию для всех функций сервера, в нем отсутствует оптимизация и исходный код на С может быть показан при помощи дебаггера.</p>
<p>Второй ключевой момент &#8211; это gdb-макросы. С их помощью можно увидеть содержмое сложных структур данных apache (например цепочек фильтров), эти сведения очень полезны при анализе core-файлов, полученных после сбоя сервера. Эти макросы находятся в файле .gdbinit, который расположен в корневой директории с исходными кодами сервера. Если вы хотите больше узнать о этих макросах, то в конце статьи приведены ссылки.</p>
<p><strong>Использование исходного кода Apache для устранения проблем</strong><br />
Когда анализ лог-файлов, core-файлов и использование системных утилит не приносит результатов, можно обратиться напрямую к исходным кодам сервера. Исходный код помещен в четкую иерархическую структуру и каждый каталог содержит код конкретного объекта. В релизе 2.2.3 в дереве содержатся следующие каталоги:</p>
<ul>
<li>$SRCROOT/server &#8211; ядро сервера</li>
<li>$SRCROOT/include &#8211; заголовочные файлы</li>
<li>$SRCROOT/srclib/apr &#8211; окружение среды выполнения</li>
<li>$SRCROOT/srclib/apr-util &#8211; утилиты среды выполнения</li>
<li>$SRCROOT/support &#8211; утилиты</li>
<li>$SRCROOT/modules &#8211; модули</li>
</ul>
<p>Если стек вызовов или сессия отладки показывают на проблему со специфичной функцией, то можно найти ее описание в дереве исходных кодов при помощи утилиты <em>find</em></p>
<blockquote><p> $ find . -name \*.h | xargs egrep &#8220;apr_array_make&#8221;</p>
<p>./srclib/apr/include/apr_tables.h:APR_DECLARE(apr_array_header_t *) apr_array_make(apr_pool_t *p, &#8230;<br />
&lt; &#8230; &gt;</p></blockquote>
<p>После того, как описание найдено, при помощи <em>find</em> и <em>grep</em> можно найти и ее определение:</p>
<blockquote><p> $ find . -name \*.c | xargs egrep &#8220;apr_array_header_t.*apr_array_make&#8221;</p>
<p>/srclib/apr/tables/apr_tables.c:APR_DECLARE(apr_array_header_t *) apr_array_make(apr_pool_t *p, &#8230;<br />
&lt; &#8230; &gt;</p></blockquote>
<p>В приведенном пример прототип функции находится в файле apr_tables.h, а описание в apr_tables.c. Но помните, что в зависимости от того, что вы ищете (функцию или макрос) результаты поиска могут потребовать дополнительной обработки.</p>
<p><strong>Полезные ссылки</strong><br />
<noindex><a href="http://httpd.apache.org/">Официальный сайт Apache</a><br />
<a href="http://prefetch.net/presentations/Apache_Presentation.pdf">Внутреннее устройство и отладка Apache</a><br />
<a href="http://www.cs.virginia.edu/~jcw5q/talks/apache/apache2moddebugging.ppt">Устройство модулей в Apache2</a><br />
<a href="http://people.apache.org/~trawick/exception_hook.html">Модуль mod_backtrace</a><br />
<a href="http://prefetch.net/code/mod-backtrace.diff">Патч для модуля mod_backtrace для использования на платформе Solaris</a></noindex></p>
<p>Оригинал: <a href="http://prefetch.net/articles/debuggingapache.html">http://prefetch.net/articles/debuggingapache.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/24/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	<img style='margin:0;padding:0;border:0;' width='1px' height='1px' src="http://boombick.org/blog/wp-content/plugins/mystat/mystat.php?act=time_load&id=0&rnd=828086505" /></channel>
</rss>

