Заметки по созданию хостинга на базе панели ISP Control

Материал из Linux Wiki
Перейти к: навигация, поиск

Бэкап

Использование многопоточной архивации на SMP

Для улучшения использования многоядерных процессоров есть смысл поставить pbzip2. Для его использования в /etc/ispcp/ispcp.conf изменить параметр ZIP на bzip2, а CMD_BZIP на

CMD_BZIP = /usr/bin/pbzip2

это затронет архивирование баз данных (как для доменов, так и для самой панели). Для многопоточной архивации контента придется немного изменить скрипт /var/www/ispcp/engine/backup/ispcp-backup-all, 297-я строка - надо сжатие напрямую через tar сменить на внешнюю команду. Скрипт в этом месте выглядит так (закомментированный старый и новый вариант):

#$backup_cmd = "$cmd_tar --create --directory=$dmn_dir --$zip --file=$www_dir/$backup_filename --exclude=logs --exclude=phptmp --exclude=backups . 2> $www_dir/$backup_filename.log";
$backup_cmd = "$cmd_tar --create --directory=$dmn_dir --exclude=logs --exclude=phptmp --exclude=backups . 2> $www_dir/$backup_filename.log | pbzip2 -9c > $www_dir/$backup_filename";

Как (более правильный) вариант - переделать скрипт, добавив новый тип сжатия - pbzip2, обрабатывающийся по тем же правилам, что и обычный bzip2, тогда в правке выше можно использовать переменную $zip.

Править ispcp-backup-ispcp, думаю, нет смысла, ибо база данных и так обрабатывается pbzip2'ом, а сжатие конфигов не настолько ресурсоемко, чтобы ради этого переделывать скрипт

Еще один вариант - использовать многопоточную версию gzip - pigz. Этот вариант может быть более предпочтителен, так как будет меньше нагружать процессор (веб-контент все равно большей частью картинки, их сжимать нет смысла). Очевидно, что возможно использовать и смешанный вариант - для баз использовать pbzip2, а скрипт бэкапа доменов переделать под использование pigz.

Конфиги

Настройки PHP

  • /etc/ispcp/fcgi/parts/php5/php.ini - тут находятся дефолтные настройки PHP (а рядом и другие дефолтные файлы), которые копируются юзеру при создании домена.

/etc/ispcp/fcgi/parts/master/php5/php.ini - аналогично, но для самой панели.

Warning.png Внимание: при запуске скрипта обновления панели все пользовательские php.ini-файлы перезаписываются вышеуказанными
  • Настройки аплоада файлов: в php.ini для нужного домена (в частности для phpmyadmin, net2ftp):
# лимит для выполнения скриптов
memory_limit = 64M
post_max_size = 64M
# лимит для аплоада файлов
upload_max_filesize = 64M

Кроме того, в /etc/apache2/mods-enabled/fcgid_ispcp.conf/etc/ispcp/apache/working/fcgid_ispcp.conf) изменить (добавить) параметр MaxRequestLen:

MaxRequestLen 64000000

Без него может появляться 500-я ошибка при аплоаде больших файлов (в частности дампов баз в phpmyadmin), ошибку можно отловить в error_log сервера.

  • Есть смысл поднять max_execution_time хотя бы до 45 секунд - протестировано JabberWorld'ом на незагруженном процессоре Athlon II x4 на 2.8 ГГц страницей со списком серверов - она генерировалась порядка 33-35 секунд. Случай крайний, но для статистики сойдет
  • Настройки phpmyadmin: в некоторых случаях (а именно при больших запросах в phpmyadmin, например, поиске значения по всем таблицам (с длинными именами) большой базы и последующим выводом значения) suhosin-патч может ругаться на превышение максимальной длины переменной в GET-запросе:
Aug 30 18:20:44 nightwolf suhosin[28127]: ALERT - configured GET variable value length limit exceeded - dropped variable 'sql_query' (attacker '46.33.236.249', file '/service/webspace/phpmyadmin.linuxoid.in/htdocs/sql.php')

Дефолтно длина переменной равна 512 символам, дефолт задается в /etc/php5/conf.d/suhosin.ini и, в принципе, в обычных случаях (но не в этом) этого достаточно. Если настроен fail2ban на отлов подобных сообщений, то после выполнения такого запроса клиент будет забанен. Чтобы этого не случилось, необходимо поправить (добавить) переменную suhosin.get.max_value_length в php.ini и присвоить ей значение повыше (например, 4-8 Кб. Для обычного WordPress'a легко получались значения в 2,5 Кбайт и это далеко не предел). Думаю, для большей секьюрности изменить эту переменную стоит только в php.ini-файле phpmyadmin'a (который в свою очередь вынести на отдельный домен). В итоге изменения сводятся к добавлению в конец этого файла следующей секции (в примере задано значение 32 Кбайта):

[suhosin]
suhosin.get.max_value_length = 32768
Warning.png Не стоит забывать, что при запуске скрипта обновления панели php-файлы будут перезаписаны, поэтому значение придется добавить заново

Ссылки: [1], [2]

  • Еще, думаю, на нагруженных серверах есть смысл снизить значение переменной PHP_FCGI_CHILDREN в файлах /var/www/fcgi/домен (можно как для одного "некритичного" домена, так и для всех сразу - не забываем поправить шаблон) с дефолтного значения 2 до 1. Идея в том, что малозагруженный сайт "отхватит" себе основной процесс php c двумя потомками, хотя ему, может быть, достаточно и одного, а высоконагруженный может испытывать недостаток в обработчиках php. В случае глобального изменения (или изменения числа потомков для большинства доменов) необходимо также поправить параметр MaxProcessCount в файле /etc/apache2/mods-enabled/fcgid_ispcp.conf - соответственно, увеличив его в 2 раза.

Скрытие версий серверов

Апач
/etc/apache2/conf.d/security
ServerTokens Prod
ServerSignature Off
proftpd
/etc/proftpd/proftpd.conf
ServerIdent                on "любая строка"

При просто "on" отдается внутренний IP-адрес и имя сервера. При off - только адрес. Чтобы убрать все, надо вставить свой идентификатор по примеру выше.

Включение AWStats

У AWStats (напомню, это софт для построения статистики посещений по логам веб-сервера) в панели есть 2 режима работы: static и dynamic, переключение производится сменой параметра AWSTATS_MODE в /etc/ispcp/ispcp.conf. В чем разница:

Dynamic-mode
  • Включается дополнительный модуль в Apache - http_proxy
  • Добавляется еще один виртуальный хост в Апачe, слушающий localhost
  • Для каждого домена добавляется запись, проксирующая запросы с каталога /stats домена через этот виртуальный хост.
  • Дефолтно запросы обрабатываются только после прохождения авторизации. Пользователи/пароли настраиваются из "Веб-инструментов" в панели
  • В итоге запросы обрабатываются напрямую Perl-скриптом awstats.pl, выполняющимся с привилегиями www-data.
  • В cron'e для обновления статистики создается запись, обрабатывающая пакетно все домены.
  • awstats.pl, вызываемый браузером, в реальном времени рисует и отдает статистику по данным, сгенерированным на бэкграунде (см. строчку про крон выше)
  • Обновление базы делается раз в 6 часов
  • Преимущество 1: обновление базы забирает очень мало ресурсов и делается достаточно быстро.
  • Преимущество 2: можно просматривать статистику за любой период
  • Недостаток 1: awstats.pl после авторизации пользователя может получить доступ к другим файлам статистики, которые лежат рядом, путем подстановки в адресной строке нужного домена, минуя авторизацию целевого домена.
  • Недостаток 2: при нахождении уязвимости в awstats.pl (и наличии своего домена на хостинге для прохождения авторизации) взломщик получит на сервере шелл с правами www-data (а, следовательно, с доступом ко всем доменам)
Static-mode
  • Для каждого домена в домашнем каталоге пользователя создается дополнительный каталог statistics
  • В конфиге виртуалхоста в Апаче делается простой редирект на этот каталог
  • Для каждого домена в /etc/cron.d/ispcp добавляется запись, вызывающая скрипт обновления статистики в /var/cache/awstats/ и генерации HTML-файлов, которые складируются в каталоге домена statistics
  • Обновление статистики для домена делается раз в день.
  • Преимущество 1: Никаких скриптов, с которыми работает пользователь. Браузеру отдается чистая статика
  • Преимущество 2: Никаких дополнительных модулей для Апача
  • Преимущество 3: Никаких дополнительных виртуалхостов
  • Преимущество 4: Чужие пользователи хостинга не имеют доступа к статистике
  • Недостаток 1: Интерфейс статистики на данный момент не позволяет просматривать статистику за прошедшие месяцы
  • Недостаток 2: Немного большее потребление ресурсов (для генерации HTML-страниц)

Чем делается статистика: взгляд изнутри на настройку dynamic-mode

При необходимости включить отключенный дефолтно awstats необходимо проделать следующее:

  • Собственно, поставить пакет awstats:
apt-get install awstats
  • В /etc/awstats/ удалить дефолтный конфиг awstats.conf (или переместить его под другое имя, например, awstats.conf.disabled)
  • В /etc/cron.d/ispcp (а также поправить файлы в /etc/ispcp/cron.d/, в частности шаблон и рабочую копию в каталоге /working/ - не знаю, надо ли - в какое время они могут перезаписывать рабочие? - но лучше сделать) раскомментировать строку для запуска обслуживающих AWStats скриптов каждые 6 часов
  • Удалить /etc/cron.d/awstats, теперь его работа делается в файле ispcp (см. выше)
  • В Apache включить модуль proxy_http, он потянет за собой модуль proxy
    • Для proxy закомментировать все параметры в /etc/apache2/mods-available/proxy.conf
  • Создать файл /etc/apache2/sites-available/01_awstats.conf, который должен генерироваться из темплейта /etc/ispcp/apache/01_awstats.conf (правки нужны минимальные)
    • Включить сайт 01_awstats.conf
  • В /etc/ispcp/ispcp.conf включить работу awstats:
AWSTATS_ACTIVE = yes

после этого в хостинг-панели в "Веб-инструментах" появится дополнительный пункт. Панель после этого начнет создавать awstats-конфиги и прописывать соответствующие записи в конфиг Апача для вновь создаваемых доменов. Для уже существующих придется это сделать вручную.

  • Не забыть перезапустить Апач, чтобы изменения вступили в силу

Включение статистики

Как уже было написано ранее, для static-mode в кронтаб для каждого домена добавляется запись. Темплейты записей можно найти в файлах

/etc/ispcp/cron.d/parts/dmn_awstats_entry.tpl
/etc/ispcp/cron.d/parts/als_awstats_entry.tpl

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

{MINUTE} {HOUR}  * * *   root umask 022 ; nice -n 19 perl {AWSTATS_ROOT_DIR}/awstats_buildstaticpages.pl -config={DMN_NAME} -update -lang={USER_LANG} -awstatsprog={AWSTATS_ENGINE_DIR}/awstats.pl -dir={APACHE_WWW_DIR}/{DMN_NAME}/statistics/ >/dev/null 2>&1 ; chown  -R --reference={APACHE_WWW_DIR}/{DMN_NAME}/ {APACHE_WWW_DIR}/{DMN_NAME}/statistics/

{MINUTE}        0       1       *       *       root umask 022 ; mkdir -p {APACHE_WWW_DIR}/{DMN_NAME}/statistics/$(date -d "-1 month" +\%Y/\%m) ; nice -n 19 perl {AWSTATS_ROOT_DIR}/awstats_buildstaticpages.pl -config={DMN_NAME} -update $(date -d "-1 month" +"-year="\%Y" -month="\%m) -lang={USER_LANG} -awstatsprog={AWSTATS_ENGINE_DIR}/awstats.pl -dir={APACHE_WWW_DIR}/{DMN_NAME}/statistics/$(date -d "-1 month" +\%Y/\%m) >/dev/null 2>&1 ; chown  -R --reference={APACHE_WWW_DIR}/{DMN_NAME}/ {APACHE_WWW_DIR}/{DMN_NAME}/statistics/

для домена и

{MINUTE} {HOUR}  * * *   root umask 022 ; nice -n 19 perl {AWSTATS_ROOT_DIR}/awstats_buildstaticpages.pl -config={ALS_NAME} -update -lang={USER_LANG} -awstatsprog={AWSTATS_ENGINE_DIR}/awstats.pl -dir={APACHE_WWW_DIR}/{ALS_PATH}/statistics/ >/dev/null 2>&1 ; chown  -R --reference={APACHE_WWW_DIR}/{ALS_PATH}/ {APACHE_WWW_DIR}/{ALS_PATH}/statistics/

{MINUTE}        0       1       *       *       root umask 022 ; mkdir -p {APACHE_WWW_DIR}/{ALS_PATH}/statistics/$(date -d "-1 month" +\%Y/\%m) ; nice -n 19 perl {AWSTATS_ROOT_DIR}/awstats_buildstaticpages.pl -config={ALS_NAME} -update $(date -d "-1 month" +"-year="\%Y" -month="\%m) -lang={USER_LANG} -awstatsprog={AWSTATS_ENGINE_DIR}/awstats.pl -dir={APACHE_WWW_DIR}/{ALS_PATH}/statistics/$(date -d "-1 month" +\%Y/\%m) >/dev/null 2>&1 ; chown  -R --reference={APACHE_WWW_DIR}/{ALS_PATH}/ {APACHE_WWW_DIR}/{ALS_PATH}/statistics/

для алиаса. Что изменилось - добавил umask 022 для файлов (вообще оказалось не нужно, просто осталось от предыдущих экспериментов) и добавил chown создаваемых файлов на тот, который у домашнего каталога пользователя. Кроме того, добавил записи, создающие в каталоге statistics домена подкаталоги для отчетов за прошедшие месяцы (Неплохо было бы еще генерировать страничку со ссылками на подкаталоги вместо унылого directory listing'a)

После всех необходимых правок включаем в файле настроек панели /etc/ispcp/ispcp.conf статистику путем изменения параметра AWSTATS_ACTIVE на yes (а также выбираем режим построения графиков - как уже условились, статический является более секьюрным, поэтому ставим единичку в нужном месте), запускаем файл обновления панели, он перегенерирует конфиги Апача и добавит в них записи для awstats в соответствии с выбранным режимом, а также обновит crontab.

Настройки AWStats

  • В конфигах (и темплейте /etc/ispcp/awstats/awstats.ispcp_tpl.conf) для динамического режима есть смысл поправить параметр ErrorMessages= для того, чтобы в случае какой-либо ошибки скрывать местоположение конфигов и заменять текст на одинаковое сообщение.

Ссылки

Обновление конфигов панели

Для обновления конфигов предназначен специальный скрипт ispcp-update. Для его работы сначала скопируйте конфиг-файл панели под именем /etc/ispcp/ispcp.old.conf (может скрипт может работать и с текущей версией (но ее придется указать руками), но не грохнет ли он ее - не проверял). Для запуска скрипта необходимо перейти в каталог /var/www/ispcp/engine/setup/. Скрипт сделает бэкап и перегенерирует конфиги сервисов в соответствии с настройками панели, используя содержимое темплейтов (поэтому при глобальном изменении какого-либо параметра необходимо делать его не только в текущей и рабочей копии, а и в темплейтах - как раз на такой случай)

ProFTPd

В дефолтный конфиг рекомендуется добавить

RLimitCPU                       session 600 600
RLimitMemory                    64M 64M
RLimitOpenFiles                 1024 1024

для ограничения максимального времени выполнения дочерних процессов (на случай подвисания или еще чего-то процессоропожирающего) - используется только session, ибо если применять ко всему - в долговременной перспективе есть вероятность снятия демона, дочерний же процесс при превышении лимита будет демоном перезапущен; размера памяти, занимаемого процессом или демоном (параметр не накопительный, поэтому в идеале демон его никогда не достигнет; однако может помочь в случае подвисания/атаки/etc) и максимального числа открытых файлов на каждый процесс

Права доступа

  • Включаем Апач в группу каждого создаваемого домена. Это позволит ставить на файлы и каталоги более секьюрные права - вплоть до 400 на скрипты и 440 на обычный html. Для этого надо поправить скрипт /var/www/ispcp/engine/ispcp_common_methods.pl на строке 2275:
# Добавляем Апач в группу домена
$cmd = "/usr/sbin/usermod -a -G $sys_group www-data";
sys_command($cmd);

Внимание: в разных системах существуют разные ограничения на количество групп, в которые может входить пользователь. В BSD это вроде как 16 (соответственно, для более-менее крупного хостинга такой способ неприменим), в современном Linux'e дефолтно это 65536 (и вроде как может быть легко увеличен при необходимости).

После этих изменений можно поправить Umask аплоада файлов в proftpd.conf с

Umask 022 022

на

Umask 027 027

а также поменять права и группы создаваемых файлов и каталогов в /var/www/ispcp/engine/ispcp-{als,dmn,sub}-mngr - можно безболезненно ставить права 0640 для файлов и 0750 для каталогов, а также сменить группу на $sys_group с $httpd_gid. Примерно так:

/var/www/ispcp/engine# diff  ispcp-dmn-mngr ../engine-bak/ispcp-dmn-mngr | grep '^<'
<                               "$www_dir/$dmn_name/statistics", $sys_user, $sys_group, 0750
<       $rs = make_dir("$www_dir/$dmn_name", $sys_user, $sys_group, 0750);
<       $rs = make_dir("$www_dir/$dmn_name/cgi-bin", $sys_user, $sys_group, 0750);
<       $rs = make_dir("$www_dir/$dmn_name/logs", $sys_user, $sys_group, 0750);
<       $rs = make_dir("$www_dir/$dmn_name/phptmp", $sys_user, $sys_group, 0770);
<       $rs = make_dir("$www_dir/$dmn_name/errors", $sys_user, $sys_group, 0750);
<       $rs = make_dir("$www_dir/$dmn_name/errors/inc", $sys_user, $sys_group, 0750);
<               "$www_dir/$dmn_name/.htpasswd", "\n", $sys_user, $sys_group, 0640
<               "$www_dir/$dmn_name/.htgroup", "\n", $sys_user, $sys_group, 0640
<                               0640
<                       "$www_dir/$dmn_name/errors/inc/$_", $sys_user, $sys_group, 0640
<                       "$www_dir/$dmn_name/htdocs", $sys_user, $sys_group, 0750
<                       0640
<                       "$www_dir/$dmn_name/htdocs/images", $sys_user, $sys_group, 0750
<                               0640
<               $rs = make_dir("$www_dir/$dmn_name/errors", $sys_user, $sys_group, 0750);
<                       "$www_dir/$dmn_name/errors/inc", $sys_user, $sys_group, 0750

  • При аплоаде файлов через FTP-клиент могут возникать случаи, когда права на файлы выставляются не такие, как указаны в конфиге proftpd.conf (параметр Umask 022 022). Проблема в FTP-клиенте, который пытается сохранить на сайте те же unix'овые права, что и в файловой системе. Лучше сменить FTP-клиент, чем запрещать SITE_CHMOD.

Недоработки

  • При вынесении FTP-сервера на отдельный хост может возникнуть проблема с тем, что при создании FTP-аккаунта в панели нельзя выбрать произвольный каталог - возникает ошибка "Невозможно сменить каталог, обратитесь к администратору" при нажатии кнопки-ссылки "Выбрать каталог". Проблема в том, что панель для данного запроса создает временного FTP-пользователя, который подключается к системе и получает содержимое домашнего каталога, после чего строит виртуальную файловую систему. При этом в скрипте создания этой файловой системы жестко забито подключение к localhost. Поэтому при вынесении FTP-сервера на другой хост следует в файле /var/www/ispcp/gui/include/ispCP/VirtualFileSystem.php найти строки
// 'localhost' for testing purposes. I have to study if a better
// $this->_domain would work on all situations
$this->_handle = @ftp_connect('localhost');

и вписать вместо localhost нужный IP-адрес или домен.

  • Дефолтно файлы данных awstats создаются с правами root:root 640, соответственно, веб-сервер не имеет к ним доступа. Для исправления этого надо в /etc/cron.d/ispcp (а также в рабочей копии и в шаблоне) после слова root добавить umask 022 ;
ToDo: Подумать насчет лучшего распределения прав

Кроме того, в варианте со статическими страницами они тоже создаются с правами root:root 640. Можно использовать вариант с umask выше, но лучше добавить в шаблон (и в кронтабы) строчку с chmod по образцу, показанному в разделе "Включение статистики" этой статьи.

  • После удаления домена остается его конфиг для awstats. Соответственно, если создать over9000 доменов, какое-то время попользоваться, а потом удалить - конфиги все равно останутся, соответственно, будет перегенерироваться html-статистика, что будет зря грузить проц.
  • В темплейте тела конфига Апача для статического режима Awstats для алиаса пропущена ссылка на каталог иконок, из-за этого в статистике алиаса графики не отображаются. Чтобы это поправить, необходимо в файле /etc/ispcp/apache/parts/als_awstats_static_entry.tpl добавить первой строкой запись
    Alias /awstatsicons         "{AWSTATS_WEB_DIR}/icon/"

Для уже созданных доменов ситуацию без запуска скрипта обновления конфигов панели можно исправить следующим образом: в файлах /etc/ispcp/apache/working/ispcp.conf и /etc/apache2/sites-available/ispcp.conf добавляем в начало секции "httpd awstats support BEGIN" запись

    Alias /awstatsicons         "/usr/share/awstats/icon/"

после чего перезапускаем Апач командой apache2ctl graceful

  • В /var/www/ispcp/gui/domain_default_page/index.html бага - для алиаса на дефолтной страничке делается ссылка вида http://alias/{BASE_SERVER_VHOST_PREFIX}panel_url (причем, только для алиаса, для обычного домена нормально). Правится удалением BASE_SERVER_VHOST_PREFIX и заменой его на http://


  • В темплейтах интерфейса - ошибка, часть status_icon'ов обозначена словом, а часть - именем файла, при этом в темплейте жестко задано расширение. Как следствие - иконка релоада (и, по-идее, ошибки) не показываются (лечится приведением имен к чему-то одному - или добавлением .png в объявлении переменной и убирании .png в темплейте (больше правок), или, что проще, убиранием .png в релоаде и эррорах при объявлении переменной в php-файлах):
  • В /etc/cron.d/ispcp для chkrootkit сделано перенаправление вида &>:
0       */12    *       *       *       root /usr/sbin/chkrootkit &> /var/log/chkrootkit.log
похоже, cron воспринимает это как отправку процесса в фон, в итоге в лог ничего не попадает. Лечится удалением "&" (не забываем поправить темплейт /etc/ispcp/cron.d/ispcp и рабочую копию /etc/ispcp/cron.d/working/ispcp)
  • В тех же файлах для rkhunter'a есть запись, но непонятно зачем создаются 2 лог-файла с полностью одинаковым содержимым. В итоге привел запись к такому виду:
{RK-ENABLED}0   */12    *       *       *       root {RKHUNTER} --cronjob -l {RKHUNTER_LOG} && chown vu2000:vu2000 /var/log/rkhunter.log
0       */12    *       *       *       root /usr/bin/rkhunter --cronjob -l /var/log/rkhunter.log && chown vu2000:vu2000 /var/log/rkhunter.log

Первое для шаблона, второе - рабочая копия и рабочий конфиг. chown для обхода проблемы с правами.

Особенности настройки

PHP

  • Дефолтно в PHP отключен ряд функций, в частности
disable_functions = show_source, system, shell_exec, passthru, exec, phpinfo, shell, symlink, popen, proc_open

(иначе говоря, не пугаться, когда в файлике с phpinfo () будет белый экран)

ToDo: Расширить список функций по результатам аналогичных изменений на работе

Просто мысли

База данных и phpmyadmin

  • Потенциально для MySQL-сервера можно включить опцию skip-show-database, которая отключает для пользователей вывод списка доступных баз, что может быть полезно в плане безопасности - получив параметры подключения к одной базе, злоумышленник не знает про остальные, хотя доступ к ним и есть. Однако в таком случае phpmyadmin тоже не может получить спискок баз, соответственно, после авторизации выдает, что базы отсутствуют. Для этих целей заводится специальный пользователь, имеющий readonly-доступ к некоторым таблицам базы mysql (соответственно, имеющий доступ к списку всех баз сервера). Что является бОльшим злом - возможное получение списка баз одного пользователя при взломе сайта или получение списка всех баз при последующем возможном взломе PHPMyAdmin (который славится дырявостью) - выбирать вам.
    Еще один недостаток варианта с включенным skip-show-database - пользователь не может иметь собственного PHPMyAdmin'а на сайте (хотя это и не надо, пусть пользуется обновляемым системным)
  • ToDo: Сделать прозрачную авторизацию в PHPMyAdmin (без дополнительных юзеров?)

/var/www/ispcp/gui/client/pma_auth.php - захардкодил путь к phpmyadmin (чтобы сразу редиректило на главную страничку без попыток авторизации (см. ToDo выше), а не вешало панель с Апачем)

Апач

  • Логи в Апаче обрабатываются через скрипт /var/www/ispcp/engine/ispcp-apache-logger - в конфиге есть единственное обращение к этому скрипту для всех доменов одновременно, логи пайпаются на него, а он раскидывает записи в 4 разных файла для каждого домена отдельно (/var/log/apache2/*{combined,traf}* и access с error.log'ом в подкаталоге users там же). При большом количестве запросов начинает ощутимо грузить процессор. Что мешало в темплейте домена забить записи для каждого домена через стандартные директивы Апача (так, чтобы он напрямую занимался логами) - непонятно. Потенциально этот момент можно доработать, добавив в темплейт записи вида
CustomLog /var/log/apache2/{DMN_NAME}-combined.log combined # Общий лог. Проверить, что combined в конфиге задан и он NCSA extended/combined log format
CustomLog /var/log/apache2/users/{DMN_NAME}-access.log combined # Еще один лог, идентичен предыдущему. Реально различался несколькими записями за время logrotate'a. Зачем нужен - хз.
ErrorLog /var/log/apache2/users/{DMN_NAME}-error.log # Лог ошибок домена
CustomLog /var/log/apache2/{DMN_NAME}-traf.log "%I %O" # Лог трафика. Далее цифры должны суммироваться в скрипте обработки логов

Дополнено: Как показало ковыряние скрипта, первые 2 лога действительно идентичны, а в лог трафика падает суммарный объем переданных данных (лишнее поскипано):

$fh = cacheout '>>', "$main::cfg{'APACHE_LOG_DIR'}/$vhost-combined.log";
print $fh $_;

$fh = cacheout '>>', "$main::cfg{'APACHE_USERS_LOG_DIR'}/$vhost-access.log";
print $fh $_;

$fh = cacheout '>>', "$main::cfg{'APACHE_LOG_DIR'}/$vhost-traf.log";
print $fh $inBytes + $outBytes, "\n";
ToDo: Изучить, зачем нужно 2 одинаковых лога, можно ли от этого избавиться и изучить вариант отказа от дополнительного скрипта обработки логов
    • Лог в корне каталога используется, например, awstats:
$ grep ^LogFile /etc/awstats/awstats.linuxoid.in.conf 
LogFile="/var/log/apache2/linuxoid.in-combined.log"
    • /var/log/apache2/users/domain-access.log и /var/log/apache2/users/domain-error.log просто копируется юзеру в каталог logs
    • /var/log/apache2/domain-traf.log обрабатывается скриптом /var/www/ispcp/engine/traffic/ispcp-vrl-traff

Потенциально можно обойтись вообще двумя логами - access.log и error.log. Во-первых, что мешает копировать (или парсить awstats'ом) один и тот же лог, тем более, если они идентичны? Во-вторых, трафик можно брать из того же access.log, просто указывать для обработки в /var/www/ispcp/engine/traffic/ispcp-vrl-traff не 1-е поле, а 10-е, плюс как-то считать входящий трафик (?). Единственный плюс во втором случае - размер логов для парсинга, плюс отсутствие необходимости к логам стандартного формата прикручивать учет входящего трафика.

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

Разное

Назначение скриптов, механизмы работы функций

  • /etc/cron.d/ispcp:
    • /var/www/ispcp/engine/quota/ispcp-dsk-quota - скрипт для подсчета объема занимаемого пользователем дискового пространства и обновления значений в базе. Считается объем, занимаемый каталогами контента (исключая архивы бэкапов и логи), размер почтового ящика и размер базы данных, после чего данные заносятся в базу. Данные используются для вывода информации в панели управления и, например, FTP-сервером. Кроме того, FTP-сервер при загрузке файлов обновляет значения занимаемого места (т.е., в этом случае лимит вычисляется в реальном времени). На случай сбоя при обновлении значений занимаемого места FTP-сервером, эти значения будут перезаписаны данным скриптом, выполняющимся каждый день в 0 часов.
    • /var/www/ispcp/engine/traffic/ispcp-srv-traff - общий трафик, потребленный сервером, считается цепочками в iptables и этим скриптом сбрасывается в /var/log/ispcp/ispcp-iptables-input.log и /var/log/ispcp/ispcp-iptables-input.log, после чего им же парсится и данные заносятся в базу, таблица server_traffic. Результаты собираются каждый час в 0 и 30 минут и доступны в статистике у администратора. После сбора данных цепочки в iptables сбрасываются.
    • /var/www/ispcp/engine/traffic/ispcp-vrl-traff - трафик виртуальных серверов, строится по отношению к домену по данным из логов (domain-traf.log для веба; ftp_traff.log для FTP; smtp.log, smtp_delivery.log, imap.log, /pop3.log для почты - все в подкаталогах /var/log соответствующих сервисов. Для почты в коде отгрепываются значения localhost и 127.0.0.1 - может быть полезно при мультисерверности). Данные заносятся в базу в таблицу domain_traffic и доступны в статистике пользователя. Результаты собираются каждый час в 0 и 30 минут; также скрипт вызывается перед logrotate'ом.
    • /var/www/ispcp/engine/tools/ispcp-httpd-logs-mngr - скрипт занимается раскидыванием access.log и error.log в каталоги доменов/субдоменов/алиасов и назначением прав на логи. Выполняется каждый день в 0 часов. Скрипт не занимается удалением, перезапись обрабатывается через logrotate каждую неделю. Не теряется ли часть лога между копированием (в 0 часов) и перезаписью (в 6-24, ЕМНИП)?
    • /var/www/ispcp/engine/backup/ispcp-backup-all - скрипт бэкапа доменов (контента и баз, в зависимости от настроек). Доработка описывалась в 1-м разделе
    • /var/www/ispcp/engine/backup/ispcp-backup-ispcp - скрипт бэкапа конфигов панели и базы.
    • /var/www/ispcp/engine/tools/ispcp-del-logs.sh - скрипт, удаляющий логи Апача, которым больше года.
  • /var/www/ispcp/engine/ispcp-apache-logger - скрипт для работы с логами Апача. Генерирует логи access.log в корне каталога логов и подкаталоге users, а также *-traf.log в корне. С ключом -t error генерирует error.log для домена. Нужность под вопросом.

Потребление памяти веб-сервером

Максимальное потребление можно посчитать, исходя из

  • максимального количества процессов Апача
    • (параметр MaxClients в /etc/apache2/apache2.conf для prefork-варианта) из расчета примерно 3 Мб на процесс
  • максимального количества процессов php5-cgi
    • (параметр MaxProcessCount в файле /etc/apache2/mods-enabled/fcgid_ispcp.conf умноженный на
      • PHP_FCGI_CHILDREN - количество потомков для каждого процесса - дефолтно это 2 и задается в файле php5-fcgi-starter каталога /var/www/fcgi/домен - и умноженный на
    • лимит памяти для каждого скрипта - параметр memory_limit в php.ini)

Например, имея лимиты MaxClients = 100, MaxProcessCount = 35, дефолтные 2 потомка и memory_limit = 64M получаем максимальное потребление

100*3+35*2*64 = 4780 Мб

плюс не забываем учесть потребление прочих системных сервисов и небольшой запас для исключения ситуации OOM

Update: Расчет не вполне правильный, так как считается, что одним процессом обрабатывается один скрипт в одно время (cgi-вариант). На деле же одним процессом могут обрабатываться различные скрипты даже в пределах одного домена/пользователя (например, отдача контента через index.php и работа админа через веб-админку сайта через отдельный скрипт), т.о., "легкие" в процессорном плане, но емкие по потреблению памяти скрипты при высоких нагрузках могут свободно потратить всю доступную память (при этом процессы php5-cgi будут потреблять сотни Мб каждый). Поэтому единственным вариантом лимитирования памяти для предотвращения OOM на сервере является введение системных ограничений через ulimit или limits.conf

Случайно обнаруженный процесс-потомок php5-cgi при лимите в 64 Мб:

20533 vu2023    20   0  283m 134m 4912 S    0  3.3   3:22.86 /usr/bin/php5-cgi

Ссылки