Автозапуск игрового сервера при перезагрузке хоста
Хост ушёл на плановое обновление ядра, или провайдер перезагрузил ноду после сбоя — а ваш сервер, который вы честно запустили в 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), а не на явную команду оператора.