Apache + php + (mod_fcgid | mod_fastcgi)

Прочел я недавно, что Apache в режиме FastCGI работает гораздо быстрее CGI. Работа сервера в режиме FastCGI не сильно отличается от обычного режима, с одной лишь разницей - процессы не создаются каждый раз при обращении к скриптам, а остаются в памяти, поэтому один процесс может обработать множество запросов, в связи с чем уменьшается отклик сервера. Так вот решил я настроить подобную связку. На сервере установлена ОС FreeBSD 7.3. Ставить все будем на чистую систему, если установлены старые версии пакетов, то просто удалите их.

Итак, лезем в порты ставить php, доступная на данный момент версия 5.2.14. Версию 5.3 не хочу, так как разработчики поубирали из нее много старых функций и не весь софт ее еще держит.

# cd /usr/ports/lang/php52
# make install clean

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

  • CLI
  • CGI
  • REDIRECT
  • DISCARD
  • FASTCGI
  • PATHINFO

После установки php ставим apache. Вначале укажем опции сборки для апача. В опциях я указал в роли обрабатывающего соединения модуля, модуль worker. В данной конфигурации данный модуль будет эффективнее стандартного, потому что PHP будет работать в виде отдельного независимого процесса (а не в виде модуля apache), поэтому на апач будет возложена задача отдачи только статического контента. А модуль worker с этой задачей справляется лучше (лучше, надо понимать здесь как быстрее), да и памяти съедает гораздо меньше.
Правим /etc/make.conf :

# cat /etc/make.conf

PORTSDIR?=/usr/ports

.if ${.CURDIR} == ${PORTSDIR}/www/apache20
WITH_MPM=worker
WITH_SUEXEC=yes
SUEXEC_DOCROOT="/usr/home"
#SUEXEC_USERDIR="www"
WITH_AUTH_MODULES=yes
WITH_DAV_MODULES=yes
WITH_MISC_MODULES=yes
WITH_SSL_MODULES=yes
WITH_KQUEUE_SUPPORT=yes
WITH_EXCEPTION_HOOK=yes
.endif

Теперь ставим апач.

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

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

Port:   ap20-mod_fcgid-2.3.5
Path:   /usr/ports/www/mod_fcgid
Info:   An alternative FastCGI module for Apache2
Maint:  hemi@puresimplicity.net
B-deps: apache-2.0.63_15 apr-ipv6-devrandom-gdbm-db42-0.9.18.0.9.17 db42-4.2.52_5 expat-2.0.1_1 gdbm-1.8.3_3 libiconv-1.13.1_1 pcre-8.10 perl-5.10.1_2
R-deps: apache-2.0.63_15 apr-ipv6-devrandom-gdbm-db42-0.9.18.0.9.17 db42-4.2.52_5 expat-2.0.1_1 gdbm-1.8.3_3 libiconv-1.13.1_1 pcre-8.10 perl-5.10.1_2
WWW:    http://httpd.apache.org/mod_fcgid/

Ставим:

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

Если вам больше нравится модуль mod_fastcgi, то установите его (далее будет пример конфигурации с этим модулем). Установить можно так:

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

После окончания установки лезем править конфиг apache. Нужно подключить установленный модуль, для этого добавляем следующую строку:

LoadModule fcgid_module libexec/apache2/mod_fcgid.so
# или
LoadModule fastcgi_module libexec/apache2/mod_fastcgi.so

Далее пишем настройки для модуля:

<IfModule mod_fcgid.c>
 FcgidMaxProcesses 30
 FcgidMaxProcessesPerClass 5
 FcgidMinProcessesPerClass 1
 FcgidIdleTimeout 100
 FcgidMaxRequestLen 1048576
 FcgidMaxRequestsPerProcess 300
 FcgidProcessLifetime 1800
 FcgidFixPathinfo 1
 FcgidIOTimeout 180
 FcgidIPCDir /var/run/fcgidsock
 FcgidProcessTableFile /var/run/fcgid_shm
 FcgidPassHeader Authorization
 FcgidPassHeader Proxy-Authorization
 FcgidPassHeader HTTP_AUTHORIZATION
 #FcgidWrapper /usr/local/sbin/suexec

 <Location /php-bin/>
   SetHandler fcgid-script
   Options ExecCGI
   AllowOverride None
   Order allow,deny
   Allow from all
 </Location>
</IfModule>

или

<IfModule mod_fastcgi.c>
  FastCgiConfig -autoUpdate \
                       -singleThreshold 10 -multiThreshold 30 \
                       -idle-timeout 30 -killInterval 150 \
                       -min-server-life 15 -minProcesses 1 \
                       -maxClassProcesses 5 -maxProcesses 50 \
                       -pass-header Authorization \
                       -pass-header Proxy-Authorization \
                       -pass-header HTTP_AUTHORIZATION
 FastCgiIpcDir /var/run/fastcgi
 FastCgiWrapper /usr/local/sbin/suexec

 <Location /php-bin/>
   SetHandler fastcgi-script
   Options ExecCGI
   AllowOverride None
   Order allow,deny
   Allow from all
 </Location>
</IfModule>

Прокомментирую опции для модулей:

mod_fcgid:

  • FcgidFixPathinfo - должно быть 1, если в php.ini параметр cgi.fix_pathinfo выставлен в 1. В большинстве случаев включение данного параметра необходимо для правильной работы софта. Существует мнение, что установка данного параметра в 1 небезопасна, из-за возможной подстановки на исполнение вредоносного кода. В сети много дискуссий на эту тему. Если хотите разобраться, то ищите по ключевой фразе cgi.fix_pathinfo security.
  • FcgidIOTimeout - максимальное время ожидание ответа от FastCGI приложения.
  • FcgidMaxProcesses - максимальное количество процессов FastCGI.
  • FcgidMaxProcessesPerClass - максимальное количество процессов на программу FastCGI.
  • FcgidMinProcessesPerClass - минимальное количество процессов на программу FastCGI.
  • FcgidIdleTimeout - если процесс не обрабатывал запросы в течении указанного здесь времени в секундах и текущее количество процессов на программу больше, чем FcgidMinProcessesPerClass, то он прибьется.
  • FcgidMaxRequestLen - максимальный размер запроса HTTP.
  • FcgidMaxRequestsPerProcess - приложение FastCGI будет уничтожено, после того как обработает указанное здесь количество запросов.
  • FcgidPassHeader - запрос, который передается в переменные окружения.
  • FcgidProcessLifeTime - максимальное время жизни процесса FastCGI.

mod_fastcgi:

  • autoUpdate - заставляет модуль проверять время модификации приложений на диске перед каждым запросом. Если приложение было изменено, то менеджер процессов оповестит все запущенные процессы связанные с приложением. Могут возникнуть проблемы при одновременном использовании с ключом -restart.
  • idle-timeout - время простоя приложения перед принудительным завершением и записи об этом в лог файл.
  • killInterval - время, по истечению которого менеджер будет прибивать процессы.
  • minProcesses - минимальное количество процессов, запущенных одновременно.
  • maxClassProcesses - максимальное количество процессов для одной FastCGI программы.
  • maxProcesses - максимальное количество процессов FastCGI.
  • pass-header - пропускать указанные заголовки HTTP в переменные окружения cgi приложения.
  • restart - заставляет менеджер процессов перезапускать приложения после сбоев.
  • singleThreshold - целое число между 0 и 100, задающее минимальный порог загрузки для последнего экземпляра fastcgi приложения, если текущая загрузка приложения ниже этого порога, то менеджер процессов прибьет это приложение.
  • multiThreshold - целое число между 0 и 100, задающее минимальный порог загрузки для fastcgi приложений, если нагрузка ниже заданного порога, то менеджер процессов прибьет лишние экземпляры процесса, оставив только один.

Вот пример виртуального хоста:

<VirtualHost *:80>
 SuexecUserGroup chihpih chihpih
 DocumentRoot /home/chihpih/data/www/chihpih.no-ip.org
 DirectoryIndex index.php index.html

 ServerName chihpih.no-ip.org
 ServerAdmin webmaster@chihpih.no-ip.org

 ErrorLog /home/chihpih/data/log/error.log
 #CustomLog /home/chihpih/data/log/access.log common

 <IfModule mod_fcgid.c>
   AddType application/x-httpd-php .php
   AddType application/x-httpd-php-source .phps
   Action application/x-httpd-php /php-bin/php.sh
   Alias /php-bin/ "/home/chihpih/data/php-bin/"
 </IfModule>

 <IfModule mod_fastcgi.c>
   AddType application/x-httpd-php .php
   AddType application/x-httpd-php-source .phps
   Action application/x-httpd-php /php-bin/php.sh
   Alias /php-bin/ "/home/chihpih/data/php-bin/"
 </IfModule>

 <Directory "/home/chihpih/data/www/chihpih.no-ip.org/">
   Options FollowSymLinks MultiViews
   AllowOverride All
   Order allow,deny
   Allow from all
 </Directory>
</VirtualHost>

Обновление от 18.12.2014г.

Хотелось бы отметить следующий момент по связке Apache 2.2 и mod_fcgid: при включенной опции daily_clean_tmps_enable в файле /etc/periodic.conf, после очередной чистки директории с временными файлами (/tmp), в логах появляется следующая ошибка — No such file or directory: mod_fcgid: apr_global_mutex_child_init error, которая исправляется перезапуском демона httpd. Возникает она по одной простой причине — модуль mod_fcgid собирается в FreeBSD с реализацией мьютексов (mutex) через "файлы". Естественно такие файлы создаются в директории с временными файлам (/tmp). После очередной чистки директории /tmp данные файлы удаляются и возникает вышеописанная ситуация. Решений здесь несколько:

  • если используется apache 2.4, тогда возможно через переменную Mutex задать другой режим блокировки, не через "файлы";
  • вручную, при сборке модуля mod_fcigd, задать в файле fcgid_mutex_unix.c режим блокировки по умолчанию (см. строку apr_lockmech_e mechanism = APR_LOCK_DEFAULT;);
  • ну и банально — отключить автоматическую чистку директории /tmp.

После настройки апача, еще нужно создать иерархию директорий для работы сайта в домашней папке пользователя. Создадим пользователя и группу  chihpih, домашняя папка у него будет /home/chihpih с правами 0750. Чтобы апач мог получить к этой директории доступ нужно добавить пользователя www в группу пользователя или можно воспользоваться ACL,ками, как сделал я.

Создаем необходимые папки в домашней директории и даем необходимые права пользователю www:

# cd /home/chihpih/data
# mkdir log tmp www php-bin
# chown www:www log
# chown chihpih:chihpih tmp www php-bin
# chmod 0755 log
# chmod 0750 tmp php-bin
# chmod 0751 www

# setfacl -m u:www:x /home/chihpih
# setfacl -m u:www:x /home/chihpih/data
# setfacl -m u:www:rx /home/chihpih/data/php-bin
# setfacl -m u::rwx,g::rx,o::---,u:www:rx /home/chihpih/data/www
# setfacl -d -m u::rwx,g::rx,o::---,u:www:rx /home/chihpih/data/www

В папке log будут храниться логи виртуальных хостов, в tmp временные файлы для php, в php-bin скрипт и конфиг для php, а в www сами сайты. В папку php-bin нужно положить конфиг php.ini, и создать скрипт php.sh следующего содержания:

#!/bin/sh

# Для модуля mod_fastcgi можно задать следующие переменные окружения
# (для mod_fcgi первую из двух задавать нельзя)
#PHP_FCGI_CHILDREN=4
#export PHP_FCGI_CHILDREN
#PHP_FCGI_MAX_REQUESTS=300
#export PHP_FCGI_MAX_REQUESTS

exec nice -n 20 /usr/local/bin/php-cgi -c "/home/chihpih/data/php-bin/php.ini"

Так же надо дать скрипту права на запуск. Оба файла должны принадлежать пользователю, но чтобы он не смог их изменить, нужно установить дополнительные атрибуты на эти файлы.

# chflags schg,sunlink php.ini
# chflags schg,sunlink php.sh

Для автоматизации данного процесса я написал скрипт, который делает вышеописанные действия. То есть ему нужно передать имя пользователя, имя хоста, алиасы хоста и почту админа хоста, а далее он по шаблонам сделает конфигурационные файлы и запишет их куда необходимо. Останется только сделать мелкие правки, если они необходимы, и перезапустить апач.

#!/bin/sh

# Директория, в которой лежат домашние папки пользователей
ROOT_DIR="/usr/home"
# Директория, в которой лежат конфиги виртуальных хостов
AVH_DIR="/usr/local/etc/apache22/Includes"
HS_DIR="/usr/share/skel"
# Шаблон виртуального хоста
AVH_TEMPLATE="/root/hosting/webuser/vh.template"
# Шаблон конфига PHP
PHP_INI_TEMPLATE="/root/hosting/webuser/php.ini.template"
# Шаблон скрипта
PHP_SH_TEMPLATE="/root/hosting/webuser/php.sh.template"

# INFO: Пользователь создается с классом web_user32, измените его на свой.

if [ ! -d $ROOT_DIR ]; then
    echo "Bad path to root home directroy"
    exit 1
fi

if [ ! -d $AVH_DIR ]; then
    echo "Bad path to apache directroy"
    exit 1    
fi

if [ ! -d $HS_DIR ]; then
    echo "Bad path to skel directory"
    exit 1    
fi

if [ ! -f $AVH_TEMPLATE -o \
     ! -f $PHP_INI_TEMPLATE -o \
     ! -f $PHP_SH_TEMPLATE ];
then
    echo "Bad path to template files"
    exit 1
fi

user_create()
{
    local res=0
    local user_name="$1"

    if [ `cat /etc/master.passwd | grep $user_name` ]; then
        echo "User already exists"
        return 1
    fi

    pw groupadd $user_name
    if [ $? -ne 0 ]; then $res=$?; fi

    pw useradd $user_name \
              -g $user_name \
              -d "$ROOT_DIR/$user_name/data" \
              -L web_user32 \
               -s csh
    if [ $? -ne 0 ]; then $res=$?; fi

    if [ $res -ne 0 ]; then
        echo "Can't create user and group"
        return 1
    fi

    return 0
}

user_create_home_skel()
{
    local res=0
    local user_name="$1"

    mkdir -p "$ROOT_DIR/$user_name/data/php-bin"
    if [ $? -ne 0 ]; then $res=$?; fi
    mkdir -p "$ROOT_DIR/$user_name/data/log"
    if [ $? -ne 0 ]; then $res=$?; fi
    mkdir -p "$ROOT_DIR/$user_name/data/tmp"
    if [ $? -ne 0 ]; then $res=$?; fi
    mkdir -p "$ROOT_DIR/$user_name/data/www"
    if [ $? -ne 0 ]; then $res=$?; fi

    if [ $res -ne 0 ]; then
        echo "Can't create home directory"
        if [ -d "$ROOT_DIR/$user_name" ]; then
            rm -rf "$ROOT_DIR/$user_name"
        fi

        return 1
    else
        for file in `ls $HS_DIR`; do
            local new_name=`echo $file | sed -E 's/dot\.(.+)/.\2/gI'`
            cp "$HS_DIR/$file" "$ROOT_DIR/$user_name/$new_name"
        done
    fi

    return 0
}

user_create_config()
{
    local user_name="$1"
    local user_mail="$2"
    local host_name="$3"
    local host_aliases="$4"

    sed -e "s/\$user/$user_name/g" \
            $PHP_INI_TEMPLATE > "$ROOT_DIR/$user_name/data/php-bin/php.ini"
    if [ $? -ne 0 ]; then
        echo "Can't create php.ini config file"
        return 1
    fi

    sed -e "s/\$user/$user_name/g" \
            $PHP_SH_TEMPLATE > "$ROOT_DIR/$user_name/data/php-bin/php.sh"
    if [ $? -ne 0 ]; then
        echo "Can't create php.sh script file"
        return 1
    fi

    sed -e "s/\$user/$user_name/g" \
            -e "s/\$mail/$user_mail/g" \
            -e "s/\$host/$host_name/g" \
            -e "s/\$aliases/$host_aliases/g" \
            $AVH_TEMPLATE > "$AVH_DIR/$host_name.conf"
    if [ $? -ne 0 ]; then
        echo "Can't create virtual host config file"
        return 1
    fi

    return 0
}

user_set_permissions()
{
    local user_name="$1"

    chown -R $user_name:$user_name "$ROOT_DIR/$user_name"
    chmod 0750 "$ROOT_DIR/$user_name"
    find "$ROOT_DIR/$user_name/" -type d -exec chmod 0750 {} \;
    chown www:www "$ROOT_DIR/$user_name/data/log"
    chmod 0755 "$ROOT_DIR/$user_name/data/log"

    setfacl -m u:www:x "$ROOT_DIR/$user_name"
    setfacl -m u:www:x "$ROOT_DIR/$user_name/data"
    setfacl -m u:www:rx "$ROOT_DIR/$user_name/data/php-bin"
    setfacl -m u::rwx,g::rx,o::---,u:www:rx "$ROOT_DIR/$user_name/data/www"
    setfacl -d -m u::rwx,g::rx,o::---,u:www:rx "$ROOT_DIR/$user_name/data/www"

    chmod 0440 "$ROOT_DIR/$user_name/data/php-bin/php.ini"
    chmod 0550 "$ROOT_DIR/$user_name/data/php-bin/php.sh"
    chflags schg,sunlink "$ROOT_DIR/$user_name/data/php-bin/php.ini"
    chflags schg,sunlink "$ROOT_DIR/$user_name/data/php-bin/php.sh"

    return 0
}

read -p "Username: " user_name
read -p "Admin mail: " user_mail
read -p "Hostname: " host_name
read -p "Host aliases: " host_aliases

if [ ! $user_name ] || [ ! $user_mail ] || [ ! $host_name ] || [ ! "$host_aliases" ]; then
    echo "Please enter correct data"
    exit 1
fi

user_create_home_skel $user_name
if [ $? -ne 0 ]; then
    echo "error: user_create_home_skel"
    exit 1
fi

user_create $user_name
if [ $? -ne 0 ]; then
    echo "error: user_create"
    exit 1
fi

user_create_config $user_name $user_mail $host_name "$host_aliases"
if [ $? -ne 0 ]; then
    echo "error: user_create_config"
    exit 1
fi

user_set_permissions $user_name
if [ $? -ne 0 ]; then
    echo "error: user_ser_permissions"
    exit 1
fi

exit 0

В конце статьи я прикрепил архив со всеми необходимыми файлами для работы. Теперь можно добавить апач в автозагрузку и запустить его:

# echo 'apache2_enable="YES"' >> /etc/rc.conf
# /usr/local/etc/rc.d/apache2 start

Проверяем запустился ли апач:

# sockstat -4 -l | grep httpd
www      httpd      52253 21 tcp4   192.168.7.253:80      *:*
www      httpd      52252 21 tcp4   192.168.7.253:80      *:*
www      httpd      50181 21 tcp4   192.168.7.253:80      *:*
www      httpd      50059 21 tcp4   192.168.7.253:80      *:*
www      httpd      50058 21 tcp4   192.168.7.253:80      *:*
www      httpd      50057 21 tcp4   192.168.7.253:80      *:*
root     httpd      20124 21 tcp4   192.168.7.253:80      *:*

Так же посмотрим, работает ли модуль fastcgi:

# ps -ax | grep php-cgi
71576  ??  INJ    0:06,17 /usr/local/bin/php-cgi -c /home/xan/php-bin/php.ini
71579  ??  INJ    0:44,67 /usr/local/bin/php-cgi -c /home/chihpih/data/php-bin/php.ini

Если вы видите на экране что-то подобное, значит - все работает нормально. Если же нет, то смотрите логи и проверяйте конфиг.

Прикрепленные файлы
Гость (не проверено)

FcgidFixPathinfo - должно быть 1, если в php.ini параметр cgi.fix_pathinfo выставлен в 1

Лол. Если у тебя хоть на одном серваке пых с такой опцией как fastcgi то считай тебя похекали.



 

nekit

Что же вы тогда свои слова не подкрепили ссылкой на авторитетный ресурс, что это является потенциальной уязвимостью?

Гость (не проверено)

I really enjoy good vintage wine. From a local


vineyard or imported, it’s thee perfect way tto relax.


Who else enjoys wine tasting? #WhiteWine





Here is mmy site; ร้านขายไวน์ - http://jinos.com/bbs/board.php?bo_table=free&wr_id=4441057

Гость (не проверено)

I really enjoy good vintage wine. Whether it's red or white, it juet elevates any occasion. Who else enjoy wine tasting?


#RedWine





Also visit my site ไวน์ราคาถูก - https://Www.Fairviewumc.church/bbs/board.php?bo_table=free&wr_id=960987

Добавить комментарий

CAPTCHA
Этот вопрос задается для того, чтобы выяснить, являетесь ли Вы человеком или представляете из себя автоматическую спам-рассылку.

Последние комментарии

Яндекс.Метрика