Настройка ротации логов Nginx в Ubuntu

Пошаговая настройка ротации access.log и error.log Nginx через logrotate с проверкой, хранением архивов и безопасным принудительным запуском.

Журналы Nginx постоянно увеличиваются по мере поступления запросов и появления ошибок. Без ротации файлы access.log и error.log могут занять значительную часть диска.

В Ubuntu для автоматической ротации журналов обычно используется logrotate.

В этой инструкции рассматривается только настройка и проверка ротации логов Nginx.

Проверено на: Ubuntu Server 24.04 LTS
Уровень сложности: начальный
Время выполнения: около 15–20 минут
Требуемый доступ: пользователь с правами sudo

Что будет настроено

После выполнения инструкции:

  • будет проверена стандартная конфигурация logrotate для Nginx;
  • будут настроены периодичность и срок хранения;
  • старые журналы будут сжиматься;
  • будет проверено корректное переоткрытие логов Nginx;
  • будет выполнен безопасный тест;
  • будет показана ротация отдельных журналов виртуального хоста;
  • будут разобраны типичные ошибки.

Основные журналы Nginx

Стандартные файлы:

/var/log/nginx/access.log
/var/log/nginx/error.log

Для отдельных виртуальных хостов могут использоваться:

/var/log/nginx/example.com.access.log
/var/log/nginx/example.com.error.log

Проверьте каталог:

sudo ls -lah /var/log/nginx/

Проверка размера журналов

sudo du -h /var/log/nginx/*

Сортировка по размеру:

sudo du -ah /var/log/nginx/ |
sort -h |
tail -20

Проверка свободного места

df -h

Проверьте файловую систему, где расположен:

/var/log

Если корневой раздел почти заполнен, сначала освободите место и только потом запускайте принудительную ротацию.

Проверка пакета logrotate

dpkg -l |
grep logrotate

Проверьте версию:

logrotate --version

Если пакет отсутствует:

sudo apt update
sudo apt install -y logrotate

Проверка стандартной конфигурации Nginx

sudo cat /etc/logrotate.d/nginx

На стандартной установке Ubuntu пакет Nginx обычно создаёт отдельный файл:

/etc/logrotate.d/nginx

Типовая конфигурация

Она может выглядеть примерно так:

/var/log/nginx/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        if [ -f /run/nginx.pid ]; then
            kill -USR1 $(cat /run/nginx.pid)
        fi
    endscript
}

Конкретное содержимое зависит от пакета и версии Ubuntu.

Разбор параметров

daily

daily

Ротация выполняется ежедневно.

Альтернативы:

weekly
monthly

rotate

rotate 14

Хранить 14 архивных копий.

При ежедневной ротации это примерно две недели истории.

compress

compress

Старые журналы сжимаются через gzip.

Пример:

access.log.2.gz

delaycompress

delaycompress

Самый свежий архив не сжимается сразу.

Пример:

access.log.1
access.log.2.gz

Это удобно, если процесс ещё может кратковременно держать старый файл открытым.

missingok

missingok

Отсутствие журнала не считается ошибкой.

notifempty

notifempty

Пустой файл не ротируется.

create

create 0640 www-data adm

После ротации создаётся новый файл с указанными:

  • правами;
  • владельцем;
  • группой.

Проверьте фактические права существующих файлов:

sudo stat   /var/log/nginx/access.log   /var/log/nginx/error.log

sharedscripts

sharedscripts

Секция postrotate выполняется один раз для всей группы файлов, а не отдельно для каждого журнала.

postrotate

После переименования логов Nginx должен закрыть старые файловые дескрипторы и открыть новые.

Обычно используется сигнал:

USR1

Пример:

kill -USR1 "$(cat /run/nginx.pid)"

Это не останавливает веб-сервер.

Почему нельзя просто переименовать лог

Если только переименовать:

access.log → access.log.1

процесс Nginx может продолжить писать в старый открытый файл.

Поэтому после ротации необходимо выполнить переоткрытие журналов.

Проверка PID Nginx

cat /run/nginx.pid

Проверьте процесс:

ps -fp "$(cat /run/nginx.pid)"

Создание резервной копии конфигурации

sudo cp   /etc/logrotate.d/nginx   /etc/logrotate.d/nginx.backup-$(date +%F-%H%M%S)

Проверьте:

sudo ls -l /etc/logrotate.d/nginx*

Рекомендуемая базовая политика

Для обычного небольшого сайта:

daily
rotate 14
compress
delaycompress
notifempty

Это обеспечивает около двух недель ежедневных журналов.

Хранение за 30 дней

daily
rotate 30

Старые файлы будут храниться примерно месяц.

Еженедельная ротация

weekly
rotate 8

Это примерно восемь недель истории.

Для активных сайтов еженедельная ротация может создавать слишком большие файлы.

Ротация по размеру

Можно добавить:

size 100M

Но size меняет логику запуска относительно временных директив.

Для сценария «ежедневно или при достижении размера» используется:

maxsize 100M

Пример:

daily
maxsize 100M
rotate 14

Разница size и maxsize

size

Ротация выполняется только при достижении указанного размера.

Временной интервал может фактически игнорироваться.

maxsize

Позволяет выполнить ротацию раньше планового срока, если файл стал слишком большим.

Для ежедневной политики обычно удобнее maxsize.

Пример итоговой конфигурации

/var/log/nginx/*.log {
    daily
    maxsize 100M
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        if [ -f /run/nginx.pid ]; then
            kill -USR1 $(cat /run/nginx.pid)
        fi
    endscript
}

Перед применением проверьте владельца и группу журналов на своём сервере.

Проверка синтаксиса logrotate

sudo logrotate -d /etc/logrotate.d/nginx

Параметр:

-d

включает debug mode.

В этом режиме реальные файлы не ротируются.

Расширенный debug

sudo logrotate -dv /etc/logrotate.d/nginx

Проверьте:

  • какие файлы найдены;
  • нужна ли ротация;
  • какой шаблон применяется;
  • нет ли ошибки синтаксиса;
  • корректен ли postrotate.

Проверка общей конфигурации

sudo logrotate -d /etc/logrotate.conf

Это проверяет все подключённые правила.

Проверка state-файла

Logrotate хранит дату последней ротации в state-файле.

Обычно:

/var/lib/logrotate/status

Проверьте:

sudo grep nginx   /var/lib/logrotate/status

Формат может отличаться в зависимости от версии.

Принудительный тест

Перед тестом проверьте текущие файлы:

sudo ls -lah /var/log/nginx/

Запустите:

sudo logrotate -f /etc/logrotate.d/nginx

Параметр:

-f

принудительно выполняет ротацию.

Проверка результата

sudo ls -lah /var/log/nginx/

Ожидаются файлы:

access.log
access.log.1
error.log
error.log.1

При следующем цикле старые файлы будут сжаты.

Проверка записи в новый журнал

Создайте запрос:

curl -I http://127.0.0.1

Проверьте:

sudo tail -5 /var/log/nginx/access.log

Новая запись должна появиться в текущем access.log, а не в access.log.1.

Проверка открытых файлов процесса

sudo lsof -p "$(cat /run/nginx.pid)" |
grep '/var/log/nginx'

Также проверьте worker processes:

pgrep nginx
sudo lsof -c nginx |
grep '/var/log/nginx'

Активные процессы должны писать в текущие файлы без суффикса .1.

Проверка службы logrotate

В современных системах logrotate обычно запускается через systemd timer.

Проверьте:

systemctl status logrotate.timer --no-pager

Проверьте автозапуск:

systemctl is-enabled logrotate.timer

Следующий запуск

systemctl list-timers   --all |
grep logrotate

Проверка журнала systemd

sudo journalctl -u logrotate.service   -n 100   --no-pager

Проверка timer:

sudo journalctl -u logrotate.timer   -n 100   --no-pager

Ручной запуск общей службы

sudo systemctl start logrotate.service

Проверьте:

systemctl status logrotate.service --no-pager

Служба обычно имеет состояние:

inactive (dead)

после успешного разового выполнения. Это нормально для oneshot-сервиса.

Отдельные журналы виртуальных хостов

Если в Nginx настроено:

access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;

шаблон:

/var/log/nginx/*.log

обычно включает эти файлы автоматически.

Проверьте debug-режимом:

sudo logrotate -d /etc/logrotate.d/nginx |
grep example.com

Журналы в другом каталоге

Если сайт пишет в:

/var/log/nginx/example.com/access.log

стандартный шаблон:

/var/log/nginx/*.log

не захватит вложенный каталог.

Создайте отдельное правило.

Отдельное правило для каталога сайта

Создайте:

sudo nano   /etc/logrotate.d/nginx-example

Добавьте:

/var/log/nginx/example.com/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        if [ -f /run/nginx.pid ]; then
            kill -USR1 $(cat /run/nginx.pid)
        fi
    endscript
}

Проверка отдельного правила

sudo logrotate -d   /etc/logrotate.d/nginx-example

Принудительный тест:

sudo logrotate -f   /etc/logrotate.d/nginx-example

Исключение дублирующихся шаблонов

Один и тот же файл не должен попадать одновременно в два правила.

Проверьте:

sudo grep -Rni   '/var/log/nginx'   /etc/logrotate.conf   /etc/logrotate.d/

Дублирование может вызвать ошибку:

duplicate log entry

Настройка владельца и группы

Проверьте:

sudo ls -l /var/log/nginx/

Стандартно журналы могут иметь:

www-data adm

или другое сочетание в зависимости от пакета.

В create укажите фактические значения.

su в logrotate

Для некоторых нестандартных каталогов требуется:

su www-data adm

Пример:

/var/log/nginx/custom/*.log {
    su www-data adm
    daily
    rotate 14
    compress
}

Не добавляйте su без необходимости и проверки прав каталога.

Права на каталог

sudo stat /var/log/nginx

Проверьте:

  • владельца;
  • группу;
  • права;
  • доступ процесса Nginx;
  • доступ logrotate.

Проверка SELinux и AppArmor

На стандартной Ubuntu чаще используется AppArmor.

Если журналы перенесены в нестандартный каталог и Nginx не может открыть новый файл, проверьте системный журнал:

sudo journalctl -k   -n 100   --no-pager

Также проверьте:

sudo journalctl -u nginx   -n 100   --no-pager

Ротация access.log отдельно от error.log

Можно создать разные политики.

Пример для access log:

/var/log/nginx/*access.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        if [ -f /run/nginx.pid ]; then
            kill -USR1 $(cat /run/nginx.pid)
        fi
    endscript
}

Пример для error log:

/var/log/nginx/*error.log {
    weekly
    rotate 8
    compress
    delaycompress
    missingok
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        if [ -f /run/nginx.pid ]; then
            kill -USR1 $(cat /run/nginx.pid)
        fi
    endscript
}

Но разделять правила стоит только при реальной необходимости.

dateext

Для архивов с датой:

dateext

Пример имён:

access.log-20260726.gz

Дополнительно можно задать:

dateformat -%Y%m%d

Пример с dateext

daily
rotate 30
compress
delaycompress
dateext
dateformat -%Y%m%d

Не меняйте схему имён без учёта скриптов, которые читают старые журналы.

maxage

Можно удалять архивы старше определённого количества дней:

maxage 30

Пример:

daily
rotate 30
maxage 30

rotate и maxage работают совместно, но итоговое удаление зависит от фактических запусков logrotate.

Запрет ротации пустых файлов

notifempty

Пустой файл останется без создания пустого архива.

Сжатие через другой алгоритм

По умолчанию используется gzip.

Менять алгоритм обычно не требуется.

Совместимость стандартных инструментов и минимальная сложность важнее небольшой экономии места.

Проверка архивного журнала

Для .gz:

sudo zcat   /var/log/nginx/access.log.2.gz |
head

Просмотр без распаковки:

sudo zless   /var/log/nginx/access.log.2.gz

Поиск:

sudo zgrep   ' 500 '   /var/log/nginx/access.log.*.gz |
tail

Поиск по текущим и архивным логам

Текущий файл:

sudo grep   ' 404 '   /var/log/nginx/access.log |
tail

Архив без сжатия:

sudo grep   ' 404 '   /var/log/nginx/access.log.1 |
tail

Сжатые архивы:

sudo zgrep   ' 404 '   /var/log/nginx/access.log.*.gz |
tail

Ротация не заменяет централизованный сбор

Logrotate решает локальную задачу управления файлами.

Он не заменяет:

  • Loki;
  • Elasticsearch;
  • Graylog;
  • удалённый syslog;
  • SIEM;
  • резервное хранение журналов.

Если журналы нужны для аудита, отправляйте их на отдельный сервер до удаления локальных копий.

Не удаляйте активный лог вручную

Плохой вариант:

sudo rm /var/log/nginx/access.log

Nginx может продолжить писать в удалённый inode, а место не освободится до закрытия файлового дескриптора.

Проверьте удалённые открытые файлы:

sudo lsof +L1 |
grep nginx

Освобождение места после ручного удаления

Если лог был удалён, но процесс продолжает держать его открытым:

sudo kill -USR1 "$(cat /run/nginx.pid)"

После этого Nginx переоткроет журналы.

Перед сигналом проверьте PID и конфигурацию.

Не обнуляйте файлы без причины

Команда:

sudo truncate -s 0 /var/log/nginx/access.log

может временно освободить место, но нарушает нормальную историю журналов.

Используйте её только как аварийную меру, а затем исправьте ротацию.

Ошибка permission denied

Проверьте:

sudo ls -ld /var/log/nginx
sudo ls -l /var/log/nginx

Проверьте параметры:

create
su

Проверьте журнал службы:

sudo journalctl -u logrotate.service   -n 100   --no-pager

Ошибка duplicate log entry

Найдите дубли:

sudo grep -Rni   '/var/log/nginx'   /etc/logrotate.conf   /etc/logrotate.d/

Один файл должен обрабатываться одним правилом.

После ротации Nginx пишет в .1

Проверьте postrotate.

Вручную переоткройте:

sudo kill -USR1 "$(cat /run/nginx.pid)"

Проверьте:

sudo lsof -c nginx |
grep '/var/log/nginx'

Новый access.log не создаётся

Проверьте:

  • директиву create;
  • права каталога;
  • пользователя Nginx;
  • PID;
  • postrotate;
  • активную конфигурацию Nginx.

Создайте тестовый запрос:

curl -I http://127.0.0.1

Ротация не запускается ежедневно

Проверьте timer:

systemctl status logrotate.timer --no-pager

Проверьте календарь:

systemctl list-timers   --all |
grep logrotate

Проверьте журнал:

sudo journalctl -u logrotate.service   --since today   --no-pager

Файл превысил maxsize, но не ротируется сразу

Logrotate не следит за файлами постоянно.

maxsize проверяется только во время запуска logrotate.

Если timer выполняется раз в сутки, файл может превысить лимит до следующего запуска.

Для более частой проверки потребуется отдельный timer, но это уже отдельная задача.

Архивы не сжимаются

При наличии:

delaycompress

самый свежий архив остаётся несжатым до следующей ротации.

Это нормальное поведение.

Проверка после следующего цикла

sudo ls -lah /var/log/nginx/

Ожидаемая структура:

access.log
access.log.1
access.log.2.gz
error.log
error.log.1
error.log.2.gz

Откат конфигурации

Найдите резервную копию:

sudo ls -1t   /etc/logrotate.d/nginx.backup-* |
head

Восстановите:

sudo cp   /etc/logrotate.d/nginx.backup-DATE   /etc/logrotate.d/nginx

Замените DATE фактическим именем файла.

Проверьте:

sudo logrotate -d /etc/logrotate.d/nginx

Безопасный порядок настройки

  1. Проверить размер журналов.
  2. Проверить свободное место.
  3. Изучить текущее правило.
  4. Создать резервную копию.
  5. Настроить периодичность и хранение.
  6. Проверить владельца и группу.
  7. Проверить postrotate.
  8. Запустить debug mode.
  9. Выполнить принудительную ротацию.
  10. Создать тестовый HTTP-запрос.
  11. Убедиться, что запись идёт в новый лог.
  12. Проверить systemd timer.

Быстрый набор команд

Проверить размер:

sudo du -h /var/log/nginx/*

Проверить правило:

sudo cat /etc/logrotate.d/nginx

Тест без изменений:

sudo logrotate -d /etc/logrotate.d/nginx

Принудительная ротация:

sudo logrotate -f /etc/logrotate.d/nginx

Проверка новых файлов:

sudo ls -lah /var/log/nginx/

Проверка записи:

curl -I http://127.0.0.1
sudo tail -5 /var/log/nginx/access.log

Итог

После выполнения инструкции:

  • проверена стандартная конфигурация logrotate;
  • настроены периодичность и количество архивов;
  • включено сжатие старых журналов;
  • проверено переоткрытие файлов через USR1;
  • выполнена безопасная принудительная ротация;
  • проверена запись в новые журналы;
  • рассмотрены отдельные журналы виртуальных хостов;
  • разобраны типичные ошибки.

На этом базовую серию статей по Nginx можно считать завершённой.

← Предыдущая статья Перенаправление с www на основной домен в Nginx Следующая статья → Установка PostgreSQL в Ubuntu