MAATRIX GAMES / Блог / Автозапуск игрового сервера при перезагрузке хоста

Автозапуск игрового сервера при перезагрузке хоста

MAATRIX GAMES

Хост ушёл на плановое обновление ядра, или провайдер перезагрузил ноду после сбоя — а ваш сервер, который вы честно запустили в screen три недели назад и забыли, просто не поднялся. Игроки долбятся в закрытый порт, сервер простаивает часами, пока кто-то не заметит и не зайдёт руками. Решается это один раз и на пять минут: заворачиваем запуск в systemd-юнит с автозапуском и Restart=always, и после любой перезагрузки — плановой или нет — сервер поднимается сам, без вашего участия.

Почему screen и tmux не переживают перезагрузку

screen и tmux — отличный инструмент, чтобы держать консоль сервера открытой и не терять её при обрыве SSH. Но это сессии терминала, а не сервисы операционной системы. Как только хост перезагружается (или просто демон screen падает), вся сессия исчезает вместе с процессом сервера внутри неё. Никакого механизма "запомнить и поднять снова" в screen/tmux нет — это не их задача.

То же самое с nohup ./start.sh & — процесс переживёт закрытие терминала, но не переживёт reboot. А перезагрузки случаются чаще, чем кажется: security-патчи ядра на хостинге, миграция VM между физическими нодами, банальный OOM-killer, который положил сервер, а вслед за ним и всё, что не настроено на автовосстановление.

systemd — это как раз тот слой, который создан для управления сервисами: он знает, что должно быть запущено на старте системы, следит за процессом и перезапускает его, если тот упал. Это стандарт для systemd-дистрибутивов (Ubuntu, Debian, AlmaLinux, Rocky Linux — то, что чаще всего стоит на игровых серверах), и настройка занимает по времени примерно столько же, сколько чтение этой статьи.

Готовим сервис: пользователь и права

Прежде чем писать unit-файл, разберитесь с двумя вещами: от чьего имени будет работать сервер и где лежат его файлы.

Правило хорошего тона — не гонять игровые сервера от root. Если у вас ещё нет отдельного пользователя, создайте:

sudo useradd -r -m -d /home/gameserver -s /bin/bash gameserver
sudo chown -R gameserver:gameserver /home/gameserver/server

Флаг -r создаёт системного пользователя (без лишних привилегий, не для интерактивного логина по умолчанию), -m создаёт домашнюю директорию. Если сервер уже установлен и запускался под вашим обычным пользователем — можно оставить как есть, просто используйте его имя в юните.

Проверьте, что бинарник или скрипт запуска действительно исполняемый и путь абсолютный — относительные пути в systemd не работают предсказуемо, если не задан правильный WorkingDirectory:

chmod +x /home/gameserver/server/start.sh
which java   # если сервер на Java (Minecraft) — нужен полный путь к java

Нужен игровой сервер?

MAATRIX GAMES — 45+ игр, деплой за минуты, DDoS-защита, автобэкапы. Тарифы от 399 ₽/мес.

Создать сервер

Пишем unit-файл systemd

Юниты для сервисов лежат в /etc/systemd/system/. Создаём файл под конкретный сервер, например /etc/systemd/system/minecraft.service:

[Unit]
Description=Minecraft Server
After=network.target

[Service]
Type=simple
User=gameserver
Group=gameserver
WorkingDirectory=/home/gameserver/server
ExecStart=/usr/bin/java -Xms4G -Xmx8G -jar server.jar nogui
Restart=always
RestartSec=10
StandardInput=null
LimitNOFILE=100000

[Install]
WantedBy=multi-user.target

Разберём ключевые параметры:

  • After=network.target — сервис стартует после поднятия сети, иначе он может попытаться забиндить порт раньше, чем сеть готова.
  • WorkingDirectory — критично для серверов, которые ищут конфиги и world-файлы относительно текущей директории (тот же Minecraft).
  • ExecStart — полная команда запуска, с абсолютными путями. Для Java-серверов сюда переносятся все флаги -Xms/-Xmx, для Source-игр (CS2, TF2, Left 4 Dead 2) — путь к srcds_run с параметрами карты и порта, для Rust — путь к RustDedicated со всеми +server.* флагами.
  • Restart=always — вот это и есть автовосстановление: упал процесс (краш, OOM, ручной kill) — systemd поднимет его снова.
  • RestartSec=10 — пауза перед перезапуском. Без неё, если сервер падает мгновенно из-за битого конфига, вы получите бесконечный цикл рестартов, забивающий CPU и лог.
  • LimitNOFILE — многие игровые сервера (особенно с большим числом онлайн-игроков) упираются в лимит открытых файловых дескрипторов по умолчанию.

Для Rust-сервера пример ExecStart будет выглядеть примерно так:

ExecStart=/home/gameserver/rust/RustDedicated -batchmode +server.port 28015 +server.identity "rust_server" +rcon.port 28016 +rcon.password "changeme"

Если запускаете сервер через LinuxGSM (обёртку lgsm), можно указать сам скрипт: ExecStart=/home/gameserver/lgsm/mcserver start, но тогда придётся учитывать, что LinuxGSM сам умеет управлять процессом — с systemd поверх него иногда возникает двойное управление, так что сверяйтесь с документацией сборки, которую вы используете.

Включаем автозапуск и запускаем впервые

После того как unit-файл сохранён, systemd нужно перечитать конфигурацию, включить автозапуск и запустить сервис:

sudo systemctl daemon-reload
sudo systemctl enable minecraft.service
sudo systemctl start minecraft.service
  • daemon-reload — обязателен после каждого изменения файла юнита, иначе systemd продолжит работать со старой версией конфигурации из памяти.
  • enable — вот эта команда и создаёт симлинк, который заставит сервис стартовать при следующей загрузке системы (в multi-user.target, то есть на этапе, когда система уже в многопользовательском режиме и сеть поднята).
  • start — запускает сервис прямо сейчас, не дожидаясь перезагрузки.

Проверьте, что всё поднялось:

sudo systemctl status minecraft.service

Вы должны увидеть active (running) зелёным и PID процесса. Если статус failed — не паникуйте, в следующем разделе разберём, где смотреть причину.

Честно: на этом моменте стоит один раз реально перезагрузить хост (sudo reboot) и убедиться, что сервер поднимается сам, а не просто верить конфигу. Разница между "enable отработал" и "сервер реально стартует после ребута" бывает из-за неверного After=, отсутствующих прав на файлы или сети, которая поднимается медленнее, чем ожидает юнит.

Управление сервером: systemctl вместо screen

Как только сервер под systemd, вся рутина управления меняется — вместо "зайти в screen, найти нужную сессию, ткнуть команду" используются стандартные команды:

ДействиеКоманда
Запуститьsudo systemctl start minecraft.service
Остановитьsudo systemctl stop minecraft.service
Перезапуститьsudo systemctl restart minecraft.service
Статусsudo systemctl status minecraft.service
Включить автозапускsudo systemctl enable minecraft.service
Отключить автозапускsudo systemctl disable minecraft.service
Список всех активных юнитовsystemctl list-units --type=service

Плюс в том, что это одинаковый интерфейс для любого сервиса на машине — не нужно помнить, в какой screen-сессии какой сервер, особенно если у вас их несколько (например, отдельно Minecraft-сервер и Discord-бот к нему, или пара CS2-серверов под разные режимы).

Если вам всё же нужен интерактивный доступ к консоли сервера (ввести команду вида save-all или op ИмяИгрока напрямую), можно оставить STDIN открытым через отдельный screen/tmux, к которому подключается сам systemd-юнит, либо — что чище — управлять сервером через RCON. Про подключение и базовые команды RCON у нас есть отдельный разбор: RCON — подключение и основные команды. Для большинства современных серверов (Rust, CS2, ARK) RCON — вообще единственный вменяемый способ слать команды на сервер, запущенный как systemd-сервис без интерактивного stdin.

Логи, graceful shutdown и другие грабли

Все, что сервер пишет в stdout/stderr, systemd сам собирает в journald. Смотреть логи:

sudo journalctl -u minecraft.service -f      # "хвост" в реальном времени
sudo journalctl -u minecraft.service -n 200  # последние 200 строк
sudo journalctl -u minecraft.service --since "1 hour ago"

Это удобнее, чем скроллить историю screen-сессии — логи не теряются при перезапуске, их можно фильтровать по времени и грепать.

Несколько нюансов, на которых спотыкаются в первый раз:

  • Graceful shutdown. По умолчанию systemd шлёт процессу SIGTERM при остановке и ждёт 90 секунд (TimeoutStopSec) перед SIGKILL. Для серверов, которые не сохраняют мир по SIGTERM (некоторые модифицированные сборки), это может привести к потере последних минут прогресса. Если сервер поддерживает команду сохранения через RCON или у вас есть скрипт graceful-стопа, пропишите ExecStop= с этой командой явно, а не полагайтесь на дефолтный сигнал.
  • OOM-killer. Если хосту не хватает памяти, ядро может убить именно процесс сервера, а не что-то другое — и Restart=always тут же поднимет его заново, но это симптом, что -Xmx (или лимиты в конфиге игры) выставлены слишком агрессивно относительно реальной RAM хоста. Стоит держать 10-15% памяти в запасе под систему и не выделять серверу 100% доступной RAM.
  • Бесконечный рестарт-луп. Если конфиг сервера битый и он падает через секунду после старта, RestartSec=10 спасает от перегрузки CPU, но не от самого факта постоянных падений — проверяйте journalctl, если видите частые Restart в статусе.
  • RCON и systemd не конфликтуют. Даже без интерактивной консоли RCON продолжает работать как обычно — это отдельный сетевой порт, который открывает сам процесс сервера, systemd тут ни при чём.
  • Несколько серверов — несколько юнитов. Не пытайтесь запускать два инстанса игры одной командой в одном юните: заведите отдельный .service-файл на каждый порт/инстанс с уникальным именем (cs2-surf.service, cs2-dm.service) и своим WorkingDirectory. Если у вас сервера Rust или Counter-Strike 2 на разных портах — это особенно актуально, каждый деплой такого сервера получает собственный юнит.

Нужен игровой сервер?

MAATRIX GAMES — 45+ игр, деплой за минуты, DDoS-защита, автобэкапы. Тарифы от 399 ₽/мес.

Создать сервер

Частые вопросы

Systemd работает на любом Linux-хостинге?

На большинстве современных дистрибутивов — да (Ubuntu, Debian, CentOS/AlmaLinux/Rocky начиная с 7-й ветки). Если у вас Alpine или другой дистрибутив на OpenRC/runit — там свой механизм автозапуска, но принцип тот же: сервис вместо ручного screen.

Можно ли настроить автозапуск без root-доступа?

Нет, /etc/systemd/system/ требует прав root (или sudo). На виртуальных серверах и VPS root-доступ обычно есть по умолчанию; на shared-хостингах для игровых серверов, где root закрыт, автозапуск чаще уже встроен в панель управления хостинга.

Что делать, если статус после старта — failed?

Смотрите journalctl -u имя.service -n 50 — там будет причина: неверный путь в ExecStart, нет прав у пользователя на файлы, занят порт, или сервер сам упал с ошибкой конфига. В 90% случаев причина видна в первых строках лога.

Нужно ли отключать screen/tmux совсем?

Нет, они по-прежнему полезны для разовой ручной отладки — просто не полагайтесь на них как на постоянный способ держать сервер живым между перезагрузками.

Restart=always перезапустит сервер даже после команды stop?

Нет. systemctl stop — это осознанная остановка, systemd её уважает и не перезапускает сервис, пока вы не вызовете start заново. Restart=always реагирует только на неожиданное завершение процесса (краш, kill, OOM), а не на явную команду оператора.