Автоматический рестарт сервера по расписанию (cron)
Если сервер живёт неделями без перезапуска, рано или поздно начинается знакомая картина: тикрейт проседает, память жрётся быстрее обычного, а иногда сервер просто зависает без единой строчки в логах о причине. Плановый рестарт по расписанию — самый скучный и при этом самый надёжный способ этого избежать. Ниже — рабочая схема на cron и systemd, которую можно поставить один раз и забыть.
Содержание
Зачем вообще нужен плановый рестарт
Игровые серверы — это долгоживущие процессы, и почти любой из них со временем накапливает деградацию: утечки памяти в Java-мирах Minecraft, разрастание списка сущностей в Rust, фрагментацию памяти в модифицированных сборках на Lua (FiveM, Garry's Mod). Даже если утечка небольшая — пара мегабайт в час — за неделю аптайма она превращается в заметное падение TPS или FPS на клиенте.
Есть и вторая причина, менее очевидная: плановый рестарт — это точка, в которую удобно "подвесить" остальную рутину. Ротацию логов, бэкап мира перед остановкой, применение обновлений, которые требуют перезапуска процесса (не хотфиксов на лету, а именно смены бинарника или конфига). Если рестарт всё равно происходит каждую ночь, логично туда же встроить и эти задачи, а не городить отдельные cron-джобы, которые могут пересечься с работающим сервером.
Отдельно стоит сказать честно: плановый рестарт — это не замена нормального мониторинга и не лечит первопричину утечки, если она есть в конкретной версии мода или плагина. Это симптоматическое решение, но оно рабочее и почти нулевой стоимости в настройке.
Базовая cron-задача
Cron — планировщик заданий, который есть в любом Linux-дистрибутиве. Открываем crontab пользователя, от которого работает сервер (не root, если можно этого избежать):
crontab -e
Простейший вариант — рестарт через systemd-юнит раз в сутки в 5:00 по времени сервера:
0 5 * * * systemctl restart minecraft-server.service
Формат полей — минута, час, день месяца, месяц, день недели. Если нужен рестарт не каждый день, а, скажем, только по средам и субботам:
0 5 * * 3,6 systemctl restart rust-server.service
Но такой прямолинейный вызов restart — это, по сути, kill с задержкой: systemd пошлёт сигнал остановки и через таймаут прибьёт процесс, если тот не завершится сам. Для мира, который не был корректно сохранён, это может означать откат прогресса на несколько минут или, в худшем случае, повреждение файла сохранения. Дальше разберём, как сделать это правильно.
Нужен игровой сервер?
MAATRIX GAMES — 45+ игр, деплой за минуты, DDoS-защита, автобэкапы. Тарифы от 399 ₽/мес.
Создать серверПредупреждаем игроков заранее
Резкий обрыв сессии — одна из главных причин негатива от игроков, даже если рестарт длится 30 секунд. Решение — рассылка предупреждений через RCON за 10, 5 и 1 минуту до остановки. RCON (Remote Console) есть практически во всех популярных серверах: Minecraft, Rust, CS2, ARK, Valheim (через плагины), Project Zomboid.
Пример для Minecraft через mcrcon (нужно установить: apt install mcrcon или собрать из исходников):
mcrcon -H 127.0.0.1 -P 25575 -p "ваш_rcon_pass" "say Внимание! Рестарт сервера через 10 минут."
Для Rust через rust-rcon или встроенный веб-сокет RCON (порт задаётся параметром +rcon.port):
rustcli --host 127.0.0.1 --port 28016 --password "ваш_rcon_pass" "say Перезапуск сервера через 10 минут, сохраните прогресс"
Для CS2 (использует стандартный Source RCON):
rcon -a 127.0.0.1:27015 -p "ваш_rcon_pass" "say [СЕРВЕР] Рестарт через 10 минут"
Соберём это в один скрипт-обёртку, который шлёт три предупреждения с паузами, а затем инициирует корректную остановку:
#!/bin/bash
# /opt/scripts/scheduled-restart.sh
RCON_HOST="127.0.0.1"
RCON_PORT="25575"
RCON_PASS="ваш_rcon_pass"
SERVICE="minecraft-server.service"
send_warn() {
mcrcon -H "$RCON_HOST" -P "$RCON_PORT" -p "$RCON_PASS" "say $1"
}
send_warn "Плановый рестарт сервера через 10 минут"
sleep 300
send_warn "Плановый рестарт сервера через 5 минут"
sleep 240
send_warn "Плановый рестарт через 1 минуту, сохраняем мир"
sleep 60
mcrcon -H "$RCON_HOST" -P "$RCON_PORT" -p "$RCON_PASS" "save-all"
sleep 5
systemctl stop "$SERVICE"
sleep 3
systemctl start "$SERVICE"
Даём права на выполнение и меняем cron-задачу так, чтобы она вызывала скрипт, а не напрямую systemctl:
chmod +x /opt/scripts/scheduled-restart.sh
0 5 * * * /opt/scripts/scheduled-restart.sh >> /var/log/scheduled-restart.log 2>&1
Обратите внимание на >> /var/log/scheduled-restart.log 2>&1 — без этого вывод скрипта уйдёт в почту root (если настроен MTA) или потеряется вовсе, и вы не увидите, если что-то пошло не так.
Graceful shutdown вместо kill
Ключевая ошибка новичков — гасить процесс через kill -9 или pkill. Это моментально убивает процесс без сохранения состояния: для Minecraft это риск потерять последние минуты изменений в мире, для Rust — повредить файл сохранения, если запись шла в момент убийства процесса.
Правильная последовательность:
- Дать команду сохранения (для Minecraft —
save-all, для Rust —server.save, для большинства ARK/Valheim серверов через RCON — соответствующая команда сохранения из документации конкретной игры). - Дождаться завершения записи на диск (пара секунд для небольших миров, до 10-20 секунд для тяжёлых карт с сотнями структур).
- Отправить сигнал
SIGTERM(это делаетsystemctl stopпо умолчанию) — большинство серверных бинарников перехватывают его и корректно закрывают сокеты, дописывают логи, освобождают ресурсы. - Только если процесс не завершился за разумный таймаут —
SIGKILLкак крайняя мера.
Systemd уже умеет делать шаги 3-4 сам через параметр TimeoutStopSec в юните — не нужно писать это вручную, достаточно правильно настроить сам unit-файл (см. следующий раздел). Ваша задача — гарантировать, что шаги 1-2 (сохранение) выполнены до того, как systemd пришлёт SIGTERM.
Для Rust, кстати, есть нюанс: команда server.save асинхронная, и сервер не сообщает через RCON явно "сохранение завершено". На практике достаточно паузы в 10-15 секунд после команды сохранения перед остановкой — для большинства карт этого хватает, но если у вас особо крупная кастомная карта, лучше проверить логи сервера и увеличить паузу.
Автозапуск обратно через systemd
Чтобы сервер не просто остановился, а гарантированно поднялся снова, нужен systemd-юнит с Restart=always. Пример для типового Java-сервера Minecraft (Paper):
# /etc/systemd/system/minecraft-server.service
[Unit]
Description=Minecraft Paper Server
After=network.target
[Service]
User=mcserver
WorkingDirectory=/home/mcserver/server
ExecStart=/usr/bin/java -Xms4G -Xmx6G -jar paper.jar nogui
Restart=on-failure
RestartSec=10
TimeoutStopSec=60
StandardInput=null
[Install]
WantedBy=multi-user.target
Обратите внимание на Restart=on-failure, а не Restart=always — так systemd не будет пытаться поднять сервер бесконечно по кругу, если тот падает сразу после старта из-за битого конфига (это защита от "restart loop", который может забить диск логами за считаные минуты). TimeoutStopSec=60 даёт процессу минуту на корректное закрытие после SIGTERM, прежде чем systemd пришлёт SIGKILL принудительно.
После создания или изменения юнита обязательно:
systemctl daemon-reload
systemctl enable minecraft-server.service
Если сервер запускается не напрямую бинарником, а через скрипт-обёртку (типичная ситуация для Rust с oxide/uMod, где нужно применить патчи после старта, или для FiveM с txAdmin), в ExecStart указывается путь к этому скрипту, а не к самому исполняемому файлу. Про сам процесс поднятия конкретных серверов подробно расписано в статьях по Rust и Minecraft.
Выбор времени рестарта
Тут нет универсального ответа — всё зависит от того, где живёт ваша основная аудитория. Несколько практических ориентиров:
- RU-аудитория, сервер в UK или US-локации: смотрите на московское время, а не на время сервера. 5:00-6:00 по Москве обычно приходится на глубокую ночь по UTC, но это не совпадает с ночью по времени сервера — важно именно локальное время игроков, а не дата-центра.
- Международный проект (EU+US): компромисс редко бывает идеальным. Часто выбирают время, минимальное для обоих поясов сразу — например, раннее утро по UTC, которое попадает на ночь в Европе и на поздний вечер/раннюю ночь на восточном побережье США.
- Смотрите на реальные логи, а не угадывайте: если у вас включено логирование входов/выходов игроков, за неделю-две легко увидеть провал активности и поставить рестарт именно туда, а не полагаться на "все спят ночью".
Таблица для ориентира (часовые пояса сильно упрощены, проверяйте по факту):
| Аудитория | Локация сервера | Ориентировочное окно рестарта (по времени аудитории) |
|---|---|---|
| RU/СНГ | UK/US | 04:00-06:00 (МСК) |
| EU | UK | 03:00-05:00 (CET) |
| US East | US | 03:00-05:00 (ET) |
| Смешанная RU+EU | UK | 03:00-04:00 (МСК) — компромисс |
Если у сервера несколько пиков активности (например, будни отличаются от выходных), не бойтесь ставить разное время или частоту через отдельные cron-строки — например, реже рестартить по выходным, когда трафик выше и обрыв сессии заметнее.
Логирование и проверка, что рестарт реально сработал
Слепая вера в то, что cron отработал — плохая практика. Минимальный набор проверок:
# последний запуск cron-задачи и её вывод
tail -50 /var/log/scheduled-restart.log
# статус юнита и время последнего старта
systemctl status minecraft-server.service
# убедиться, что cron-демон вообще жив
systemctl status cron
Полезно также добавить в конец скрипта проверку, что процесс реально поднялся и слушает порт, с алертом (например, отправкой сообщения в Telegram-бота или webhook), если этого не произошло:
sleep 30
if ! systemctl is-active --quiet "$SERVICE"; then
curl -s -X POST "https://api.telegram.org/bot<TOKEN>/sendMessage" \
-d chat_id=<CHAT_ID> \
-d text="Внимание: сервер $SERVICE не поднялся после планового рестарта!"
fi
Это простой, но рабочий контур: не полагаться на "тишина = всё хорошо", а явно проверять факт успешного старта.
Нужен игровой сервер?
MAATRIX GAMES — 45+ игр, деплой за минуты, DDoS-защита, автобэкапы. Тарифы от 399 ₽/мес.
Создать серверЧастые вопросы
Можно ли обойтись без RCON-предупреждений, если у меня маленький сервер на 3-5 друзей?
Можно, но всё равно стоит хотя бы кинуть сообщение в Discord-канал через webhook перед рестартом — это дешевле по времени настройки, чем RCON-скрипт, и почти так же полезно для небольшой команды.
Что если сервер не поддерживает RCON вообще?
Тогда предупреждение можно слать только через внешние каналы (Discord/Telegram), а для остановки использовать штатный механизм graceful shutdown самого сервера — почти у всех есть либо консольная команда сохранения через stdin, либо API. Проверяйте документацию конкретной игры.
Стоит ли рестартить сервер каждую ночь, если проблем с производительностью не замечено?
Не обязательно каждую ночь — можно начать с раза в 2-3 дня и смотреть на метрики (TPS, память, время отклика). Если деградации нет — оставьте расписание пореже, лишний рестарт — это тоже минута простоя.
Как быть с бэкапом мира — делать его до рестарта или после?
Логичнее до остановки, сразу после команды сохранения (save-all и аналоги) — так вы бэкапите гарантированно консистентное состояние, а не файлы, которые могут быть в процессе дозаписи после холодного старта.
Рестарт ломает моды/плагины, которые кэшируют состояние в памяти?
Изредка да — некоторые плагины экономики или квестов держат несохранённое состояние между "тиками" автосохранения. Проверьте документацию конкретного плагина на предмет хука вида onServerStop или аналогичного, и по возможности добавьте его вызов явно перед остановкой.