Ротация логов на Ubuntu 24.04: проверяем, что она вообще идёт
Полез проверить, ротируются ли логи на свежей noble — и обнаружил, что половина моих мысленных команд устарела. На 24.04 logrotate больше не дёргается классическим cron'ом. Файла
/etc/cron.daily/logrotate нет, всё переехало на systemd-таймер. Если по старой памяти искать ротацию в cron — найдёшь пустоту и сделаешь неверный вывод, что она сломана.Ниже — порядок, в котором я проверяю ротацию, чтобы не гадать. И пара граблей, на которые наступил сам.
1. Жив ли таймер
Сначала смотрим на источник запуска. Нет таймера — нет ротации, и дальше копать конфиги бессмысленно.
Bash:
systemctl status logrotate.timer
systemctl list-timers logrotate.timer
В выводе
list-timers интересуют две колонки: NEXT (когда сработает) и LAST (когда отработал в прошлый раз). Свежий LAST — таймер живёт. Пустой или древний — чини таймер, а не правила.
Код:
NEXT LEFT LAST PASSED UNIT
Thu 2026-06-18 00:00:00 MSK 4h 11min Wed 2026-06-17 00:00:01 MSK 19h ago logrotate.timer
2. Debug-прогон — главный инструмент
Самое полезное. Ничего не ротирует, не трогает файлы, только показывает, какое решение logrotate принял бы по каждому логу прямо сейчас и почему:
Bash:
logrotate --debug /etc/logrotate.conf
Читаем по каждому правилу. Либо
log does not need rotating с причиной (не дорос до size, период ещё не наступил, лог пуст), либо rotating log .... Это и есть ответ на вопрос «сработает или нет, и почему нет».
Код:
considering log /var/log/nginx/access.log
Now: 2026-06-17 19:48
Last rotated at 2026-06-17 00:00
log does not need rotating (log has been rotated at 2026-06-17 00:00, which is less than a day ago)
Точечно по одному сервису тоже можно, но с оговоркой — см. следующий шаг.
Bash:
logrotate --debug /etc/logrotate.d/nginx
3. Где меня укусило: одиночный конфиг теряет глобальные настройки
Решил форсом проверить, что ротация
php8.5-fpm.log реально отрабатывает:
Bash:
logrotate --force /etc/logrotate.d/php8.5-fpm
И получил:
Код:
error: skipping "/var/log/php8.5-fpm.log" because parent directory has insecure
permissions (It's world writable or writable by group which is not "root")
Set "su" directive in config file to tell logrotate which user/group should be
used for rotation.
Первая мысль — ротация сломана. Нет. Когда натравливаешь logrotate напрямую на файл из
/etc/logrotate.d/, он не читает /etc/logrotate.conf — а там лежат глобальные дефолты, в том числе su root adm. Без него logrotate видит, что родительский /var/log групп-овнится syslog (штатные 775 root:syslog — «писабелен группой не-root»), и из соображений безопасности отказывается ротировать.В реальном плановом прогоне (через
/etc/logrotate.conf) глобальный su действует, и тот же лог ротируется штатно. Проверяется одной строкой:
Bash:
grep -n su /etc/logrotate.conf
Есть
su root adm — всё в порядке, ложная тревога. Отсюда правило: для боевой проверки гоняй весь /etc/logrotate.conf, а не отдельный файл — иначе теряешь su, create, дефолтные rotate/weekly и ловишь несуществующие ошибки.
Bash:
# так — с глобалками, как на проде
logrotate --force /etc/logrotate.conf
--debug /etc/logrotate.d/nginx из шага 2 у меня сработал только потому, что stanza nginx самодостаточна и от глобального su не зависит. Везёт не всегда.4. Кто когда ротировался — state-файл
logrotate помнит последнюю ротацию каждого файла в state. Путь не угадываем — его logrotate сам печатает первой строкой debug-вывода:
Код:
Reading state from file: /var/lib/logrotate/status
На Ubuntu это
/var/lib/logrotate/status (именно status, без префикса — на этом я сам споткнулся, искал несуществующий logrotate.status):
Bash:
cat /var/lib/logrotate/status
Каждая строка —
"путь" дата. Дата древняя или файла в списке вообще нет — значит, он не ротируется, что бы ты ни думал про наличие правила.5. У кого нет правила — и кто на самом деле жрёт диск
Главная засада не в сломанной ротации, а в логах, для которых правила нет вовсе. Смотрим, кто крупнейший:
Bash:
du -ah /var/log 2>/dev/null | sort -rh | head -20
У меня 1.3 ГБ из 1.4 — это
/var/log/journal. Проверяем, есть ли на него правило:
Bash:
grep -rl 'journal' /etc/logrotate.d/ # пусто
Пусто — и так и должно быть. journald ротирует себя сам, logrotate его не трогает в принципе. Ретеншн журнала живёт в
/etc/systemd/journald.conf, дефолт — до 10% ФС или 4 ГБ. Прижать:
Bash:
# разово почистить
journalctl --vacuum-size=500M # или: --vacuum-time=14d
# навсегда — в /etc/systemd/journald.conf:
# SystemMaxUse=500M
systemctl restart systemd-journald
Мораль: файл большой, его пути нет ни в
/etc/logrotate.d/, ни в state — он не под logrotate. Либо им рулит свой демон (journald), либо никто, и тогда он растёт до упора.По сервисам: у
nginx в postrotate должен быть kill -USR1 мастеру (иначе пишет в удалённый inode — место не освобождается). Под PHP-шный error_log() в файл нужен copytruncate: скрипт держит дескриптор открытым и по сигналу переоткрывать не умеет. У mysql ротация работает только при живом доступе для mysqladmin flush-logs.Нюанс именно noble
Раз запуск через systemd, ошибки postrotate-скриптов в
--debug не видны — их ловим в журнале самого прогона:
Bash:
journalctl -u logrotate.service --since "2 days ago"
Если там только
Starting/Finished без ошибок — сервис отрабатывает чисто.Короткий чеклист
systemctl list-timers logrotate.timer— таймер жив, LAST свежийlogrotate --debug /etc/logrotate.conf— что решит по каждому логу (весь конфиг, не отдельный файл)cat /var/lib/logrotate/status— даты последних ротаций (путь бери из строкиReading state from file:)du -ah /var/log | sort -rh | head— кто растёт; крупное часто рулится не logrotate (journald)journalctl -u logrotate.service— ошибки postrotate
Пять команд — и понятно, ротируется ли всё, что должно, не пухнет ли молча то, для чего правила никто не написал, и не пугаешься ли ты ложной ошибки от форса одиночного конфига.