Логротация: почему логи игрового сервера нельзя игнорировать
Классическая история: сервер работал месяцами без единой перезагрузки, все довольны, а потом внезапно падает запись мира, RCON перестаёт отвечать, а df -h показывает 0% свободного места. Виновник — не хак и не баг движка, а забытая папка logs/, которая тихо росла все эти месяцы и однажды съела весь диск. Логротация — это не про порядок ради порядка, а про то, чтобы такого вечера у вас никогда не было. Разберём, как настроить logrotate под игровой сервер, сколько логов реально нужно хранить и почему сжатие старых файлов — не опция, а обязательный пункт чек-листа.
Содержание
- Почему логи вообще становятся проблемой
- Как это устроено у разных игр по умолчанию
- Устанавливаем и настраиваем logrotate
- Ключевая грабля: copytruncate или postrotate
- Если игра не пишет в файл: логируем stdout через systemd
- Сколько хранить: баланс между диском и расследованием инцидентов
- Мониторинг места на диске как страховка
Почему логи вообще становятся проблемой
Игровой сервер пишет в лог гораздо больше, чем кажется на первый взгляд. Каждый коннект и дисконнект игрока, каждая ошибка плагина, каждый чат-месседж (если включено логирование чата), каждая RCON-команда админа — всё это строки в файле, который растёт без остановки, если никто не следит.
На спокойном сервере на 10-20 игроков лог может расти на десятки мегабайт в день. На загруженной сборке с активным античитом, подробным логированием плагинов (Oxide/uMod на Rust, Paper с включёнными таймингами) или RP-сервером FiveM, где логируется каждое действие в тикет-системе, счёт может идти на сотни мегабайт в сутки. Без ротации файл latest.log или server.log просто копится месяцами.
Проблема не только в занятом месте:
- Диск переполняется незаметно — сервер продолжает работать, пока не кончится место, и тогда падает уже не только логирование, а запись сохранений мира, что куда хуже.
- Большой лог тормозит диагностику — открыть файл на 5 ГБ текстовым редактором или прогнать через
grepзаметно дольше, чем читать ротированный кусок за один день. - Некоторые процессы пишут в лог синхронно — на медленном диске (особенно на бюджетных VPS с сетевым хранилищем) это может просаживать тикрейт при активном логировании.
- История инцидентов теряется — если файл не архивируется, а перезаписывается при рестарте, вы теряете улики ровно тогда, когда они нужнее всего — сразу после краша.
Если сервер уже упал и вы разбираетесь, что произошло, — сначала прочитайте как читать логи и искать причину краша, а логротацию настройте сразу после, чтобы в следующий раз было что читать.
Как это устроено у разных игр по умолчанию
Прежде чем городить свою ротацию, стоит понять, что уже делает сама игра — часто дублировать не нужно, а нужно только дополнить.
| Игра/движок | Встроенная ротация | Что нужно добавить |
|---|---|---|
| Minecraft (Java, Forge/Fabric/Paper) | Да, latest.log архивируется в logs/YYYY-MM-DD-N.log.gz при каждом рестарте | Ничего критичного, но старые .gz тоже стоит чистить по возрасту |
| Rust | Нет, пишет в stdout | Обязательно — либо logrotate, либо перенаправление с ротацией на уровне systemd |
| CS2, TF2, Left 4 Dead 2 (Source) | Нет, файлы L<дата>.log копятся бесконечно | Обязательно чистить/архивировать по возрасту |
| ARK: Survival (Ascended) | Частично, но ShooterGame.log может расти без ограничения при долгом аптайме | Желательно |
| Project Zomboid | Нет отдельного встроенного лимита на размер | Обязательно |
| FiveM (GTA V) | Зависит от ресурсов сервера, ESX/QBCore обычно пишут свои файлы без лимита | Обязательно, особенно логи тикет-систем и античита |
| Discord-бот, Telegram-бот управления сервером | Обычно нет, если это ваш собственный скрипт | Обязательно, если бот активно логирует |
Даже там, где игра сама архивирует старые сессии (Minecraft), она обычно не удаляет их совсем — просто оставляет расти папку logs/ в виде десятков .gz-файлов за месяцы. Это уже не критично для диска, но за годы набегает объём, так что возрастной лимит не помешает и там.
Нужен игровой сервер?
MAATRIX GAMES — 45+ игр, деплой за минуты, DDoS-защита, автобэкапы. Тарифы от 399 ₽/мес.
Создать серверУстанавливаем и настраиваем logrotate
logrotate — штатная утилита почти всех Linux-дистрибутивов (Debian/Ubuntu, CentOS/Alma, Rocky), обычно уже установлена и запускается по крону раз в сутки. Проверить:
which logrotate
cat /etc/cron.daily/logrotate
Если утилиты нет:
apt install logrotate # Debian/Ubuntu
dnf install logrotate # CentOS/AlmaLinux/Rocky
Конфиги хранятся в /etc/logrotate.d/ — каждый сервис получает свой файл. Создаём отдельный для игрового сервера, например /etc/logrotate.d/rust-server:
/home/rustserver/server/my-server/RustDedicated_Data/... /home/rustserver/logs/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
copytruncate
}
Разбор ключевых директив:
daily— ротация раз в сутки (есть такжеweekly,monthly, либоsize 100M— ротация по достижении размера, что полезнее для очень активных серверов).rotate 14— хранить 14 архивных копий (то есть две недели истории при дневной ротации).compress— сжимать старые файлы в.gz, экономит до 90% места на текстовых логах.delaycompress— не сжимать файл сразу, а только следующий цикл (полезно, если какой-то процесс ещё дописывает в него данные после ротации).missingok— не ругаться ошибкой, если лог-файла временно нет (сервер не запущен).notifempty— не ротировать пустой файл, незачем плодить пустые архивы.copytruncate— критически важная директива для процессов, которые держат файл лога открытым постоянно (большинство игровых серверов). Вместо переименования файлаlogrotateкопирует его содержимое и обрезает оригинал до нуля — так процесс продолжает писать в тот же файл-дескриптор без перезапуска.
Применить и проверить конфиг без ожидания суток можно принудительно:
logrotate -f /etc/logrotate.d/rust-server
logrotate -d /etc/logrotate.d/rust-server # dry-run, покажет что будет сделано без реальных действий
Ключевая грабля: copytruncate или postrotate
Здесь чаще всего ошибаются новички. Есть два принципиально разных подхода к ротации файла, который процесс держит открытым:
Вариант 1 — copytruncate. Простой и универсальный, не требует ничего от самого сервера. Минус — между копированием и обрезкой файла есть крошечное окно, в которое теоретически можно потерять несколько строк лога, записанных ровно в этот момент. Для игрового сервера это почти всегда несущественно.
Вариант 2 — postrotate с сигналом процессу. Логротация переименовывает старый файл, а затем сигналом (SIGHUP/SIGUSR1) просит процесс переоткрыть лог — работает только если сам процесс это умеет:
postrotate
systemctl kill -s HUP gameserver.service > /dev/null 2>&1 || true
endscript
Проблема в том, что большинство игровых серверов (Rust, ARK, Source-движок, ваш собственный Discord-бот на Python/Node) не умеют переоткрывать лог по сигналу — если использовать postrotate без copytruncate для такого процесса, файл переименуется, а сервер продолжит писать в уже переименованный (и невидимый в списке файлов) дескриптор — новый server.log не появится вообще, пока процесс не перезапустится.
Практический вывод: для 9 из 10 игровых серверов используйте copytruncate. postrotate со штатным переоткрытием логов имеет смысл только для процессов, которые сами это умеют — например, отдельный сервис веб-панели рядом на той же машине, который работает по HTTPS.
Если игра не пишет в файл: логируем stdout через systemd
Rust, Valheim и многие другие сервера по умолчанию пишут вывод только в stdout, а не в файл. Если сервер запущен через systemd-юнит (что правильнее, чем голый screen/tmux — подробнее в статье про systemd, screen и tmux для игровых процессов), самый чистый способ получить файл лога — journald с последующей выгрузкой, либо явный редирект в юните:
[Service]
ExecStart=/home/rust/server/RustDedicated -batchmode +server.port 28015
StandardOutput=append:/home/rust/logs/rust-server.log
StandardError=append:/home/rust/logs/rust-server.log
Такой файл logrotate ротирует так же, как любой другой — copytruncate работает и здесь, поскольку systemd просто дописывает в открытый дескриптор.
Альтернатива — оставить вывод в journald (поведение по умолчанию без StandardOutput) и настроить лимиты самого journald вместо logrotate, в /etc/systemd/journald.conf: SystemMaxUse=500M и MaxRetentionSec=14day, затем systemctl restart systemd-journald. Это не совсем логротация в классическом смысле, но решает ту же задачу. Какой вариант выбрать — дело вкуса: файл проще смотреть через grep/tail, journald удобнее фильтровать через journalctl -u rust-server --since "1 hour ago".
Сколько хранить: баланс между диском и расследованием инцидентов
Универсального числа нет, но есть рабочие ориентиры:
- Спокойный сервер с редкими проблемами — 14-30 дней ротации достаточно, этого хватает разобраться в инциденте, даже если о нём сообщили не сразу.
- Активный сервер с частыми жалобами на читеров/гриферов — храните дольше, 30-60 дней, особенно логи чата и RCON-команд админов.
- Продакшн с юридическими рисками (персональные данные игроков, платёжные логи биллинга) — ротация должна сверяться с политикой хранения персональных данных: иногда логи нужно хранить дольше по закону, а иногда — наоборот, удалять быстрее по требованиям приватности.
- Диагностические/дебаг-логи с verbose-уровнем — обычно достаточно 3-7 дней: они огромные по объёму и актуальны только для текущей проблемы.
Практический приём — не хранить всё на одном уровне детализации. Держите короткую ротацию (7 дней) на подробные debug-логи и длинную (30-60 дней) на сжатые архивы ключевых событий вроде банов, крашей и рестартов — так вы не теряете важную историю, но и не платите местом на диске за мегабайты рутинного шума.
Мониторинг места на диске как страховка
Даже идеально настроенная логротация не спасает от роста диска по другим причинам — бэкапы, ресурс-паки, чужие процессы на той же машине. Логротация снижает риск, но не отменяет необходимость следить за диском в целом.
Простой крон-скрипт для алерта в Discord при нехватке места (запускать раз в 30 минут через crontab):
#!/bin/bash
THRESHOLD=85
USAGE=$(df -h / | awk 'NR==2 {print $5}' | tr -d '%')
if [ "$USAGE" -ge "$THRESHOLD" ]; then
curl -s -X POST -H "Content-Type: application/json" \
-d "{\"content\": \"⚠️ Диск занят на ${USAGE}%! Проверь логи и бэкапы на сервере.\"}" \
"$DISCORD_WEBHOOK_URL"
fi
Это тот же принцип, что и уведомления о критичных событиях сервера через webhook — только конкретно про место на диске, которое логи занимают в первую очередь, если ротация не настроена или настроена неправильно (например, rotate 14 без compress на очень болтливом сервере всё равно может накопить внушительный объём).
Если у вас несколько игровых серверов на одной машине, стоит также свериться с общей схемой распределения ресурсов — там же обычно решается и вопрос отдельных дисков/разделов под логи каждого сервера, чтобы переполнение одного не роняло остальные — см. как разделить ресурсы между несколькими игровыми серверами на одной машине.
Нужен игровой сервер?
MAATRIX GAMES — 45+ игр, деплой за минуты, DDoS-защита, автобэкапы. Тарифы от 399 ₽/мес.
Создать серверЧастые вопросы
Что будет, если не настраивать logrotate вообще?
Ничего страшного не произойдёт, пока не кончится место на диске — а вот когда кончится, скорее всего пострадает не только логирование: перестанут сохраняться миры, упадёт база данных плагинов, может отвалиться сам процесс сервера. Лучше настроить один раз заранее, чем разбираться в 3 часа ночи.
Можно ли просто удалять старые логи скриптом через find -mtime +14 -delete вместо logrotate?
Можно, и для совсем простых случаев это рабочий вариант, но logrotate даёт сжатие, безопасную ротацию открытых файлов (copytruncate) и единый стандартный механизм — плюс не нужно писать и поддерживать свой скрипт с нуля.
Логи занимают место даже после сжатия — что не так?
Проверьте, не логируется ли что-то избыточное — например, полный чат сервера или подробный debug-режим плагина, который забыли выключить после отладки. Иногда решение — не хранить дольше, а логировать меньше.
Нужна ли логротация, если хостинг сам управляет дисками и мониторит место?
Мониторинг хостинга обычно предупредит о переполнении, но не решит проблему за вас — файлы логов всё равно растут внутри вашего дискового квота. На MAATRIX GAMES диск выделяется под конкретный тариф, и логротация — это ваша зона ответственности, как и на любом другом хостинге.
Как ротировать логи Docker-контейнера с игровым сервером?
logrotate хоста логи контейнера обычно не видит — настройте драйвер json-file с лимитами max-size/max-file в daemon.json, либо пробросьте лог-директорию наружу volume'ом и ротируйте её штатным logrotate хоста, как описано выше.