Участник:Rain/Заметки/Onyx: различия между версиями

Материал из Linux Wiki
Перейти к навигацииПерейти к поиску
м (чуть поменял формулировку)
Строка 605: Строка 605:
* monit на все основные сервисы на всех серверах
* monit на все основные сервисы на всех серверах
* Восстановить Nagios, скорректировать работу его и/или серверов для снижения текущего числа уведомлений.
* Восстановить Nagios, скорректировать работу его и/или серверов для снижения текущего числа уведомлений.
* Запретить crontab для carid на вебах
* Максимально запретить crontab'ы, особенно на веб-серверах.
* Аудит модулей Апача на вебах, удаление лишних (показ загруженных: apachectl -t -D DUMP_MODULES 2>&1)
* Аудит модулей Апача на вебах, удаление лишних (показ загруженных: apachectl -t -D DUMP_MODULES 2>&1)
* Сделать ежедневный (минимум, а можно и несколько раз в день) снапшот контента веб-сайта на мастер-сервере (минимум (для быстрой развертки контента в случае аварии), как вариант - еще где-то на стороне, в изолированном от боевых серверов месте), хранить снапшоты хотя бы за неделю. В случае с мастером надо определиться с хостерской backup-системой, чтобы она не начала бэкапить 100500 снапшотов одного и того же контента по 100 Гб каждый.
* Сделать ежедневный (минимум, а можно и несколько раз в день) снапшот контента веб-сайта на мастер-сервере (минимум (для быстрой развертки контента в случае аварии), как вариант - еще где-то на стороне, в изолированном от боевых серверов месте), хранить снапшоты хотя бы за неделю. В случае с мастером надо определиться с хостерской backup-системой, чтобы она не начала бэкапить 100500 снапшотов одного и того же контента по 100 Гб каждый.

Версия 10:12, 6 апреля 2012

Заметки по серверам для carid.com:

Что хотелось бы сделать

Кодировки MySQL

Навести порядок с кодировками базы. Сейчас в настройках на большинстве серверов указан (а местами не указан, а просто используется старое дефолтное значение) latin1. При этом в коде явно указывается использовать юникод через

SET NAMES 'utf8'

(иначе бы не получалось сохранять всякие там "®" и прочие юникодные символы) - хотя кое-где стоит

SET NAMES 'latin1'

(но такие места не должны вызвать проблем, в дальнейшем их можно поправить). Т.е., реально настройки указываются одни, база в свойствах таблиц указывает latin1, а реально данные хранятся другие; как следствие - имеем проблемы при работе с дампами.
По-идее, в настройках сервера можно сходу указать правильные параметры подключения - это не должно сломать текущую логику работы (нужна проверка на тестовом сервере); кодировка все равно задается через set names (но не уверен, что именно происходит при репликации и в чем (и какими настройками это регулируется) там передаются данные). Для перехода на правильные настройки можно использовать следующий алгоритм:

    • Прописать правильные настройки на Master-сервере
    • Перевести slave-алиасы на мастер-сервер
    • STOP SLAVE; на слейв-сервере
    • Одновременно перезапускаем Master-сервер
    • Заливаем дамп напрямую с Slave-сервера на Master-сервер, заменяя в потоке charset в дампе на юникодный и проверив, что льется юникодный поток.
    • Снимаем уже правильный дамп с Master-сервера
    • Настраиваем Slave-сервера на работу с юникодом
    • Восстанавливаем работу Slave'ов
    • Переключаем slave сайта на восстановленные слейвы.

По-идее, основная часть работы (и downtime сайта) займет время однопоточной заливки дампа (т.е., минут 30). Как вариант - написать скрипт, который будет дампить и заливать базы впараллель, тогда downtime уменьшится минут до 10.

Заметка по работе с дампами на текущий момент
  • Дамп на бэкапе должен сниматься с default-charset=latin1 и skip-character-set
  • Дамп на import.carid.com должен сниматься без ключей
  • Заливаться дамп везде должен с default-charset=latin1
  • На бэкап-сервере кодировки сервера и клиента различаются (latin1 и utf8) без каких-либо настроек в конфиге мускуля

Ссылки

InnoDB

Перевод базы на InnoDB. Считаю, что это решит нашу текущую проблему с локами базы при смешной нагрузке (как в случае с мастером, когда маленький апдейт лочит все остальные select'ы и они отжирают все доступные подключения - пример такой ситуации у меня есть; так и в случае со слейвом, когда пришедший репликационный запрос лочит вычитку - а в этот момент, например, какой-то скрипт активно использует сервер - в итоге все надолго умирает и идет отставание репликации - по-идее, благодаря версионности InnoDB репликация должна проходить проще. Можно достаточно легко проверить, переведя какой-то слейв на InnoDB и запустив на нем тяжелый скрипт, делающий много вычитки). На данный момент сменить тип движка нельзя для следующих таблиц:

Используется FULLTEXT:

xcart_categories_index
xcart_extra_field_values
xcart_make_model
xcart_order_details
xcart_order_messages
xcart_products
xcart_users_map

Ошибка при конвертации:

"ERROR 1075 (42000) at line 1: Incorrect table definition; there can be only one auto column and it must be defined as a key" в xcart_counters

с ошибкой разобраться, для остальных таблиц потенциально можно вынести поиск в отдельную маленькую таблицу, оставив ее в MyISAM (требует правки кода, так что в крайнем случае можно оставить их как есть - все же лучше иметь 8 лочащихся таблиц, чем 300; однако среди них есть достаточно крупные с частым обращением).

Само по себе изменение остальных таблиц должно пройти гладко; на время конвертации можно переключить Slave-сервера на мастер (т.к. мастер мощный, а слейв могут долго работать с таблицей; как следствие - отставание репликации). Помимо ликвидации табличных локов, это позволит держать всю базу в оперативной памяти, т.е., будет не особо важно, насколько быстрый диск (остальные параметры на тему сброса данных на диск можно потюнить).

Момент, необходимый для рассмотрения - держать ли все таблицы в одном ibdata-файле или нет. С одной стороны работа с таблицами, разделенными по файлам проще (нагляднее, проще для восстановления, наглядно видно занимаемое и свободное место, можно мигрировать с диска на диск на ходу (а надо ли, если замена диска все равно подразумевает отключение сервера?) и т.п.), с другой - в случае использования одного файла можно указать в качестве файла полностью FIO Drive - без таблицы разделов (привет выравниванию) и без файловой системы (привет фрагментации).

До этого момента рассматривать варианты, вроде перехода на MySQL-кластер или Percona-сервер - бред, так как первое, фактически - мультимастер-сервер с синхронной репликацией (и не самым хорошим движком), второе хорошо прежде всего XtraDB (который модифицированный InnoDB - т.е., опять-таки упираемся в переход на InnoDB).

После решения проблем подобных миграций при недостатке производительности (но не ранее) можно рассматривать переход на другие базы (на случай, если векторы развития MySQL и остальных баз не изменится) - на данный момент это MariaDB+XtraDB или Percona Server.

Про Foreign Key к Богдану - момент не понял, ведь если его явно не задавать, то возможностью можно просто не пользоваться и проблем это не вызовет.

Разобрались, просто не поняли друг друга.

Ссылки

Оптимизация использования MySQL-серверов, отказоустойчивость

Потенциально можно раскидывать запросы чтения с основного сайта с Master на Slave-сервер для разгрузки мастер-сервера. Подобные оптимизации можно делать только после ликвидации локов (что даст ускорение репликации и большую синхронность между серверами; как следствие - более корректную вычитку данных приложением).

Варианты реализации:

  • На уровне приложения. Объявить новую переменную с подключением к слейву, подключения на вычитку данных цеплять на эту переменную. Требует правки кода и знания того, как работает сайт, поэтому пока труднореализуемо.
    • Как подпункт: в дальнейшем в таком варианте можно сделать, например, балансировку на уровне DNS'a - объявить для алиаса несколько IP-адресов и он в round robin-режиме будет отдавать разные сервера.
  • На уровне подключений:
    • mysql-proxy. Без наведения порядка с кодировками не взлетит, так как раскидывает подключения на уровне запросов (т.е., set names может уйти на один сервер, а запрос - на другой и получим кашу. Как вариант - жестко задать настройки (пусть и неправильные), чтобы на любой коннект принудительно устанавливалась нужная кодировка (т.е., set names в конфиге сервера) - должно помочь, но требует проверки). Прост в настройке, может раскидывать запросы на запись и чтения по разным серверам (в т.ч. несколько серверов чтения)
    • haproxy. Рулит подключениями на уровне TCP-соединений. Более навороченный вариант, требует больше настройки.

Еще оптимизация - можно сделать Master-Master-репликацию. Тут есть 2 подпункта:

  • Можно вынести админку, с которой работают импортеры/апдейтеры и прочие отделы на другой мастер-сервер при условии малого пересечения таблиц, в которые пишет админка и сайт (подразумевается, например, что посетитель не пишет в таблицу с перечнем товаров, в которую пишет сотрудник и т.п. Как подвариант - пересекающиеся таблицы писать только на один сервер для исключения ситуации split brain'a)
  • HA-кластер. Умирает один мастер - переключаемся каким-то средством балансировки на другой (через haproxy/mysql-proxy/heartbeat и т.п.). Пока второй мастер живой - используется для админки (1-й пункт) или как слейв. Плюс как слейв можно завести 3-й сервер (освободившийся от memcached, например). На пару с избавлением от центрального memcached получим полностью отказоустойчивую систему.

Memcached

Убрать единый сервер Memcached и создать собственный Memcached на каждом веб-сервере. Плюсы:

  • Убираем единую точку отказа
  • Убираем оверхед при перегонке мелких данных по сети.
  • Не держим лишний мощный, но практически не используемый сервер

Недостаток такого варианта - выделение памяти на каждом сервере. На деле из 36 Гб на веб-серверах используется 2-3 Гб. Memcached за долгое время набрал данных лишь на 8 Гб (на момент написания текста), из них многое - из-за постоянных тестов. Эффективность кэша на момент 8 Гб - порядка 80 процентов (update: 80 процентов из всех выборок чтения. На деле доля удачных чтений из всех запросов на уровне 60 процентов), что мало. Итого, если выделить даже по 16 Гб под memcached на каждом сервере - этого с головой хватит и для нужд веб-сервера, и для memcached. По процессору - даже единый memcached практически не нагружает процессор (нагрузка на уровне пары процентов для одного ядра сервера). При разделении нагрузка на каждый отдельный memcached уменьшится до 3 раз на текущий момент. Когда начнем упираться в процессор на веб-сервере - наличие на нем memcached будет далеко не самой большой проблемой (иначе говоря, мы скорее заведем новый сервер впараллель к трем существующим, чем упремся в процессор).

Варианты реализации:

  • Репликация данных: не затрагивает приложение, но repcached на данный момент умеет работать только в режиме master<->master или мастер с несколькими слейвами (кстати, пробовал репликацию цепочкой - не взлетело, да и не является отказоустойчивой). Для наших трех серверов не подходит. Из того, что протестировал между двумя серверами - плюс в том, что при восстановлении сервера реплицируются все данные, т.е., снова разогревать кэш не придется.
  • Redis. Проблемы с репликацией те же, что и в первом пункте, в остальном вроде как является более быстрой альтернативой memcached (что пока не требуется).
  • Использовать средства приложения: Богдан говорит, что приложение при легкой правке кода может принимать массив серверов, при этом можно указывать их вес (т.е., для 127.0.0.1 указать максимальный приоритет, для других узлов - меньший).


Скриптик для мониторинга эффективности кэша
while sleep 1
do
clear
echo -e "stats\nquit" | nc localhost 11211 |
awk '
/cmd_get/{cg=$3}
/cmd_set/{cs=$3}
/get_hits/{gh=$3}
/delete_misses/{dm=$3}
/delete_hits/{dh=$3}

END {
t=cg+cs+dm+dh
dt=dm+dh
print "Report: \t[R: "cg/t*100"% (only "gh/t*100"% successful) + W: "cs/t*100"% + D: "dt/t*100"% (only "dh/t*100"% successful)] from "t" total requests"
}'
done

Тест латентности сети

Провел небольшой тест на латентность сети при работе с мелкими данными в кэше.

Скрипт:


<?php

$m = new Memcached();
$m->addServer("$argv[1]", "$argv[2]");

for ($i = '1'; $i <= "$argv[3]"; $i++) {

$a=rand().rand().rand();

$m->set("$i", "$a");
}
?>

Для Ъ: создание указанного 3-м параметром числа ключей и занесение в каждый из ключей рандомного числа.

Было сделано 4 тестирования - скрипт на локалхосте + memcached на локалхосте, скрипт на локалхосте + memcached на машине в локальной сети и для обоих вариантов скрипт и memcached менялись местами.

100 Мбит

Линк 100 Мбит (Реально сервер подключен к гигабитному свичу, но десктоп - к 100 Мбит. При случае протестирую на полностью гигабитной сети). Результаты повторяемые:

Тест на десктопе:

Все локально:

rain@debian:~$ time php /tmp/phpset.php localhost 22122 1000000

real    0m28.818s
user    0m7.656s
sys     0m6.068s

Memcached на другой машине в сети:

rain@debian:~$ time php /tmp/phpset.php 10.0.2.2 22122 1000000

real    1m58.699s
user    0m7.284s
sys     0m5.788s

Тест на удаленной машине:

Все локально:

rain@developer:~$ time php /tmp/file.php 10.0.2.2 22122 1000000


real    0m34.526s
user    0m6.844s
sys     0m12.541s

Memcached на другой машине в сети:

rain@developer:~$ time php /tmp/file.php 10.0.2.19 22122 1000000


real    2m0.241s
user    0m12.253s
sys     0m15.245s

1 Гбит

ToDo: Сделать тест для гигабитной незагруженной сети

Сеть vs Сокет

Сделал еще тест для сравнения скорости работы через сеть и через unix-сокет. Правда, для этого пришлось перейти на php5-memcache (php5-memcached не хотел подключаться к сокету - или я что-то не так сделал). Соответственно, по правкам скрипта - new Memcache() и connect вместо addServer. Тест сделан на одной и той же незагруженной машине с двухядерным процессором. Результаты:

Сокет:

root@developer:~# time php file.php unix:///tmp/mem.sock 0 1000000

real    0m30.652s
user    0m10.109s
sys     0m9.465s

Сеть:

root@developer:~# time php file.php 127.0.0.1 22122 1000000

real    0m41.677s
user    0m11.513s
sys     0m15.353s

Результаты стабильно повторяемы.

Ссылки

Безопасность

ToDo: Заполнить

Web

Soft

  • Apache/nginx на веб-серверах сейчас работают через права группы (контент под carid:users, Апач - под apache:users (почему-то :) кроме 2-го веба), nginx - через nginx:users), но контент часто имеет права 666 или 777. Определиться, нужна ли запись данных Апачем в каталоги сайта; если да - перевести Апач под пользователя сайта, если нет - просто переключить с users на выделенную группу (см. ниже).
  • Запретить выполнение скриптов из каталогов аплоада файлов (/images, /files и вообще любых каталогов, где могут появляться файлы) (без разницы, аплоадятся они через веб или FTP). На данный момент в images/ есть ряд скриптов сомнительной нужности (в этом каталоге):
root@345735-web1:/home/carid/httpdocs/images# find . -iname "*.php"
./mcafee3.php
./ebay/left_menu.php
./ebay/contact.php
./ebay/header_menu_d.php
./gps-systems/garmin/downloads/script.php
По возможности перенести их в другое место, а каталог закрыть.

PHP

  • Позапрещать ненужные функции в настройках PHP. Сейчас свободно работают всякие там system, exec и прочее, что позволяет свободно пользоваться веб-шеллами (проверено). При использовании багов в коде сайта по серверу можно свободно разгуливать и запускать программы с правами apache (48).

Набросок однострочников для поиска ненужных функций:
# Поиск функций в коде                                                                                                                                                                       
LANG=C grep -hEIro --include="*.php*" "[ ^]\b[a-z0-9_]+\(" /home/carid/httpdocs/ | sed -r 's/\(|^ //g' | sort -u > carid_func_list
# вывод доступных функций в PHP
php -r '$functions = get_defined_functions();sort($functions['internal']);print_r($functions['internal']);' 2>/dev/null | awk '/[0-9]\] =>/{print $3}' > php_func_int
# Показ используемых встроенных функций
fgrep -x -f carid_func_list php_func_int
# Показ неиспользуемых встроенных функций
fgrep -x -v -f carid_func_list php_func_int

# Поиск функций в коде
echo list_of_functions | tr ' ' '\n' | while read i
do
grep -HrEnIo --include="*.php*" "[ ^]\b$i\(" /home/carid/httpdocs/ || echo "${i}: NOT_USED"
done | awk '/NOT/; /\($/{gsub(/\(/, "", $2); gsub(/:$/, "", $1); print $2": "$1}' > flist

На данный момент в коде найдена 631 встроенная функция.

При тестовом запуске заметил, что в коде бывает встречаются реально не используемые функции - например, в модулях Zend'a
(TODO: запросить у программеров, какие модули Zend'a и прочих фреймворков реально нужны)
или в каких-нибудь OS-специфичных проверках - например, в ./modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/RunTest.php попалось такое:

        if (OS_WINDOWS && isset($section_text['RETURNS'])) {
            ob_start();
            system($cmd, $return_value);

и это единственное место использования system() в коде. Соответственно, можно безопасно это отключить.

Наброски списка функций для отключения:


# Остатки нагугленных функций, которые отключали другие люди. Не удалил на всякий случай, может пригодится.
# disable_functions = eval, PHP_SELF, highlight_file, ini_restore, ini_set, posix_setpgid, posix_setsid

# Не найденные в документации функции.
# proc, dll, max_execution_time, proc_show, cpuinfo, meminfo, cmd, uname, ftp, debugger_on, debugger_off, listen, ioctl, leak, ssthru, view_size

# Разное
disable_functions = dl, posix_mkfifo, chown, link, symlink, phpinfo, ftp_exec, chgrp, ssh2_exec, posix_setuid, posix_setgid, posix_kill, escapeshellarg, escapeshellcmd
disable_functions = syslog, closelog, define_syslog_variables, openlog

# Требуется проверка - функции могут для чего-то использоваться
disable_functions = chmod, set_time_limit, php_uname, posix_uname, disk_free_space, diskfreespace, disk_total_space, get_env, ini_get_all, ini_get, error_log

# Зависит от используемого варианта PHP. Работает только в том случае, когда PHP подключен через mod_php
disable_functions = apache_get_modules, apache_get_version, apache_note, apache_setenv

# Выполнение команд
disable_functions = shell_exec, exec, system, passthru, popen, proc_open, proc_nice, proc_get_status, proc_close, proc_terminate

# Работа с процессами
disable_functions = pcntl_alarm, pcntl_exec, pcntl_fork, pcntl_getpriority, pcntl_setpriority, pcntl_signal_dispatch, pcntl_signal, pcntl_wait
disable_functions = pcntl_waitpid, pcntl_wexitstatus, pcntl_wifexited, pcntl_wifsignaled, pcntl_wifstopped, pcntl_wstopsig, pcntl_wtermsig

Проверка показала использование в коде 73 функций из списка выше (без тех, что требуют проверки, но с php_uname и posix_uname), из них 2 - в комментариях.
Список протестированных функций
pcntl_waitpid: NOT_USED
pcntl_wexitstatus: NOT_USED
pcntl_wifexited: NOT_USED
pcntl_wifsignaled: NOT_USED
pcntl_wifstopped: NOT_USED
pcntl_wstopsig: NOT_USED
pcntl_wtermsig: NOT_USED
pcntl_alarm: NOT_USED
pcntl_exec: NOT_USED
pcntl_fork: NOT_USED
pcntl_getpriority: NOT_USED
pcntl_setpriority: NOT_USED
pcntl_signal_dispatch: NOT_USED
pcntl_signal: NOT_USED
pcntl_wait: NOT_USED
shell_exec: NOT_USED /home/carid/httpdocs/include/classes/class.upload.php:424
exec: /home/carid/httpdocs/include/classes/Zend/Db/Adapter/Pdo/Abstract.php:256
exec: NOT_USED /home/carid/httpdocs/include/classes/class.upload.php:424
exec: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Builder.php:378
exec: /home/carid/httpdocs/modules/HTML_PDF/dompdf/load_font.php:231
system: NOT_USED /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/RunTest.php:449
passthru: NOT_USED
popen: /home/carid/httpdocs/payment/cc_saferpay.php:65
popen: /home/carid/httpdocs/payment/cc_saferpay.php:137
popen: /home/carid/httpdocs/include/func/func.https_ssleay.php:103
popen: /home/carid/httpdocs/include/func/func.https_httpscli.php:100
popen: /home/carid/httpdocs/include/func/func.https_curl.php:169
popen: /home/carid/httpdocs/include/func/func.https_openssl.php:108
popen: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Builder.php:442
popen: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Package.php:454
popen: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Package.php:535
popen: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Package.php:724
popen: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/OS/Guess.php:247
proc_open: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/RunTest.php:125
proc_open: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/RunTest.php:131
proc_nice: NOT_USED
proc_get_status: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/RunTest.php:168
proc_close: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/RunTest.php:173
proc_terminate: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/RunTest.php:156
apache_get_modules: /home/carid/httpdocs/m1info.php:926
apache_get_version: NOT_USED
apache_note: NOT_USED
apache_setenv: NOT_USED
syslog: /home/carid/httpdocs/kmp/admin/application/libraries/PEAR/PEAR.php:84
syslog: /home/carid/httpdocs/include/classes/Zend/Log/Writer/Syslog.php:265
syslog: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR.php:84
closelog: /home/carid/httpdocs/include/classes/Zend/Log/Writer/Syslog.php:237
define_syslog_variables: NOT_USED
openlog: /home/carid/httpdocs/include/classes/Zend/Log/Writer/Syslog.php:177
dl: /home/carid/httpdocs/kmp/admin/ci_system/libraries/Image_lib.php:1458
dl: /home/carid/httpdocs/kmp/admin/application/libraries/PEAR/PEAR.php:743
dl: /home/carid/httpdocs/kmp/admin/application/libraries/PEAR/PEAR.php:748
dl: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR.php:743
dl: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR.php:748
posix_mkfifo: NOT_USED
chown: NOT_USED
link: /home/carid/httpdocs/include/classes/Zend/Feed/Entry/Atom.php:243
link: /home/carid/httpdocs/include/classes/Zend/Feed/Entry/Atom.php:252
link: /home/carid/httpdocs/include/classes/Zend/Feed/Atom.php:121
link: /home/carid/httpdocs/include/classes/Zend/Feed/Atom.php:130
symlink: NOT_USED
phpinfo: /home/carid/httpdocs/wde-master/admin/general.php:63
phpinfo: /home/carid/httpdocs/kmp/admin/application/models/bugreportmodel.php:54
phpinfo: /home/carid/httpdocs/include/classes/Zend/Tool/Framework/System/Provider/Phpinfo.php:35
phpinfo: /home/carid/httpdocs/include/classes/class.upload.php:491
phpinfo: /home/carid/httpdocs/include/classes/class.upload.php:2986
phpinfo: /home/carid/httpdocs/ioncube/ioncube-loader-helper.php:180
phpinfo: /home/carid/httpdocs/ioncube/ioncube-loader-helper.php:574
phpinfo: /home/carid/httpdocs/ioncube/ioncube-loader-helper.php:662
phpinfo: /home/carid/httpdocs/ioncube/ioncube-loader-helper.php:902
phpinfo: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Install.php:357
phpinfo: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Install.php:410
phpinfo: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Install.php:454
phpinfo: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Install.php:722
phpinfo: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Install.php:968
ftp_exec: NOT_USED
chgrp: NOT_USED
ssh2_exec: NOT_USED
posix_setuid: NOT_USED
posix_setgid: NOT_USED
posix_kill: NOT_USED
escapeshellarg: /home/carid/httpdocs/kmp/admin/application/libraries/index_doc_lib.php:22
escapeshellarg: /home/carid/httpdocs/kmp/admin/application/libraries/index_rtf_lib.php:25
escapeshellarg: /home/carid/httpdocs/kmp/admin/application/libraries/index_pdf_lib.php:24
escapeshellarg: /home/carid/httpdocs/kmp/admin/application/libraries/index_ppt_lib.php:31
escapeshellarg: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Package.php:440
escapeshellarg: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Package.php:447
escapeshellarg: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Package.php:525
escapeshellarg: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Command/Package.php:529
escapeshellarg: /home/carid/httpdocs/modules/HTML_PDF/dompdf/load_font.php:231
escapeshellcmd: NOT_USED
php_uname: /home/carid/httpdocs/wde-master/admin/general.php:104
php_uname: /home/carid/httpdocs/m1info.php:595
php_uname: /home/carid/httpdocs/include/classes/CyberSorce/CYBERSOURCE.php:199
php_uname: /home/carid/httpdocs/include/classes/Zend/Mail/Storage/Writable/Maildir.php:417
php_uname: /home/carid/httpdocs/include/classes/Zend/Mail.php:1117
php_uname: /home/carid/httpdocs/ioncube/ioncube-loader-helper.php:311
php_uname: /home/carid/httpdocs/check_requirements.php:346
php_uname: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/DependencyDB.php:452
php_uname: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Dependency2.php:275
php_uname: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/PEAR/Registry.php:780
php_uname: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/OS/Guess.php:26
php_uname: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/OS/Guess.php:88
php_uname: /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2/PEAR/OS/Guess.php:129
php_uname: /home/carid/httpdocs/modules/HTML_PDF/dompdf/include/functions.inc.php:205
posix_uname: NOT_USED
  • Использовать open_basedir - сейчас доступ к файловой системе через PHP для основного сайта никак не ограничен; для доменов на mail.carid.com кое-где указан, но "/tmp" используется общий для всех сайтов
  • По возможности актуализировать (и поддерживать в дальнейшем) версии используемых фреймворков и прочих веб-компонентов:
    • /home/carid/httpdocs/include/classes/Zend/Version.php: текущая версия 1.11.7, актуальная: 1.11.11, changelog (и далее)
    • /home/carid/httpdocs/modules/Amazon_Payment_Checkout/lib/PEAR-1.7.2: текущая версия 1.7.2 (Rel: 2008-05-17), актуальная: 1.9.4 (Rel: 2011-07-07), changelog (+более ранние), + проверить используемые модули.
    • /home/carid/httpdocs/kmp/admin/application/libraries/PEAR/PEAR.php: текущая версия 1.7.1 (Rel: 2008-02-03), остальное аналогично предыдущему.
  • Протестировать связку suhosin + mod_security + fail2ban

FTP

  • /etc/proftpd.conf@mail.carid.com: Umask 027
Ссылки

Общее

Сервисы

Общее

  • Полностью выпилить Mail-сервера (smtp, pop/imap) на вебах и DB-серверах, перейти на nullmailer-like пересылку с форвардом на mail.carid.com - избавление от лишних потенциально уязвимых сервисов, требующих обслуживания.
    • Все bounced-письма или недоставленные сообщения должны собираться на mail.carid.com
  • Убрать automount. Идет в дефолтной поставке и на серверах не выполняет ничего полезного. После этого можно будет убрать каталоги /misc, /net
  • Определиться с софтом, необходимым хостеру. На данный момент непонятный статус у следующих процессов:
Web:

dsm_*
rhnsd
snmpd

Mail:

+ brcm_iscsiuio
+ iscsid
+ *simpana* (cvd, EvMgrC)

----

+ miniserv WebMin'a
  • Сделать аудит crontab'ов и периодически запускаемых процессов в них, расписать, зачем нужен каждый скрипт и кем (по чьему запросу) он был добавлен.
  • После удаления лишних сервисов удалить ненужные, временные и т.п. аккаунты.
  • Пообновлять пароли на серверах, перейти на sha512-хэши.
  • Ввести политику использования ssh-ключей, запретить использование парольного входа, запретить рут-логин, (запретить туннели?).
  • Избавиться от реальных пользователей для proftpd на mail.carid.com, перейти на виртуальных
    • Определиться со списком нужных пользователей и тем, куда они должны ходить; далее либо перевести proftpd под nobody, а для каталогов сделать UserOwner/GroupOwner <юзер/группа сайта> (это сейчас не работает, хоть и встречается в конфиге), что попутно позволит избежать проблем с правами, либо (если заработает) использовать одного пользователя/группу в файле описания виртуальных пользователей.
Заработает. Делаем что-то вроде:

AuthUserFile /etc/proftpd/auf
# Или вообще выпилить обычных системных юзеров и разрешить только тех, которые описаны в файле выше - т.е., убрать mod_auth_unix.c
AuthOrder mod_auth_file.c mod_auth_unix.c
RequireValidShell off

в конфиге сервера, после чего

echo PASSWORD | ftpasswd --passwd --gid=2521 --file=/etc/proftpd/auf --md5 --not-system-password --name USER --shell /usr/sbin/nologin --uid 10001 --home=/bla/bla/images --stdin

Получаем кучку виртуальных юзеров, работающих с контентом под одним пользователем, но с различающимися логинами. В GECOS можно загнать полные имена, чтобы потом проще было находить виновных :).

Файлик читается юзером proftpd (или тем, кто определен в конфиге как User), т.е., он должен иметь права на чтение файла (думаю, есть смысл сделать proftpd:nobody 640)
  • Перевод SUID-бинарников на группы
Заметка
find / -xdev -perm -4000 -ls

groupadd -r suid

bins='/bin/su /bin/ping /bin/mount /bin/ping6 /bin/umount /usr/bin/chsh /usr/bin/chfn /usr/bin/newgrp /usr/bin/passwd /usr/bin/gpasswd /sbin/mount.nfs'

chown :suid $bins
chmod 4750 $bins

find / -xdev -perm -4000 -ls

Web

  • Убрать vsftpd (FTP на веб-серверах не нужен, все изменения делаются через мастер-сервер, для того, чтобы забрать какой-то файлик с веба (логи, например) есть NFS)
  • Убрать xinetd (не несет никакой полезной нагрузки, просто лишний сервис)
  • atd (вроде нигде не используется)
  • mysqld (не используется, нет ни одной базы)

Mail

  • После изменений архитектуры определить, нужен ли отдельный mysql-сервер на mail.carid.com - как минимум определиться с тем набором баз, которые в данный момент на нем есть.
Вроде используется для CPanel, но кроме него в базе есть еще куча мусора, вроде старой копии базы для carid
  • Убрать xinetd: через него запускаются только почтовые сервисы (qmail и т.п.), ftp и rsync. Почта и FTP используются постоянно, у нас не так мало ресурсов, чтобы использовать суперсервер, поэтому можно перевести их в standalone-режим. rsyncd как демон теперь не используется.
  • Убрать rsyncd. Заменен lsync'ом, который работает с rsync через ssh.

SQL-DB-сервера

Определиться с тем, какие у нас сервера будут работать (в т.ч. определиться по архитектуре и требуемой мощности серверов), потом смотреть сервисы

NOSQL-сервер (memcached)

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

  • vsftpd
  • mysqld
  • xinetd

Файловая система

  • Сделать лучшую разбивку дискового пространства на разделы, использовать запрещающие опции монтирования для разделов, доступных на запись, использовать квоты.
Кандидаты на вынесение на другой раздел:
/home/ (особенно для Web'ов, где в /home хранится веб-контент)
/var
/var/log
/usr (статический контент, можно даже сделать с RO, но надо проверить работоспособность бэкапа - или доработать скрипты)
/tmp (кое-где уже есть)
/var/qmail/ для Mail-сервера
/var/lib/mysql/ вынести в отдельный каталог (по аналогии с master-серверами) и на отдельный раздел
/home/carid/httpdocs/var/ на вебах вынести в /var/log/<что-то> или просто на отдельный раздел.
/var/run и /var/lock - подумать насчет вынесения в tmpfs
  • На вебах и master-сервере сменить права на контент на 640(750), раз в сутки делать поиск по cron'у файлов с кривыми правами и фиксить.
  • Убрать дефолтную системную группу (users, 100) для веб-контента, использовать выделенную группу (завести группу carid, например, сделать ее основной для пользователя carid).
    • nginx перевести в эту группу (ему надо только читать контент - хватит и группы с RO-правами)

Разное

Заметки на различные тематики / для сортировки:

  • Варианты балансировки обращения к базе:
    • mysql-proxy (ro, rw)
    • haproxy (ro, rw)
    • DNS round robin (ro)
    • iptables DNAT range (ro)
  • Оптимизация/изменение настроек MySQL:
    • Увеличить время хранения бинлогов/relay-логов - должно с запасом покрывать выходные, т.е., 3-4 дня.
    • Не запускать slave-сервер автоматом при перезапуске.
  • Вынести каталог с сервер-специфичными файлами (в частности, var) из каталога httpdocs
  • Было бы интересно собрать полную (в т.ч. User Agent'ы) статистику посещений сайта.
  • LOW_PRIORITY_UPDATES актуально только для движков с табличными локами, т.е., на InnoDB апдейты будут идти с нормальным приоритетом.
  • Перейти на RAID10 на Slave-сервере. 5-й сильно уж тормозит - дамп заливался несколько часов против 40 минут (при тесте на RAID10 на Mail-сервере). RAID5 неприменим для базы.
Тест на Mail-сервере
root@345731-mail1:~# time { pv  carid_2012_02_20.sql.bz2 | pbunzip2 -c | mysql -hlocalhost -uroot -p'pass' raidtestdb ; }
1.85GB 0:40:09 [ 803kB/s] [===================================================>] 100%

real    40m20.638s
user    16m31.050s
sys     0m20.355s
  • По работающей в данный момент почте на серверах:
    • memcached: почта не работает совсем. Postfix шлет почту на полное имя, не может отрезолвить домен, бонсит мыло опять-таки на полный домен, которое тоже никуда не приходит. Про то, что он отвечает за *db2* - не знает, так как в базе mydestination - левый домен.
    • old db: В конфиге есть mynetworks = 1.1.1.1/32. По использованию: шлются отчеты по обновлениям на rgerashenko
    • slave: почтой явно давно не пользовались, в логах за последнее время пусто
    • master: По использованию - аналогично с old db
    • web1: в mydestination кривой домен получателя - стоит web2 (да еще и hostname!=mailname, что создает свои проблемы), но локально почта пытается работать благодаря тому, что @web1.carid.com резолвится. На деле - см. memcached. В конфиге разрешен релей для 1.1.1.1/32. "mail for web1.carid.com loops back to myself".
    • web2: Полностью аналогичен web1, только в качестве левого домена указан web3
    • web3: Домен в mydestination соответствует хостнейму (но не mailname, как и на остальных серверах), поэтому почта так же само зацикливается. Разрешенный релей - 1.1.1.1/32.
  • monit на все основные сервисы на всех серверах
  • Восстановить Nagios, скорректировать работу его и/или серверов для снижения текущего числа уведомлений.
  • Максимально запретить crontab'ы, особенно на веб-серверах.
  • Аудит модулей Апача на вебах, удаление лишних (показ загруженных: apachectl -t -D DUMP_MODULES 2>&1)
  • Сделать ежедневный (минимум, а можно и несколько раз в день) снапшот контента веб-сайта на мастер-сервере (минимум (для быстрой развертки контента в случае аварии), как вариант - еще где-то на стороне, в изолированном от боевых серверов месте), хранить снапшоты хотя бы за неделю. В случае с мастером надо определиться с хостерской backup-системой, чтобы она не начала бэкапить 100500 снапшотов одного и того же контента по 100 Гб каждый.
Снапшотилка для бэкап-сервера
td="/home/carid/snapshot/$(date +%Y/%m/%d)" ; mkdir -p "${td}" ;  cp -al /home/carid/httpdocs/ ${td}
  • Вспомнить, зачем на вебах apache в группе nagios'a (если это делал я)
  • Повыявлять и сделать аудит существующих костылей "напарничка" на серверах; убрать лишние и то, что с ними связано. На данный момент из найденного:
    • @web{1..3}: /etc/logrotate.d/maillog - cat'ает maillog в несуществующий файл, после чего запускает /home/carid/scripts/mailanalyse.sh. Тот в свою очередь пытается подключаться на старую офисную базу, обламывается, в результате чего на серверах днями висят ветки процессов cron->logrotate->mysql. Ненужность: 1) Оно в любом случае не работает; 2) maillog'ов на вебах не будет вообще.
      • /home/carid/scripts содержит только упомянутый скрипт (и его вариации), поэтому после зачистки можно каталог полностью удалить.

Лишние пакеты

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

Service Web (все) Mail Master Old Slave Memcached
httpd X [1] X [2] X [3] X [1]
nginx X [4]
autofs X X X X X X
xinetd X X [5] X X X X
subversion X X [3] X [3] X [3] X [3]
postfix X [6] X X X X
dovecot X X X X X
squirrelmail X X X X X
webalizer X X X X
bind X [7] X X X X
spamassassin X X X X X
cyrus-sasl* X X X X X
vsftpd X X X X X
sendmail X X X X X
ppp X [7] X[7] X[7] X[7] X[7] X[7]
rsyncd X [8]
mysqld X X
php-* X X X X
  1. 1,0 1,1 работает, никуда не смотрит. Присутствуют конфиги для webalizer, squirrelmail и т.п.
  2. пытается запуститься, но фейлится на своей конфигурации
  3. 3,0 3,1 3,2 3,3 3,4 отключен в init-скриптах
  4. работает, есть конфиг для carid
  5. Mail и FTP перевести на standalone
  6. После перехода на nullmailer
  7. 7,0 7,1 7,2 7,3 7,4 7,5 7,6 установлен, но не запущен и не используется
  8. Не является отдельным пакетом, необходимо просто удалить запуск в xinetd и конфиги

Что сделано

На данный момент из полезного сделано:

Разное

  • ­done! inotify-based синхронизация контента между 6 (master -> web{1,3}/import/backup) серверами. Практически не вызывает нагрузки, контент копируется в реальном времени.
Мусор, выкинутый после введения lsyncd
www@import.carid.com

*/15    *       *       *       *               RSYNC_PASSWORD="djh8PKq" /usr/local/bin/rsync -rzt carid@50.56.1.164::images/ /www/import.carid.com/images > /dev/null 2>&1
0       */1     *       *       1,2,3,4,5       RSYNC_PASSWORD="djh8PKq" /usr/local/bin/rsync --exclude 'phpmyadmin/' --exclude 'phpmyadmin3/' --exclude 'import2/' --exclude 'images/' --exclude 'import/' --exclude 'config.php' --exclude 'config/config.xml' --exclude 'index.php' --exclude 'files/' --exclude 'var/tmp/' --exclude 'var/log/' --exclude 'var/templates_c/' --exclude 'var/cache/' --exclude 'wde-master/admin/.htaccess' --exclude 'include/refine_search_detection.php' --exclude 'csv_parser/' --exclude '.htaccess' --exclude='.svn' -rzt carid@50.56.1.164::httpdocs/ /www/import.carid.com > /dev/null 2>&1 && /bin/rm -f /www/import.carid.com/var/templates_c/* > /dev/null 2>&1


root@mail

*       *       *       *       *       /root/bin/ftpwatch2sql.sh

shell@mail>

fix /var/www/vhosts/carid.com/private/svn/svn_sync.sh

carid@mail

*       *       *       *       *       /usr/local/bin/psqlftpfile.sh 2>>/tmp/sync.log
0       2       *       *       *       rsync -trvn --del --exclude='wde-master'  --exclude='.svn' --exclude='/config.php' --exclude='config/*' --exclude='/robots.txt' --exclude='.htaccess' --exclude="var/*" --exclude="private/*" --exclude="sync-stat/" /var/www/vhosts/carid.com/httpdocs/ web3:/home/carid/httpdocs/ | mail -s "Master->web3 rsync report" team.admins@onyxenterprises.com
0       2       *       *       *       rsync -trvn --del --exclude='wde-master'  --exclude='.svn' --exclude='/config.php' --exclude='config/*'  --exclude='/robots.txt' --exclude='.htaccess' --exclude="var/*" --exclude="private/*" --exclude="sync-stat/" /var/www/vhosts/carid.com/httpdocs/ web2:/home/carid/httpdocs/ | mail -s "Master->web2 rsync report" team.admins@onyxenterprises.com
0       2       *       *       *       rsync -trvn --del --exclude='wde-master'  --exclude='.svn' --exclude='/config.php' --exclude='config/*' --exclude='/robots.txt' --exclude='.htaccess' --exclude="var/*" --exclude="private/*" --exclude="sync-stat/" /var/www/vhosts/carid.com/httpdocs/ web1:/home/carid/httpdocs/ | mail -s "Master->web1 rsync report" team.admins@onyxenterprises.com

carid@web{1,2,3}

0       *       *       *       *       sleep 15; RSYNC_PASSWORD="djh8PKq" nice -n 19 ionice -c 2 -n 7  rsync -rqvt carid@192.168.100.164::files/ /home/carid/httpdocs/files >> /tmp/sync.log
0       *       *       *       *       sleep 15; RSYNC_PASSWORD="djh8PKq" nice -n 19 ionice -c 2 -n 7 rsync -rqvt carid@192.168.100.164::pages/ /home/carid/httpdocs/skin1/pages >> /tmp/sync.log
0       *       *       *       *       sleep 15; RSYNC_PASSWORD="djh8PKq" nice -n 19 ionice -c 2 -n 7 rsync -rqvt --delete carid@192.168.100.164::images/ /home/carid/httpdocs/images  >> /tmp/sync.log
*/30    *       *       *       *       scp -rp mail1:~carid/httpdocs/authorized-installers ~carid/httpdocs/ > /dev/null 2>&1
0       8       *       *       1,3,5   scp -rp mail1:~carid/httpdocs/sitemaps ~carid/httpdocs > /dev/null 2>&1

Web

  • ­done! /var/www/vhosts/carid.com/httpdocs/images/mcafee3.php вынести с вебов (он везде одинаковый и генерит одну картинку, которую можно просто создавать на мастере)