Зачем вообще разбираться в нюансах logrotate
Ротация логов в Linux кажется простой задачей: «переименовал файл, сжал, удалил старое». Но на проде именно logrotate часто становится источником тихих проблем: приложение перестаёт писать в лог (пишет в удалённый inode), ротация не срабатывает из-за прав доступа, postrotate дергает сервис слишком часто, а copytruncate незаметно теряет строки в моменты пиков.
Ниже разберём самые частые грабли вокруг logrotate: права/владельцы, директивы create и su, режим copytruncate, хуки postrotate, а также практичные мелочи вроде missingok, notifempty, rotate, compress и sharedscripts.
Как работает logrotate: коротко о механике
Обычно logrotate запускается по расписанию (cron или systemd timer) и читает конфиги из /etc/logrotate.conf и /etc/logrotate.d/. Для каждого правила он решает, пора ли «крутить» лог (по времени или размеру), и выполняет шаги:
- проверяет условия (существует ли файл, не пустой ли, не ротировался ли недавно и т. п.);
- делает ротацию: переименовывает (или копирует) текущий файл в
.1, сдвигает старые.2,.3и т. д. согласноrotate; - создаёт новый файл (директива
create) или оставляет приложению самому создать новый; - при необходимости сжимает (
compress) и выполняет скрипты (postrotate,prerotateи т. п.).
Ключевой момент: большинство проблем происходит на стыке «кто владелец файла» и «кто выполняет действия logrotate».
Если логи у вас активно анализируются (например, для отчетов по трафику и аномалиям), полезно держать ротацию и права в порядке: иначе парсеры начинают «видеть дырки» или упираются в доступы. По теме анализа логов может пригодиться материал про связку goaccess, logrotate и алерты по логам.

Типовые ошибки permissions: почему “Permission denied” и “skipping”
logrotate чаще всего запускается от root. Кажется, что root может всё — но это не всегда так: безопасность в logrotate устроена жёстко, и он может отказать в ротации, если видит небезопасные права у каталога или файла. Это сделано, чтобы исключить подмену файлов/линков (класс атак через world-writable каталоги).
Самые частые симптомы:
- в debug видно «skipping … because parent directory has insecure permissions»;
- ошибка «Permission denied» при попытке создать новый файл;
- после ротации приложение не пишет в новый лог (файл создан с неправильными owner/group/mode);
- ротация отрабатывает, но
postrotateне выполняется из-за раннего выхода по ошибке.
Проверьте права: файл и каталоги по пути
Даже если сам лог-файл нормальный, проблемным может быть любой каталог на пути. Проверка, которую удобно делать первой:
namei -l /var/log/nginx/access.log
Команда покажет права на каждый каталог и на файл. Опасные варианты:
- каталог логов или его родитель имеет права
777или просто доступен на запись всем (o+w); - лог-файл принадлежит не тому пользователю, а logrotate пытается создать новый с
createбез прав; - владелец файла — root, а приложение пишет от непривилегированного пользователя (или наоборот).
Диагностика: прогон в debug и принудительный запуск
Чтобы понять, что logrotate собирается делать, полезны два режима:
logrotate -d /etc/logrotate.conf
Это «dry-run»: показывает план действий, но ничего не меняет.
logrotate -vf /etc/logrotate.conf
Это принудительный запуск (-f) с подробным выводом (-v). На проде используйте аккуратно: можно неожиданно дернуть postrotate и reload/рестарты.
create: кто создаёт новый лог и с какими правами
Директива create управляет созданием нового пустого файла после ротации (когда ротация делается переименованием). Типичный вид:
/var/log/myapp/*.log {
daily
rotate 14
missingok
notifempty
compress
create 0640 myapp adm
}
Важно понимать: если вы используете create, именно logrotate создаст новый файл и выставит права/владельца. Если create не указана, то после переименования «старого» файла приложение должно само создать новый (или продолжит писать в старый inode, если вы не сделали reload/reopen логов).
Практическая рекомендация: для большинства демонов и веб-сервисов create удобен, но только если вы точно знаете, под каким пользователем процесс пишет в лог. Ошибка в owner/group обычно выглядит как «лог замолчал».
su directive: лечим проблемы с правами без лишних привилегий
Директива su указывает, под каким пользователем и группой logrotate должен выполнять операции ротации внутри конкретного блока. Это критично, когда логи лежат в каталоге сервиса (например, в /srv) и вы не хотите расширять права каталога ради root-задачи.
Пример для приложения, которое пишет в каталог, принадлежащий пользователю myapp:
/srv/myapp/log/*.log {
daily
rotate 7
missingok
notifempty
compress
su myapp myapp
create 0640 myapp myapp
}
Чем su полезна на практике:
- не нужно делать каталог логов «широким» по правам;
- меньше риска, что
createсоздаст файл с неправильным owner/group; - логичнее с точки зрения безопасности: ротация происходит с правами сервиса, а не с максимальными привилегиями.
Нюанс: в разных дистрибутивах и версиях logrotate контекст исполнения скриптов и файловых операций может отличаться. После добавления
suобязательно проверьте реальное поведение в вашей системе черезlogrotate -dи тестовую ротацию.
copytruncate: когда выручает и чем опасен
copytruncate — популярная директива, когда сервис нельзя или неудобно заставлять переоткрывать лог-файл. Она работает так: logrotate копирует текущий лог в ротированный файл и затем обнуляет исходный файл (truncate), не меняя inode. Процесс, который держит открытый дескриптор, продолжит писать в тот же файл — просто после обнуления.
Пример:
/var/log/legacy-app.log {
size 200M
rotate 10
missingok
notifempty
compress
copytruncate
}
Главный минус copytruncate — возможная потеря строк
Между «копированием» и «truncate» есть окно времени. Если в этот момент приложение активно пишет, часть строк может:
- попасть в ротированный файл, но не попасть в текущий (или наоборот);
- попасть в текущий уже после копирования и исчезнуть после truncate.
На низкой нагрузке это почти незаметно. На высоких RPS/лог-флуде — вполне реально.
Когда copytruncate оправдан
- старое ПО, которое не умеет переоткрывать лог по сигналу/reload;
- нет возможности делать reload/рестарт (жёсткий SLA, критичные соединения);
- логирование не является источником аудита/биллинга, и потеря небольшой доли строк допустима.
Когда лучше не использовать copytruncate
- аудит/безопасность/финансы: нужна полнота событий;
- очень высокая интенсивность записи в лог;
- приложение умеет reopen/reload логов (тогда лучше классическая схема с переименованием + reload).
postrotate: что выполнять после ротации и как не «уронить» сервис
postrotate — блок команд, который logrotate выполняет после успешной ротации. Обычно здесь делают reload сервиса, чтобы он переоткрыл файлы логов и начал писать в новый файл (особенно когда не используется copytruncate).
Классический пример (перезагрузка без полноценного рестарта):
/var/log/nginx/*.log {
daily
rotate 14
missingok
notifempty
compress
delaycompress
create 0640 www-data adm
sharedscripts
postrotate
systemctl reload nginx
endscript
}
sharedscripts: чтобы postrotate не выполнялся N раз
Если в блоке указано несколько файлов (например, /var/log/nginx/*.log), то по умолчанию скрипты могут выполниться для каждого файла отдельно. Для nginx это означает несколько reload подряд. Директива sharedscripts говорит: «выполни скрипты один раз на весь блок».
Практически всегда для веб-серверов и сервисов с набором логов стоит включать sharedscripts, чтобы избежать лишних reload/дергания systemd.
Делайте postrotate «мягким»
Ошибки в postrotate — частая причина «странной» ротации. Рабочие правила:
- используйте
reloadвместоrestart, если сервис это поддерживает; - не пишите интерактивные команды;
- не логируйте вывод скрипта в тот же каталог/файл, который крутите, чтобы случайно не устроить рекурсию;
- проверяйте окружение: в контейнерах
systemctlможет отсутствовать, тогда нужен другой механизм reopen.
missingok и notifempty: чтобы ротация не мешала жизни
Эти две директивы часто стоит включать по умолчанию для «необязательных» логов.
missingok— не считать ошибкой отсутствие файла. Полезно, когда лог создаётся не всегда (например, только при включённом debug) или сервис иногда выключен.notifempty— не ротировать пустые файлы. Это снижает «мусор» из нулевых архивов и лишних действий.
Комбинация missingok notifempty обычно делает поведение logrotate более предсказуемым.
rotate, compress и delaycompress: хранение и нагрузка
Базовые директивы хранения:
rotate— сколько архивов хранить (например,rotate 14= две недели приdaily);compress— сжимать ротированные логи;delaycompress— не сжимать самый свежий.1до следующей ротации.
delaycompress полезен, когда какие-то процессы ещё могут читать свежий ротированный лог (сборщики метрик, парсеры, диагностика), либо если вы делаете reload, но опасаетесь гонок чтения.
Также помните про CPU: сжатие больших логов в пиковые часы может давать заметный всплеск нагрузки. В таких случаях лучше ротировать по размеру, либо подбирать частоту так, чтобы компрессия попадала в «тихие» окна.
Практический шаблон: безопасная ротация без copytruncate
Если сервис умеет перечитывать или переоткрывать логи по reload (или по сигналу), обычно лучше избегать copytruncate и использовать «классическую» схему: переименование + create + postrotate reload.
/var/log/myservice/*.log {
daily
rotate 14
missingok
notifempty
compress
delaycompress
su myservice myservice
create 0640 myservice myservice
sharedscripts
postrotate
systemctl reload myservice
endscript
}
Что здесь решает проблемы заранее:
suиcreateфиксируют permissions и владельцев;sharedscriptsпредотвращает многократный reload;missingokиnotifemptyубирают ложные ошибки и пустые ротации;compressэкономит место, аdelaycompressснижает риск конфликтов со свежим архивом.
Если без copytruncate никак: минимизируем риски
Когда вы вынуждены использовать copytruncate, разумно хотя бы:
- ротировать по размеру, чтобы операция копирования была быстрее и окно потерь — меньше;
- держать разумное число
rotate, достаточное для расследований; - включить
compress, чтобы не съесть диск; - учесть буферизацию: если приложение пишет большими буферами и редко flush, в момент truncate можно потерять не только строки, но и куски буфера.
Пример более «бережной» конфигурации:
/var/log/legacy-app.log {
size 100M
rotate 20
missingok
notifempty
compress
copytruncate
}
Чек-лист: что проверить, если ротация не работает или работает странно
План действий:
logrotate -d /etc/logrotate.conf.Тест с подробным выводом:
logrotate -vf /etc/logrotate.conf(осторожно сpostrotate).Права каталогов по пути:
namei -l. Ищите world-writable и неожиданных владельцев.Корректность
create: owner/group должны совпадать с тем, кто пишет в лог.Если есть проблемы с доступом и «insecure permissions» — добавьте
suв блок.Если сервис после ротации пишет «в никуда» — вам нужен
postrotate(reload/reopen), либоcopytruncateкак компромисс.Если
postrotateвыполняется слишком много раз — включитеsharedscripts.Если плодятся пустые архивы — включите
notifempty.Если иногда файла нет — включите
missingok.
Итог
В logrotate важны не столько «daily и rotate», сколько детали: кому принадлежат файлы, под кем выполняются операции (su), кто создаёт новый лог (create), как сервис переоткрывает дескрипторы (postrotate), и не прячете ли вы проблемы под copytruncate ценой потерь событий.
Если вы один раз аккуратно настроите права и хук переоткрытия логов, logrotate станет «скучной» системой — а это лучший комплимент для продовой инфраструктуры, будь то сервер на VDS или типовой веб-проект на виртуальном хостинге.



