Эта статья — часть Большого Мануала по настройке lamp-сервера на debian.
Предыдущая часть цикла — Боремся с вирусней на сайтах.
Следующая часть цикла — Not yet published
Исторически большая часть вирусни для php занимается именно тем, что шлёт спам. Навскидку я бы оценил количество этой вирусни в половину от всей. Поэтому логгирование вызовов mail() сильно сокращает время на поиск активной части вирусни. Да и просто для дебага «почему письмо не шлется» удобно. Тем более, что в php с версии 5.3 всё же прикрутили неплохое логгирование, которое указывает конкретный php-файл и строчку, где был вызов.
Но, сами понимаете, если бы всё было просто, статью писать я бы не стал. Лог-то прекрасно пишется, если просто включить настройку mail.log, но пишется он от имени пользователя, под которым запущен сам скрипт (соответственно, под апачем скорее всего www-data). А если каждый сайт под своим пользователем? Соответственно, все мануалы пестрят чем-то вроде «создайте файл /var/log/php-mail.log, сделайте chmod 777». В принципе, незачем читать его кому-либо, кроме рута и группы adm, как это принято для всех логов, куда может попасть приватная инфа.
Поэтому отправлять лог мы будем не в файл, а в syslog. Что характерно, официальная документация на php.net об этом не напоминает, да и вообще пришлось поискать, как такое сделать (сначала я пытался сделать mail.log = /dev/log). В итоге, конечно, ничего сложного.
Сначала создаём каталог и файл для лога (вообще каталог не обязательно, я для аккуратности):
Далее заводим ini-файл для php, который включит логгирование (я пишу пример для apache, для fpm/cli просто положите по аналогии в соответствующие каталоги). Для php 5.X в debian файл следует поместить в /etc/php5/apache2/conf.d/90-mail-log.ini, для php7.0 — в /etc/php/7.0/apache2/conf.d/90-mail-log.ini, для 7.2 (если у вас пакет от Ondrej) — в /etc/php/7.2/apache2/conf.d/90-mail-log.ini
Содержимое файла (можете, в принципе, вписать в сам php.ini, но это не всегда удобно):
Далее настраиваем rsyslog (он стоит по умолчанию в debian, для остальных сами гляньте, как откладывать в файл строчки по вхождению), чтобы нужная нам информация попадала в отдельный лог. Кстати, сойдёт за пример, как писать отдельный лог для любых строчек с каким-либо вхождением (в данном случае — «mail()»). Например, в файл /etc/rsyslog.d/99-php-maillog.conf
& ~
Почти всё, остаётся только написать конфиг для logrotate, чтобы случайно не забить всё место. Ротировать будем при достижении файлом определенного размера (size 100M). Пишем, например, в /etc/logrotate.d/php-mail
rotate 7
size 100M
copytruncate
create 0640 root adm
compress
missingok
notifempty
}
Всё, осталось только отрестартить нужные демоны:
Теперь у нас есть лог, в который могут писать любые сайты вне зависимости от пользователя, под которым сайт работает. Прочитать этот лог могут только root и пользователи группы adm, а сам лог изредка ротируется.
Строчки в логе будут выглядеть примерно так:
Стоит добавить:
1) Полезно так же выставить mail.add_x_header в true. Так в самом тексте письма будет добавлено имя файла, который сгенерировал это письмо и UID пользователя.
2) Если у вас таки есть желание отдать логи пользователю, то можно писать что-то типа ‘mail.log = «${HOME}/logs/mail.log»‘. Можно ли так же настроить logrotate с ходу не скажу, но в крайнем случае можно для logrotate генератор конфигов написать.
> 1) Полезно так же выставить mail.add_x_header в true. Так в самом тексте письма будет добавлено имя файла, который сгенерировал это письмо и UID пользователя.
Как раз не полезно, information disclosure.
А в логе всё то же самое будет.