DayZ: краш сервера при рестарте
Сервер работал всю ночь без нареканий, а после планового рестарта в 5 утра просто не поднялся — в логах либо тишина, либо строчка про повреждённые данные. Знакомая картина для DayZ-админов: краш на рестарте почти никогда не связан с самим геймплеем, а почти всегда — с тем, что происходит в момент остановки и старта процесса. Разберём три самые частые причины и как их искать по логам, а не гадать.
Содержание
Почему именно рестарт, а не бой на 60 игроках
DayZ-сервер может часами держать полный онлайн без единого предупреждения в логах, а падать именно в момент планового перезапуска — и это не совпадение. Рестарт — единственный момент, когда одновременно происходит несколько рискованных вещей: процесс дописывает персистентные данные на диск, cron или systemd могут пересечься с фоновым обновлением через SteamCMD, а сам движок заново парсит все файлы миссии и модов с нуля вместо того, чтобы держать их уже провалидированными в памяти.
Поэтому если сервер стабильно падает именно при перезапуске (а не спонтанно посреди сессии), в 90% случаев причина — одна из трёх: повреждённая база персистентности, рассинхрон версий модов после автообновления, или сам скрипт рестарта убивает процесс неправильно. Дальше — по порядку, с тем, как отличить одно от другого по логам.
| Симптом | Скорее всего причина | Где смотреть |
|---|---|---|
Краш сразу на загрузке миссии, упоминание .bin/persistence в логе | Битый storage_1/storage_2 | profiles/script_*.log, profiles/*.RPT |
Краш с текстом Addon '...' requires addon '...' или CRC mismatch | Конфликт версий модов после апдейта | profiles/*.RPT, версии в steamapps/workshop |
| Процесс просто не запускается, но логов нет вовсе | Проблема в restart-скрипте/cron, а не в игре | journalctl -u dayzserver, вывод cron-задачи |
| Сервер стартует, но откатывает базы/тайники игроков | Восстановление со старого storage после сбоя | profiles/script_*.log за момент предыдущего краша |
storage_1 и storage_2: как DayZ бережёт (и портит) базу предметов
Персистентные данные — построенные базы, тайники, брошенный лут, транспорт — DayZ хранит не в одном файле, а поочерёдно пишет в две папки внутри директории миссии, например ~/dayzserver/mpmissions/dayzOffline.chernarusplus/storage_1/ и storage_2/. Это защита от обрыва записи: пока идёт сохранение в одну копию, вторая остаётся целой на случай сбоя.
Проблема в том, что эта защита работает только при штатной остановке. Если сервер убить в момент, когда обе копии оказались в промежуточном состоянии (что как раз вероятнее при жёстком килле, а не при штатном завершении), при следующем старте движок либо не сможет распарсить данные, либо восстановит версию с явными потерями — пропавшие тайники, откатившиеся базы, задвоенный лут. В логе script_*.log в такой ситуации обычно видна ошибка чтения persistence-файлов или предупреждение о повреждённой базе сразу после строчки инициализации миссии.
Что делать на месте, если сервер уже не стартует:
- Остановите сервис и сделайте копию обеих папок, прежде чем что-то трогать:
cp -r storage_1 storage_1.bak && cp -r storage_2 storage_2.bak. - Попробуйте временно переименовать повреждённую копию (обычно это та, что новее по времени модификации —
ls -la storage_1 storage_2) и запустить сервер на второй. - Если обе копии битые — остаётся принять потерю персистентности и запустить сервер с чистой базой (движок создаст новую при отсутствии обеих папок).
Профилактика надёжнее лечения: держите отдельный бэкап storage_1/storage_2 перед каждым плановым рестартом, а не только перед патчами. Это буквально одна строчка rsync в скрипте рестарта, которая много раз спасала базы игроков.
Поднять сервер DayZ за пару минут
Готовый образ MAATRIX GAMES: NVMe, AMD EPYC, DDoS-защита, панель управления. Локации UK, US, RU. Оплата картой РФ, СБП или криптой.
Создать серверКонфликт модов после автообновления через SteamCMD
Если моды у вас обновляются автоматически (например, отдельным cron-заданием со SteamCMD, которое тянет свежие версии из Workshop независимо от рестарта игры), возникает классическая гонка: SteamCMD может докачать новую версию мода в момент, когда сервер уже запускается или ещё не успел полностью остановиться. Результат — файлы мода частично новые, частично старые, и движок падает с ошибкой вида Addon '@ModName' requires addon '@Dependency' или молчаливым несовпадением подписи (.bikey).
Отдельная и более частая причина: автор мода выкатил обновление в Workshop, SteamCMD его подтянул, а зависимость @CF (Community Framework, от которого зависит большинство крупных модов) осталась на старой сборке. Проверить версию мода можно по времени последнего обновления в манифесте:
cat ~/steamcmd/steamapps/workshop/appworkshop_221100.acf | grep -A2 "1559212036"
Порядок диагностики:
# смотрим последний краш в RPT-логе
tail -100 ~/dayzserver/profiles/*.RPT
# сверяем список модов в ExecStart с реально скачанными папками
ls ~/dayzserver/@*
# проверяем, не идёт ли параллельно ещё одна закачка SteamCMD
ps aux | grep steamcmd
Чтобы разорвать гонку, разделите обновление модов и рестарт сервера по времени с запасом, и не запускайте +workshop_download_item для нескольких модов параллельно из разных процессов — SteamCMD не всегда корректно обрабатывает конкурентные закачки в одну директорию. Подробно о том, откуда брать моды и как считать зависимости, — в статье про установку модов на DayZ-сервер, а сборки, где такие конфликты всплывают чаще всего из-за числа зависимостей, — в обзоре популярных модпаков Namalsk, Deer Isle и других.
Restart-скрипт и cron: где чаще всего косячат
Самая банальная и при этом самая частая причина краша на рестарте — сам скрипт, который его выполняет. Три типичные ошибки:
- Жёсткий kill вместо штатной остановки. Скрипт вида
pkill -9 DayZServerубивает процесс мгновенно, не давая движку дописать persistence — именно так чаще всего и получаются битыеstorage_1/storage_2из предыдущего раздела. - Гонка с обновлением. Cron-задача на рестарт и cron-задача на
app_updateчерез SteamCMD стоят слишком близко по времени и иногда пересекаются — сервер стартует поверх ещё не докачанных файлов. - Нет блокировки от повторного запуска. Если предыдущий рестарт завис (например, SteamCMD ждёт ввода или сеть подвисла), а cron уже запустил следующий по расписанию — получаются два конкурирующих процесса, которые дерутся за одни и те же файлы миссии.
Рабочий вариант скрипта с блокировкой и паузой между остановкой и обновлением:
#!/bin/bash
# /opt/scripts/dayz-restart.sh
LOCKFILE="/tmp/dayz-restart.lock"
if [ -e "$LOCKFILE" ]; then
echo "Предыдущий рестарт ещё не завершён, выходим"
exit 1
fi
trap "rm -f $LOCKFILE" EXIT
touch "$LOCKFILE"
# бэкап persistence перед остановкой
rsync -a ~/dayzserver/mpmissions/dayzOffline.chernarusplus/storage_1/ ~/backups/storage_1_$(date +%F)/
rsync -a ~/dayzserver/mpmissions/dayzOffline.chernarusplus/storage_2/ ~/backups/storage_2_$(date +%F)/
sudo systemctl stop dayzserver
sleep 5
# обновление сервера и модов — только после полной остановки
~/steamcmd/steamcmd.sh +login anonymous +force_install_dir ~/dayzserver +app_update 223350 +quit
sudo systemctl start dayzserver
И соответствующая cron-запись с логированием вывода, без которого при сбое вы не увидите вообще ничего:
0 5 * * * /opt/scripts/dayz-restart.sh >> /var/log/dayz-restart.log 2>&1
Про общий подход к предупреждению игроков и выбору времени рестарта — в статье про автоматический рестарт сервера по расписанию через cron; там же разобрана логика TimeoutStopSec в systemd-юните, актуальная и для DayZ.
Graceful shutdown вместо kill процесса
У DayZ, в отличие от Rust или Minecraft, нет встроенной команды сохранения через RCON в общем доступе — из коробки штатный способ остановить сервер корректно — отправить ему сигнал SIGTERM, который посылает systemctl stop по умолчанию, а не SIGKILL. Движок перехватывает SIGTERM и успевает дописать persistence и закрыть сокеты; SIGKILL (то же самое, что kill -9 или pkill -9) обрывает процесс мгновенно, независимо от того, на каком этапе записи он находится.
Если у вас установлен BEC (BattlEye Extended Controls) или аналогичный инструмент для админки Arma-движка, через него можно послать команды #shutdown или #restart по BattlEye RCON — это ещё более мягкий путь, чем сигнал ОС, потому что команда идёт через штатный протокол игры, а не снаружи процесса. Для небольших серверов без BEC вполне достаточно правильно настроенного systemd-юнита:
# /etc/systemd/system/dayzserver.service
[Unit]
Description=DayZ Dedicated Server
After=network.target
[Service]
User=steam
WorkingDirectory=/home/steam/dayzserver
ExecStart=/home/steam/dayzserver/DayZServer -config=serverDZ.cfg -port=2302 -profiles=profiles -dologs -adminlog -netlog -freezecheck
Restart=on-failure
RestartSec=10
TimeoutStopSec=60
[Install]
WantedBy=multi-user.target
TimeoutStopSec=60 — ключевая строка: она даёт процессу минуту на корректное завершение после SIGTERM, и только если он не уложился, systemd досылает SIGKILL принудительно. На Windows-хостинге аналог — не форсировать taskkill /F, а сначала попробовать закрыть процесс штатно (через taskkill без /F или через диспетчер задач с ожиданием), форс — только если завис.
Чек-лист и восстановление после краша
Если рестарт всё-таки закончился крашем, порядок действий такой:
- Смотрим свежий
profiles/script_*.logиprofiles/*.RPT— там почти всегда есть конкретная строка с причиной (persistence, addon dependency, отсутствующий файл миссии). - Проверяем, не идёт ли параллельно процесс SteamCMD (
ps aux | grep steamcmd) — если да, ждём его завершения, не перезапускаем сервер поверх. - Если ошибка про persistence — откатываемся на бэкап
storage_1/storage_2, сделанный перед рестартом (см. скрипт выше). - Если ошибка про моды — сверяем версии в
-mod=изExecStartс реально скачанными папками@ModNameи при необходимости передокачиваем битый мод целиком, а не патчим поверх. - После восстановления — запуск не через cron, а вручную с полным выводом в терминал (
sudo systemctl start dayzserver && journalctl -u dayzserver -f), чтобы сразу увидеть, поднялся ли процесс до конца.
Чек-лист перед каждым плановым рестартом, чтобы краш вообще не случился:
- Бэкап
storage_1иstorage_2сделан до остановки, не после. - Обновление модов и обновление сервера не пересекаются по времени с самим рестартом (есть запас минимум в несколько минут).
- В restart-скрипте нет
kill -9/pkill -9— толькоsystemctl stopили явныйSIGTERM. - Есть lock-файл, защищающий от повторного запуска скрипта, если предыдущий рестарт завис.
- Вывод cron-задачи логируется в файл, а не теряется молча.
Поднять сервер DayZ за пару минут
Готовый образ MAATRIX GAMES: NVMe, AMD EPYC, DDoS-защита, панель управления. Локации UK, US, RU. Оплата картой РФ, СБП или криптой.
Создать серверЧастые вопросы
Можно ли включить автоматическое восстановление из storage_2, если storage_1 повреждён?
Штатного автоматического переключения нет — если основная копия читается с ошибкой, движок может либо упасть, либо создать новую пустую базу. Ручное переименование папок, описанное выше, работает надёжнее, чем надежда на автоматику.
Помогает ли validate в app_update от битых модов?
Помогает от повреждённых файлов самого сервера (движка), но не от рассинхрона версий модов — Workshop-моды скачиваются и валидируются отдельной командой workshop_download_item, и validate на app_update 223350 их не трогает.
Что делать, если краш повторяется на каждом рестарте, а логи не помогают?
Запустите сервер вручную в foreground-режиме (./DayZServer -config=... без демонизации через systemd) — так вывод в терминал часто подробнее, чем то, что попадает в RPT-файл, особенно на самых ранних этапах инициализации.
Обязательно ли делать бэкап persistence перед каждым рестартом, если он ежедневный?
Строго рекомендуется — это дешёвая операция (папки storage_1/storage_2 обычно весят не так много), а цена восстановления без бэкапа — полная потеря баз и тайников всех игроков.
Может ли обновление самой игры (не мода) сломать совместимость с текущими модами?
Да, это отдельная и частая причина краша именно после патча DayZ — крупные апдейты меняют API, и моды, которые их автор ещё не обновил под новую версию, начинают падать при загрузке. В таком случае помогает откат сервера на предыдущую версию через -beta в SteamCMD, если разработчик держит старые билды в депо.