Заметки по созданию хостинга на базе панели ISP Control
Бэкап
Использование многопоточной архивации на 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 - аналогично, но для самой панели.
Внимание: при запуске скрипта обновления панели все пользовательские 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
Не стоит забывать, что при запуске скрипта обновления панели php-файлы будут перезаписаны, поэтому значение придется добавить заново |
- Еще, думаю, на нагруженных серверах есть смысл снизить значение переменной 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/. Скрипт сделает бэкап и перегенерирует конфиги сервисов в соответствии с настройками панели, используя содержимое темплейтов (поэтому при глобальном изменении какого-либо параметра необходимо делать его не только в текущей и рабочей копии, а и в темплейтах - как раз на такой случай)
'/bin/cp -p /etc/cron.d/ispcp /etc/ispcp/cron.d/backup/ispcp.1312222596' '/bin/cp -fp /etc/ispcp/cron.d/working/ispcp /etc/cron.d/' '/bin/cp -p /etc/bind/named.conf /etc/ispcp/bind/backup/named.conf.1312222596' '/bin/cp -pf /etc/ispcp/bind/working/named.conf /etc/bind/named.conf' '/bin/cp -p /etc/apache2/mods-available/fastcgi_ispcp.conf /etc/ispcp/apache/backup/fastcgi_ispcp.conf.1312222596' '/bin/cp -p /etc/apache2/mods-available/fastcgi_ispcp.load /etc/ispcp/apache/backup/fastcgi_ispcp.load.1312222596' '/bin/cp -p /etc/apache2/mods-available/fcgid_ispcp.conf /etc/ispcp/apache/backup/fcgid_ispcp.conf.1312222596' '/bin/cp -p /etc/apache2/mods-available/fcgid_ispcp.load /etc/ispcp/apache/backup/fcgid_ispcp.load.1312222596' '/bin/cp -pf /etc/ispcp/apache/working/fastcgi_ispcp.conf /etc/apache2/mods-available/' '/bin/cp -pf /etc/ispcp/apache/working/fcgid_ispcp.conf /etc/apache2/mods-available/' '/bin/cp -pf /etc/ispcp/apache/working/fastcgi_ispcp.load /etc/apache2/mods-available/' '/bin/cp -pf /etc/ispcp/apache/working/fcgid_ispcp.load /etc/apache2/mods-available/' '/bin/cp -p /etc/apache2/sites-available/ispcp.conf /etc/ispcp/apache/backup/ispcp.conf.1312222596' '/bin/cp -pf /etc/ispcp/apache/working/ispcp.conf /etc/apache2/sites-available/' '/bin/cp -p /etc/logrotate.d/apache2 /etc/ispcp/apache/backup/apache2.1312222597' '/bin/cp -p /etc/apache2/mods-available/proxy.conf /etc/ispcp/apache/backup/proxy.conf.1312222597' '/bin/cp -p /etc/apache2/sites-available/01_awstats.conf /etc/ispcp/apache/backup/01_awstats.conf.1312222597' '/bin/cp -pf /etc/ispcp/apache/working/01_awstats.conf /etc/apache2/sites-available/' '/bin/cp -p /etc/postfix/main.cf /etc/ispcp/postfix/backup/main.cf.1312222597' '/bin/cp -p /etc/postfix/master.cf /etc/ispcp/postfix/backup/master.cf.1312222597' '/bin/cp -p /etc/postfix/ispcp/aliases /etc/ispcp/postfix/backup/aliases.1312222597' '/bin/cp -p /etc/postfix/ispcp/domains /etc/ispcp/postfix/backup/domains.1312222597' '/bin/cp -p /etc/postfix/ispcp/mailboxes /etc/ispcp/postfix/backup/mailboxes.1312222597' '/bin/cp -p /etc/postfix/ispcp/transport /etc/ispcp/postfix/backup/transport.1312222597' '/bin/cp -p /etc/postfix/ispcp/sender-access /etc/ispcp/postfix/backup/sender-access.1312222597' '/bin/cp -pf /etc/ispcp/postfix/working/main.cf /etc/postfix/main.cf' '/bin/cp -pf /etc/ispcp/postfix/master.cf /etc/ispcp/postfix/working/' '/bin/cp -pf /etc/ispcp/postfix/master.cf /etc/postfix/master.cf' '/bin/cp -pf /etc/ispcp/postfix/ispcp/aliases /etc/ispcp/postfix/working/' '/bin/cp -pf /etc/ispcp/postfix/working/aliases /etc/postfix/ispcp/' '/bin/cp -pf /etc/ispcp/postfix/ispcp/domains /etc/ispcp/postfix/working/' '/bin/cp -pf /etc/ispcp/postfix/working/domains /etc/postfix/ispcp/' '/bin/cp -pf /etc/ispcp/postfix/ispcp/mailboxes /etc/ispcp/postfix/working/' '/bin/cp -pf /etc/ispcp/postfix/working/mailboxes /etc/postfix/ispcp/' '/bin/cp -pf /etc/ispcp/postfix/ispcp/transport /etc/ispcp/postfix/working/' '/bin/cp -pf /etc/ispcp/postfix/working/transport /etc/postfix/ispcp/' '/bin/cp -pf /etc/ispcp/postfix/ispcp/sender-access /etc/ispcp/postfix/working/' '/bin/cp -pf /etc/ispcp/postfix/working/sender-access /etc/postfix/ispcp/' '/bin/cp -p /etc/courier/authdaemonrc /etc/ispcp/courier/backup/authdaemonrc.1312222597' '/bin/cp -p /etc/courier/userdb /etc/ispcp/courier/backup/userdb.1312222597' '/bin/cp -pf /etc/ispcp/courier/working/authdaemonrc /etc/courier/' '/bin/cp -pf /etc/ispcp/courier/userdb /etc/ispcp/courier/working/' '/bin/cp -pf /etc/ispcp/courier/working/userdb /etc/courier' '/bin/cp -p /etc/proftpd/proftpd.conf /etc/ispcp/proftpd/backup/proftpd.conf.1312222597' '/bin/cp -pf /etc/ispcp/proftpd/working/proftpd.conf /etc/proftpd/proftpd.conf' '/bin/cp -p /etc/bind/named.conf /etc/ispcp/bind/backup/named.conf.1312222603' '/bin/cp -pf /etc/ispcp/bind/working/named.conf /etc/bind/named.conf' '/bin/cp -p /var/cache/bind/panel.linuxoid.in.db /etc/ispcp/bind/backup/panel.linuxoid.in.db.1312222603' '/bin/cp -pf /etc/ispcp/bind/working/panel.linuxoid.in.db /var/cache/bind/' '/bin/cp -p /var/www/fcgi/master/php5-fcgi-starter /etc/ispcp/fcgi/backup/master.php5-fcgi-starter.1312222603' '/bin/cp -p /var/www/fcgi/master/php5/php.ini /etc/ispcp/fcgi/backup/master.php.ini.1312222603' '/bin/cp -p /var/www/fcgi/master/php5/browscap.ini /etc/ispcp/fcgi/backup/master.browscap.ini.1312222603' '/bin/cp -pf /etc/ispcp/fcgi/working/master.php5-fcgi-starter /var/www/fcgi/master/php5-fcgi-starter' '/bin/cp -pf /etc/ispcp/fcgi/working/master.php.ini /var/www/fcgi/master/php5/php.ini' '/bin/cp -pf /etc/ispcp/fcgi/parts/master/php5/browscap.ini /etc/ispcp/fcgi/working/browscap.ini' '/bin/cp -pf /etc/ispcp/fcgi/working/browscap.ini /var/www/fcgi/master/php5/browscap.ini' '/bin/cp -p /etc/apache2/sites-available/00_master.conf /etc/ispcp/apache/backup/00_master.conf.1312222603' '/bin/cp -pf /etc/ispcp/apache/working/00_master.conf /etc/apache2/sites-available/' '/bin/cp -p /var/www/ispcp/gui/tools/pma/config.inc.php /etc/ispcp/pma/backup/config.inc.php.1312222603' '/bin/cp -f /etc/ispcp/pma/working/config.inc.php /var/www/ispcp/gui/tools/pma/'
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 ;
Кроме того, в варианте со статическими страницами они тоже создаются с правами 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-файлах):
root@nightwolf:/# grep -HErniI --color=auto 'status_icon' /var/www/ispcp/gui/
/var/www/ispcp/gui/reseller/users.php:273: $status_icon = "ok";
/var/www/ispcp/gui/reseller/users.php:275: $status_icon = "disabled";
/var/www/ispcp/gui/reseller/users.php:282: $status_icon = "reload.png";
/var/www/ispcp/gui/reseller/users.php:284: $status_icon = "error.png";
/var/www/ispcp/gui/reseller/users.php:290: 'STATUS_ICON' => $status_icon,
/var/www/ispcp/gui/themes/omega_original/admin/manage_users.tpl:217: <td class="{USR_CLASS}" align="center"><a href="#" onClick="action_status('{URL_CHANGE_STATUS}', '{USR_USERNAME}')" class="link"><img src="{THEME_COLOR_PATH}/images/icons/{STATUS_ICON}.png" width="16" height="16" border="0" alt="" /></a></td>
/var/www/ispcp/gui/themes/omega_original/reseller/users.tpl:111: <td class="{CLASS_TYPE_ROW}" align="center"><a href="#" onClick="change_status('{URL_CHANGE_STATUS}', '{NAME}')"><img src="{THEME_COLOR_PATH}/images/icons/{STATUS_ICON}.png" width="16" height="16" border="0" alt="" /></a></td>
/var/www/ispcp/gui/include/admin-functions.php:783: $status_icon = 'ok';
/var/www/ispcp/gui/include/admin-functions.php:787: $status_icon = 'disabled';
/var/www/ispcp/gui/include/admin-functions.php:797: $status_icon = 'reload.png';
/var/www/ispcp/gui/include/admin-functions.php:800: $status_icon = 'error.png';
/var/www/ispcp/gui/include/admin-functions.php:807: 'STATUS_ICON' => $status_icon,
- В /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 () будет белый экран)
Просто мысли
База данных и 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";
- Лог в корне каталога используется, например, 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)
- (параметр MaxProcessCount в файле /etc/apache2/mods-enabled/fcgid_ispcp.conf умноженный на
Например, имея лимиты 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
Ссылки
- Официальный сайт
- Официальный форум (часто спамится, но можно найти что-то полезное)
- Мануал по мультисерверной настройке (на базе этого)