FreeBSD: Apache + mpm_worker + PHP + mod_fcgid

Автор: | 11/09/2012
 

Если вы вообще не знаете что такое Multi-Processing Module  то для начала почитайте эту>>> статью. Там же рассказывается, какая разница между worker, prefork и другими MPM. Мы будем использовать MPM worker.

PHP будет обрабатываться с помощью модуля FastCGI. Тут на выбор – использовать mod_fcgid или mod_fastcgi. Будем использовать mod_fcgid, так как данный модуль позволяет индивидуально для каждого виртуального хоста установить минимальное/максимальное количество запущенных экземпляров FastCGI приложения. Так же, можно индивидуально задавать и большинство других параметров. В тоже время mod_fastcgi умеет работать со встроенным в PHP менеджером процессов, а mod_fcgid не умеет. Такое поведение mod_fastcgi позволяет PHP работать с различными акселераторами. В случае же mod_fcgid акселераторы менее эффективны, потому что для каждого экземпляра FastCGI приложения (в данном случае процесс PHP) будет создаваться свой разделяемый сегмент памяти.

Однако, с mod_fastcgi иногда возникают проблемы – процессы для PHP рождаются, но не умирают и бесконечно висят. С mod_fcgid таких проблем нет. Встроенный в PHP процесс-менеджер, который должен следить за подобными процессами, имеет множество врожденных проблем. У mod_fcgid есть свой нормальный менеджер процессов, который не дает PHP висеть, потреблять оперативную память и ничего не делать. Акселераторы да, с ним не работают. Вообще, лучший из них (по нашим тестам) – Xcache – не высвобождал память от своего кеша, загоняя сервер в swap. Поэтому от акселераторов мы отказались.

В примере используются:

# uname -a
FreeBSD 9.0-RELEASE

# httpd -v
Server version: Apache/2.2.22 (FreeBSD)

# php -v
PHP 5.3.16 with Suhosin-Patch (cli)

Приступим.

Начнем с редактирования файла  /etc/make.conf, добавим в него строки:

# cat /etc/make.conf
PERL_VERSION=5.12.4
WITHOUT_X11=yes
NO_X11=yes
WITHOUT_GUI=yes
NO_GUI=yes
WITHOUT_IPV6=yes
NO_IPV6=yes
WITHOUT_INET6=yes
NO_INET6=yes

WITH_APACHE_SUEXEC=yes
SUEXEC_DOCROOT=/
SUEXEC_USERDIR=www
SUEXEC_LOGFILE=/var/log/apache/suexec.log
APACHE_BUFFERED_LOGS=yes

Начинаем сборку самого Apache:

# cd /usr/ports/www/apache22-worker-mpm/
# make config-recursive

Устанавливаем следующие пункты:

# make showconfig | grep suexec
SUEXEC=on: mod_suexec

# make showconfig | grep cgi
CGID=on: mod_cgid
PROXY_SCGI=off: mod_proxy_scgi

# make install clean

Проверяем, как собрался suexec:

# suexec -V
-D AP_DOC_ROOT=”/”
-D AP_GID_MIN=1000
-D AP_HTTPD_USER=”www”
-D AP_LOG_EXEC=”/var/log/apache/suexec.log”
-D AP_SAFE_PATH=”/usr/local/bin:/usr/bin:/bin”
-D AP_UID_MIN=1000
-D AP_USERDIR_SUFFIX=”www”

Сам Apache будем проверять позже, когда дойдем до его конфигурирования.

Если MySQL не установлен – устанавливаем. Т.к. отличий нет, то процесс установки и начальной настройки MySQL можно прочитать тут>>>.

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

# cd /usr/ports/lang/php5
# make config-recursive

Обязательно отмечаем для установки:

CGI=on: Build CGI version

и НЕ устанавливаем модуль для Apache:

APACHE=off: Build Apache module

Проверяем:

# /usr/local/bin/php-cgi -v
PHP 5.4.6 (cgi-fcgi) (built: Aug 30 2012 08:57:21)
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2012 Zend Technologies

Нас тут интересует вот это: PHP 5.4.6 (cgi-fcgi).

Устанавливаем расширения РНР:

# cd /usr/ports/lang/php5-extensions
# make config-recursive
# make install clean

Далее – выполняем установку модуля FastCGI:

# cd /usr/ports/www/mod_fcgid
# make install clean

Приступим к настройке виртуалхоста для сайта example.org.ua, который будет работать на этом сервере.

Создадим рабочий каталог сайта.

# mkdir /usr/local/www/apache22/data/example.org.ua

Создадим каталог для хранения настроек PHP:

# mkdir /usr/local/www/apache22/fcgi/

И в нем каталог для нашего сайта:

# mkdir /usr/local/www/apache22/fcgi/example.org.ua/

Файлы сайта надо будет загружать в /usr/local/www/apache22/data/example.org.ua!

Каталог …/fcgi/example.org.ua/ используется только для хранения файла с описанием обработчика (“wrapper“) PHP-запросов нашего сайта, который будет вызывать уже непосредственно сам обработчик:

Далее, в этом каталоге создаем сам файл, назовем его php.cgi и в него добавим:

#!/bin/sh
PHP_FCGI_CHILDREN=0
PHP_INI_SCAN_DIR=/usr/local/www/apache22/fcgi/example.org.ua
PHP_FCGI_MAX_REQUESTS=400
PHPRC=/usr/local/etc/
export PHP_FCGI_CHILDREN
export PHP_INI_SCAN_DIR
export PHP_FCGI_MAX_REQUESTS
export PHPRC
exec /usr/local/bin/php-cgi

В этот же каталог – отдельный файл настроек РНР php.ini:

# cp /usr/local/etc/php.ini-production /usr/local/www/apache22/fcgi/example.org.ua/php.ini

Отдельный php.cgi нужен потому, что в нем задается путь к php.ini. А отдельный php.ini нужен для настроек виртуалхоста, т.к. настройки PHP заданные в виде php_value в файле .htaccess, работают только в том случае, если используется mod_php. При использовании mod_fcgi они вызовут ошибку 500.

Схема FastCGI очень гибкая, и она предполагает что каждому сайту на сервере можно подключить разный набор расширений PHP. То есть одному сайту можно разрешить использовать расширение mysql или gd, другому – запретить. Чтобы разрешить использовать необходимые расширения – нужно создать в /usr/local/www/apache22/fcgi/example.org.ua кроме php.ini еще и extensions.ini, или же поместить текст из extensions.ini в конец файла php.ini.

Или просто скопировать готовый:

# cp /usr/local/etc/php/extensions.ini /usr/local/www/apache22/fcgi/example.org.ua/extensions.ini

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

Username   : example
Password   : *****
Full Name  :
Uid        : 1002
Class      :
Groups     : example
Home       : /usr/local/www/apache22/data/example.org.ua
Shell      : /usr/sbin/nologin

Сменим владельца файлов:

# chown example:example php*
# ls -la

-rwxr–r–  1 example example 261 Sep  8 20:00 php.cgi
-r–r–r–  1 example example 66938 Sep  8 22:34 php.ini
-rw-r–r–  1 example example 402 Sep 11 17:48 extensions.ini

Даем права на запуск файла-обработчика:

# chmod +x php.cgi

Примеры файлов:

php.ini

extensions.ini

Переходим в каталог выше, и меняем владельца каталога:

# cd ../
# chown example:example example.org.ua
# ls -la

drwxr-xr-x  2 example example 512 Sep  8 22:34 example.org.ua

В каталоге /usr/local/bin меняем пользователя файлов, которые непосредственно будут заниматься обработкой PHP:

# chown www:www php php-cgi

Создадим каталог хранения логов:

# mkdir /var/log/apache/

Создадим файлы логов этого сайта:

# touch /var/log/apache/example.org.ua.error.log
# touch /var/log/apache/example.org.ua.access.log

Заодно – файл лога suexec:

# touch /var/log/apache/suexec.log

Создадим каталог для хранения конфигураций виртуалхостов (для каждого виртуала – свой отдельный файл, что бы не засорять httpd.conf и не забивать все в один файл, например …/extra/httpd-vhost.conf:

# mkdir /usr/local/etc/apache22/sites/

Создадим конфиг виртуалхоста для сайта example.org.ua с таким содержимым:

# cat /usr/local/etc/apache22/sites/example.org.ua.conf

<VirtualHost example.org.ua:80>
SuexecUserGroup example example
ServerName “example.org.ua”
ServerAlias “www.example.org.ua”

DocumentRoot “/usr/local/www/apache22/data/example.org.ua”
ErrorLog “/var/log/apache/example.org.ua.error.log”
CustomLog “/var/log/apache/example.org.ua.access.log” “combined”

ScriptAlias /cgi-bin/ /usr/local/www/apache22/fcgi/example.org.ua/

<Directory “/usr/local/www/apache22/data/example.org.ua”>
Options -ExecCGI -Indexes +FollowSymLinks -Multiviews
</Directory>
</VirtualHost>

Приступаем к настройке самого Apache.

Правим httpd.conf, приводим его к такому виду:

# Общие настройки сервера:
ServerRoot       “/usr/local”
ServerAdmin      root@setevoy.org.ua
ServerName       takashi.setevoy.org.ua
ServerSignature  EMail
ServerTokens     OS

Listen 80

# Ненужные модули закомментированы, что бы не грузить лишнего. Снимите # если требуется загрузить модуль
#LoadModule authn_file_module libexec/apache22/mod_authn_file.so
#LoadModule authn_dbm_module libexec/apache22/mod_authn_dbm.so
#LoadModule authn_anon_module libexec/apache22/mod_authn_anon.so
LoadModule authn_default_module libexec/apache22/mod_authn_default.so
LoadModule authn_alias_module libexec/apache22/mod_authn_alias.so
LoadModule authz_host_module libexec/apache22/mod_authz_host.so
LoadModule authz_groupfile_module libexec/apache22/mod_authz_groupfile.so
LoadModule authz_user_module libexec/apache22/mod_authz_user.so
#LoadModule authz_dbm_module libexec/apache22/mod_authz_dbm.so
LoadModule authz_owner_module libexec/apache22/mod_authz_owner.so
LoadModule authz_default_module libexec/apache22/mod_authz_default.so
LoadModule auth_basic_module libexec/apache22/mod_auth_basic.so
LoadModule auth_digest_module libexec/apache22/mod_auth_digest.so
#LoadModule file_cache_module libexec/apache22/mod_file_cache.so
#LoadModule cache_module libexec/apache22/mod_cache.so
#LoadModule disk_cache_module libexec/apache22/mod_disk_cache.so
#LoadModule dumpio_module libexec/apache22/mod_dumpio.so
#LoadModule reqtimeout_module libexec/apache22/mod_reqtimeout.so
LoadModule include_module libexec/apache22/mod_include.so
#LoadModule filter_module libexec/apache22/mod_filter.so
#LoadModule charset_lite_module libexec/apache22/mod_charset_lite.so
#LoadModule deflate_module libexec/apache22/mod_deflate.so
LoadModule log_config_module libexec/apache22/mod_log_config.so
LoadModule logio_module libexec/apache22/mod_logio.so
LoadModule env_module libexec/apache22/mod_env.so
LoadModule mime_magic_module libexec/apache22/mod_mime_magic.so
#LoadModule cern_meta_module libexec/apache22/mod_cern_meta.so
LoadModule expires_module libexec/apache22/mod_expires.so
LoadModule headers_module libexec/apache22/mod_headers.so
#LoadModule usertrack_module libexec/apache22/mod_usertrack.so
#LoadModule unique_id_module libexec/apache22/mod_unique_id.so
LoadModule setenvif_module libexec/apache22/mod_setenvif.so
#LoadModule version_module libexec/apache22/mod_version.so
LoadModule ssl_module libexec/apache22/mod_ssl.so
LoadModule mime_module libexec/apache22/mod_mime.so
#LoadModule dav_module libexec/apache22/mod_dav.so
LoadModule status_module libexec/apache22/mod_status.so
LoadModule autoindex_module libexec/apache22/mod_autoindex.so
#LoadModule asis_module libexec/apache22/mod_asis.so
LoadModule info_module libexec/apache22/mod_info.so
LoadModule suexec_module libexec/apache22/mod_suexec.so
LoadModule cgid_module libexec/apache22/mod_cgid.so
#LoadModule dav_fs_module libexec/apache22/mod_dav_fs.so
#LoadModule vhost_alias_module libexec/apache22/mod_vhost_alias.so
LoadModule negotiation_module libexec/apache22/mod_negotiation.so
LoadModule dir_module libexec/apache22/mod_dir.so
#LoadModule imagemap_module libexec/apache22/mod_imagemap.so
LoadModule actions_module libexec/apache22/mod_actions.so
#LoadModule speling_module libexec/apache22/mod_speling.so
#LoadModule userdir_module libexec/apache22/mod_userdir.so
LoadModule alias_module libexec/apache22/mod_alias.so
LoadModule rewrite_module libexec/apache22/mod_rewrite.so
LoadModule fcgid_module libexec/apache22/mod_fcgid.so
#LoadModule cgi_module libexec/apache22/mod_cgi.so

<IfModule !mpm_netware_module>
<IfModule !mpm_winnt_module>

# Пользователь и группа, от имени которого будет работать Apache
User www
Group www

</IfModule>
</IfModule>

# Рабочий каталог сервера, в котором будут храниться файлы сайтов
DocumentRoot “/usr/local/www/apache22/data”

# Настраиваем модуль worker
<IfModule mpm_worker_module>
ServerLimit 240
StartServers 5
MaxClients 240
MinSpareThreads 2
MaxSpareThreads 20
ThreadsPerChild 20
MaxRequestsPerChild 600
</IfModule>

# Немного тюнинга самого Apache
#The option Timeout specifies the amount of time Apache will wait for a
#GET, POST, PUT request and ACKs on transmissions. You can safely leave

#this option on its default values.
Timeout 300

# The option KeepAlive, if set to On,
#specifies enabling persistent connections on this web server. For better performance,
#it’s recommended to set this option to On, and allow more than one request per
#connection.
KeepAlive On

# UseCanonicalName: Определяет как Apache
#строит внутренние URL-ссылки и значения переменных SERVER_NAME и SERVER_PORT. Когда
#задано “Off”, Apache использует имя и порт, данные клиентом. Если же задано “On”, то
#Apache использует значение директивы ServerName.
UseCanonicalName Off

# Директива HostnameLookups указывает,
#записывается ли в журнальный файл имя компьютера (например, macl.shoop.com) или
#только его IP-адрес (например, 152.2.22.81). По умолчанию сервер сохраняет имя
#компьютера, но если ожидаемый объем графика очень велик, отключение опции
#HostnameLookups позволит немного уменьшить нагрузку на сервер.
HostnameLookups Off

# Keep track of extended status information
each request. This setting applies to the entire server, and cannot be enabled
#or disabled on a virtualhost-by-virtualhost basis. The collection of extended status
#information can slow down the server.
ExtendedStatus On

# Настраиваем корневую директорию сервера (см. ServerRoot)
<Directory />
Options FollowSymLinks SymLinksIfOwnerMatch
AllowOverride None
Order deny,allow
Deny from all
# Если появляются 403 неизвестно откуда – попробуйте заменить предыдущие
# 2 строки на строки , находящиеся ниже
# Order allow,deny
# Allow from all
</Directory>

# Настраиваем директорию для сайтов
#(настройки относятся ко всем сайтам внутри неё, если другое не будет указано в описании виртуалхоста)
<Directory “/usr/local/www/apache22/data”>
Options FollowSymLinks SymLinksIfOwnerMatch
AllowOverride None
Order allow,deny
Allow from all
</Directory>

# Какие файлы загружать по-умолчанию,
#если в запросе не указан конкретный
<IfModule dir_module>
DirectoryIndex index.php index.htm index.html index.shtml
</IfModule>

AccessFileName .htaccess

AcceptFilter http none
AcceptFilter https none

# Ограничиваем доступ к файлам htaccess,
и другим, начинающимся с ht
<FilesMatch “^.ht”>
Order allow,deny
Deny from all
Satisfy All
</FilesMatch>

# Файл лога ошибок по умолчанию
ErrorLog “/var/log/httpd-error.log”

# Уровень логирования
LogLevel warn

<IfModule log_config_module>
LogFormat “%h %l %u %t “%r” %>s %b “%{Referer}i” “%{User-Agent}i”” combined
LogFormat “%h %l %u %t “%r” %>s %b” common

<IfModule logio_module>
# You need to enable mod_logio.c to use %I and %O
LogFormat “%h %l %u %t “%r” %>s %b “%{Referer}i” “%{User-Agent}i” %I %O” combinedio
</IfModule>
CustomLog “/var/log/httpd-access.log” combined
</IfModule>

<IfModule alias_module>
ScriptAlias /cgi-bin/ “/usr/local/www/apache22/cgi-bin/”
</IfModule>

<Directory “/usr/local/www/apache22/cgi-bin”>
AllowOverride None
Options None
Order allow,deny
Allow from all
</Directory>

<Directory /usr/local/www/apache22/fcgi/*/>
Options ExecCGI
AllowOverride none
Order allow,deny
Allow from all
</Directory>

DefaultType text/plain

<IfModule mime_module>
TypesConfig etc/apache22/mime.types
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
</IfModule>

<IfModule ssl_module>
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
SSLSessionCache nonenotnull
</IfModule>

<IfModule mod_cgi.c>
AddHandler cgi-script .pl .cgi
</IfModule>

<IfModule mod_fcgid.c>
FcgidMaxProcesses 400
FcgidMaxProcessesPerClass 40
FcgidMinProcessesPerClass 0
FcgidMaxRequestInMem 8388608
FcgidMaxRequestLen 31457280
FcgidFixPathinfo 1
FcgidIdleScanInterval 10
FcgidBusyScanInterval 10
FcgidIdleTimeout 120
FcgidBusyTimeout 600
FcgidProcessLifetime 600
FcgidIOTimeout 300
FcgidMaxRequestsPerProcess 400
FcgidPassHeader Authorization
FcgidPassHeader Proxy-Authorization
FcgidPassHeader HTTP_AUTHORIZATION

AddType application/x-httpd-fastphp .php

Action application/x-httpd-fastphp /cgi-bin/php.cgi
Action application/x-httpd-php /cgi-bin/php.cgi

<Location /cgi-bin/>
Options ExecCGI
SetHandler fcgid-script
</Location>
</IfModule>

NameVirtualHost 77.120.101.36:80

# Подключаем каталог с файлами конфигураций виртуалхостов
Include “/usr/local/etc/apache22/sites/”

Готовый пример httpd.conf без комментариев можно взять ту:

httpd.conf

Сохраняем, и проверяем ничего ли не напутали:

# apachectl configtest
Syntax OK

Запускаем Apache:

# apachectl start

Или:

# apachectl onestart

Не забываем добавить его в /etc/rc.conf для запуска при старте сервера:

apache22_enable=”YES”

Проверяем, загрузились ли требуемые модули:

# httpd -M | grep cgi
cgi_module (shared)
fcgid_module (shared)
Syntax OK

В каталоге /usr/local/www/apache22/data/example.org.ua создаем файл index.php и в него добавляем код:

<?php
phpinfo();
?>

И пробуем зайти на сам сайт http://example.org.ua.

UPD: Хотя я давно не пользуюсь Apache HTTPmod_fcgid, но хороший человек посоветовал добавить:

1. На счет отдельных файлов настроек РНР, то копировать extensions.ini в php.ini нельзя, так как в настройках php могут быть указаны еще глобальные extensions.ini, которые относятся к общему php. Как минимум, будут дублироваться модули, но это не так страшно, хуже если php при обработке скрипта будет вываливать 504. А фейлится он будет при дублировании таких модулей/библиотек: xmlreader, soap, pdo_pgsql, http, xls (это в php 5.4), если говорить о php5.5, то к списку добавляется xmlrpc и shmop. Поэтому их надо разграничивать, модули, которые прописаны в глобальном extention не должны дублироваться в php.ini, ошибка будет не совсем явной.
2. Директивы в апаче ScriptAlias /cgi-bin/ “/usr/local/www/apache22/cgi-bin/”, AddHandler cgi-script .pl .cgi и Directory /usr/local/www/apache22/fcgi/*/ в совокупности открывают потенциальную дыру. Если открыть любой домен и дописать к URI /cgi-bin/php.cgi, то увидем содержимое этого php.cgi, а это значит, что потенциально можно передать запрос через php/? на обработку php-cgi. В конец httpd.conf измени вот это:
<Directory /usr/local/www/apache22/fcgi/*/>
Options ExecCGI
AllowOverride none
Order allow,deny
Allow from all

на вот такое:
<Directory /usr/local/www/apache22/fcgi/*/>
Options ExecCGI
AllowOverride none
Order Deny,Allow
Deny from All
Allow from env=REDIRECT_STATUS
</Directory>

Просто добавь к статье, что бывают еще /usr/local/etc/php/extensions.ini и эти файлы относятся к глобальным настройкам php, модули в них не должны дублироваться с модулями в php.ini.
И к директиве в апаче допиши Allow from env=REDIRECT_STATUS

Материалы по теме:

http://httpd.apache.org
http://www.faqs.org
http://100.org.ua
http://dn.forceit.ru
http://веб-информ.рф
http://apachedev.ru
http://stopxaker.ru
http://silinio.webhost.ru
http://www.opennet.ru
http://dn.forceit.ru
http://www.faqs.org
http://adminlog.ru
http://httpd.apache.org
http://remotehelp.pp.ua
http://dedicatesupport.com
http://www.cyberciti.biz
http://vds-admin.ru
http://www.info-x.org
http://greenmice.info