Logrotate — стандартный инструмент Linux для управления лог-файлами. Автоматически архивирует, сжимает и удаляет старые логи по расписанию.
Как работает logrotate
- Запускается через cron (
/etc/cron.daily/logrotate) - Читает конфиги из
/etc/logrotate.confи/etc/logrotate.d/ - Для каждого лога применяет правила: rotate, compress, delete
Конфиг для Nginx
sudo nano /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
nginx -s reopen
endscript
}
Конфиг для вашего приложения
sudo nano /etc/logrotate.d/myapp
/var/www/myapp/logs/*.log {
weekly
rotate 8
compress
delaycompress
missingok
notifempty
create 0644 www-data www-data
}
Тестирование и запуск
# Тест без реального выполнения
sudo logrotate -d /etc/logrotate.d/nginx
# Принудительный запуск
sudo logrotate -f /etc/logrotate.conf
# Проверить статус
sudo cat /var/lib/logrotate/status
| Директива | Значение |
|---|---|
| daily/weekly/monthly | Частота ротации |
| rotate N | Хранить N архивов |
| compress | Сжимать gzip |
| missingok | Не ошибаться если файл отсутствует |
df -h. Если /var заполнен — запустите logrotate -f /etc/logrotate.conf принудительно.Разбор типичных ошибок
Ошибка error: skipping "/var/log/nginx/access.log" because parent directory has insecure permissions появляется, если каталог с логами доступен на запись группе или всем — logrotate из соображений безопасности отказывается работать с такими путями, чтобы кто-то не подменил лог символьной ссылкой на системный файл.
error: skipping "/var/log/nginx/access.log" because parent directory has insecure permissions
(It's world writable or writable by group which is not "root")
Решение — выставить права каталога chmod 755 /var/log/nginx, а не расширять список доверенных групп в /etc/logrotate.conf: это дыра в безопасности, а не обход бага. Флаг su в правиле (su www-data www-data) иногда используют вместо исправления прав, но он лишь меняет пользователя, от имени которого logrotate выполняет ротацию, и не отменяет проверку безопасности самого каталога.
После настройки лог всё равно растёт бесконечно, хотя правило вроде бы верное. Частая причина — процесс держит старый файловый дескриптор открытым даже после ротации: без postrotate со свежим сигналом переоткрытия лог-файла (nginx -s reopen, systemctl reload myapp) приложение продолжает писать в уже переименованный и заброшенный файл access.log.1, а новый access.log остаётся пустым.
directory vs default: где искать проблему
| Симптом | Вероятная причина | Проверка |
|---|---|---|
| Правило не срабатывает вообще | Синтаксическая ошибка в конфиге | logrotate -d покажет ошибку парсинга |
| Файл ротируется, но не сжимается | Директива compress отсутствует или закомментирована | Проверить итоговый конфиг построчно |
| Новый файл пустой, старый растёт | Приложение не переоткрыло дескриптор | Проверить наличие и содержимое postrotate |
| «insecure permissions» | Права каталога логов слишком открытые | ls -ld /var/log/имя-каталога |
Когда logrotate не подходит
- Приложение уже пишет логи через
journald— тогда ротацией и хранением занимаетсяjournalctl --vacuum-size/--vacuum-time, а не logrotate, дублировать оба механизма избыточно. - Нужна централизованная агрегация логов с нескольких серверов и полнотекстовый поиск — logrotate только локально управляет файлами, для агрегации нужен стек вроде Grafana Loki.
- Логи должны ротироваться по размеру в реальном времени, а не раз в сутки по крону — logrotate запускается по расписанию cron, а не следит за файлом непрерывно; для мгновенной ротации по размеру нужен инструмент вроде
logrotateс более частым запуском или приложение с собственной ротацией. - Контейнеризированное приложение пишет логи в stdout, а не в файл — ротацией stdout-логов управляет сам движок контейнеров через драйвер логирования (
json-fileс лимитом размера), а не logrotate внутри контейнера.
Проверка результата
- Проверьте синтаксис без реальной ротации:
logrotate -d /etc/logrotate.d/nginx— в выводе не должно быть строк сerror. - Принудительно выполните ротацию:
logrotate -f /etc/logrotate.d/nginxи убедитесь, что появился файл вродеaccess.log.1.gz. - Проверьте, что приложение продолжает писать в новый файл, а не в старый:
tail -f /var/log/nginx/access.logдолжен показывать новые запросы сразу после ротации. - Проверьте статус последнего запуска:
cat /var/lib/logrotate/status | grep nginxдолжен показывать сегодняшнюю дату.
Освобождение места на диске от уже накопленных старых логов, включая экстренную очистку без правки конфигов, разобрано отдельно в статье про logrotate на VPS. Для логов systemd-сервисов без отдельных файлов на диске см. статью про journalctl и rsyslog.
Проверить существующие правила
# Посмотреть все конфиги logrotate
ls /etc/logrotate.d/
# Протестировать без реальной ротации
sudo logrotate --debug /etc/logrotate.conf
Создать правило для своего приложения
# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily # Ротация каждый день
missingok # Не ошибаться если файл отсутствует
rotate 14 # Хранить 14 архивов
compress # Сжать gzip
delaycompress # Не сжимать последний архив
notifempty # Не ротировать пустые файлы
create 0640 www-data www-data # Права нового файла
postrotate
systemctl reload nginx > /dev/null 2>&1 || true
endscript
}
Параметры logrotate
| Параметр | Описание |
|---|---|
| daily/weekly/monthly | Период ротации |
| rotate N | Количество архивов |
| size 100M | Ротация по размеру |
| compress | Сжать gzip |
| maxage 30 | Удалять архивы старше 30 дней |
| sharedscripts | postrotate выполняется один раз |
Принудительная ротация прямо сейчас
sudo logrotate --force /etc/logrotate.d/myapp
Освобождение места от старых логов
# Найти большие лог-файлы
sudo find /var/log -name "*.log" -size +100M
# Очистить файл без удаления (процесс продолжает писать)
sudo truncate -s 0 /var/log/nginx/access.log
# Или через journald
sudo journalctl --vacuum-size=500M
du vs df: как быстро понять, где место
| Симптом | Команда для диагностики | Что показывает |
|---|---|---|
| df видит меньше свободного места, чем du | lsof +L1 | Удалённые, но всё ещё открытые файлы |
| Непонятно, какой каталог самый тяжёлый | du -h --max-depth=1 /var/log | sort -rh | Размер каждого подкаталога логов |
| Логи растут быстрее, чем ожидалось | watch -n 5 'du -sh /var/log/nginx' | Скорость прироста в реальном времени |
Когда обычной ротации мало
- Диск уже заполнен под завязку прямо сейчас, а не ротация нужна на будущее —
logrotate --forceне поможет мгновенно, если виноваты открытые удалённые файлы; нужно сначала перезапустить держащие их процессы. - Логов накапливается больше, чем позволяет держать диск даже со сжатием — нужен вынос логов на отдельный том, в объектное хранилище или в централизованную систему вроде Grafana Loki, а не более агрессивная ротация на том же диске.
- Нужно найти конкретную причину аномального роста логов, а не просто освободить место — это уже задача анализа самих логов на ошибки и подозрительный трафик, а не ротации.