Когда друг в очередной раз спрашивает: «А давай поднимем свой сервер, чтобы никто не выключал?», — начинаешь гуглить и натыкаешься либо на видео сомнительного качества, либо на форумные треды десятилетней давности. А хочется, чтобы сервер работал, обновлялся, не падал и не открывал дыру в безопасности. Эта статья — практический разбор двух подходов к организации игрового сервера на Linux: «голое железо» с systemd и контейнеризация через Docker. На примере Minecraft (как самой частой истории) и Valheim (как примера из мира Steam). Без магии, с командами и конфигами.

Что нужно решить до первой команды

Прежде чем ставить пакеты, ответьте на три вопроса. От них зависит всё остальное.

Железо. Minecraft — игра, которая любит одно ядро и много памяти. Официальные требования начинаются от 1 ГБ RAM для ванильного сервера, но для 5–10 игроков уже стоит ориентироваться на 2–4 ГБ. Для модовых сборок цифры умножаются: 3 ГБ хватит на 3–8 игроков, 4 ГБ — на 8–15, а дальше — как повезёт с конкретными модами. Valheim требует минимум 4 ядра и 2 ГБ RAM, но на практике стабильнее себя чувствует с запасом.

ОС. Ubuntu 22.04/24.04 LTS или Debian 12+ — самые «обкатанные» варианты для игровых серверов. На старых дистрибутивах Valheim может не запуститься из‑за устаревшей glibc (нужна версия 2.29+). Если железо старое, Docker часто становится обходным путём, потому что тащит свои зависимости.

Подход. systemd на хосте — прозрачность и контроль. Docker — воспроизводимость и лёгкость обновлений. Ниже — оба варианта.

Вариант 1: systemd на «голом железе» (на примере Minecraft)

Этот путь хорош, когда вы хотите понимать, что происходит, и не хотите прослойки в виде контейнера.

Шаг 1. Подготовка системы и пользователя

Создаём отдельного пользователя, чтобы сервер не работал от root. Это базовое требование безопасности.

bash

sudo apt update && sudo apt upgrade -y
sudo adduser minecraft

Не забудьте пароль — он понадобится для переключения. Дальше ставим Java. Для Minecraft 1.20.5+ нужна Java 21.

sudo apt install -y curl unzip openjdk-21-jdk

Шаг 2. Загрузка и первый запуск

Переключаемся на пользователя minecraft, создаём папку и качаем server.jar с официального сайта Mojang. Ссылка на конкретную версию меняется, поэтому актуальную берите на странице загрузки Java Edition.

su - minecraft
mkdir -p ~/minecraft-server && cd ~/minecraft-server
curl -L -o minecraft_server.jar <актуальная_ссылка_на_server.jar>
echo "eula=true" > eula.txt

eula=true — это согласие с лицензией Mojang. Для тестового сервера сойдёт, но помните: вы берёте на себя ответственность за соблюдение условий.

Пробный запуск:

java -Xms2G -Xmx2G -jar minecraft_server.jar nogui

Флаги -Xms и -Xmx задают минимальный и максимальный размер heap. Для ванильного сервера на 5–10 человек 2 ГБ — разумный старт. Для модовых сборок смотрите на 4–6 ГБ и выше.

Шаг 3. systemd‑юнит: чтобы сервер пережил перезагрузку

Запускать java в screen или tmux — это не эксплуатация, это лотерея. Нормальный способ — unit‑файл. Один из распространённых шаблонов для Minecraft выглядит так:

ini

# /etc/systemd/system/minecraft@.service
[Unit]
Description=Minecraft Server %i
After=network.target

[Service]
WorkingDirectory=/opt/minecraft/%i
Type=simple
User=minecraft
Group=minecraft
ProtectSystem=full
ProtectHome=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
Environment="MCMINMEM=512M" "MCMAXMEM=1024M"
ExecStart=/usr/bin/java -Xms${MCMINMEM} -Xmx${MCMAXMEM} -jar server.jar nogui
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

Пара замечаний. ProtectSystem=full, ProtectHome=true и остальные Protect*‑директивы — это не паранойя, а нормальная практика для сетевых сервисов: они ограничивают доступ процесса к файловой системе и ядру. Шаблон @ позволяет держать несколько инстансов, если понадобится.

Активация:

sudo systemctl daemon-reload
sudo systemctl enable --now minecraft@server

Логи смотрим через journalctl -u minecraft@server -f, остановку делаем через systemctl stop. Просто и предсказуемо.

Вариант 2: Docker и Docker Compose

Если не хочется вручную следить за версиями Java и обновлениями, контейнер снимает часть рутины. Для Minecraft каноническим считается образ itzg/minecraft-server: он умеет автоматически скачивать нужную версию, подтягивать модлоадеры и принимать настройки через переменные окружения.

Минимальный docker-compose.yml:

services:
  minecraft:
    image: itzg/minecraft-server
    tty: true
    stdin_open: true
    ports:
      - "25565:25565"
    environment:
      EULA: "TRUE"
      TYPE: "VANILLA"
      VERSION: "LATEST"
      MEMORY: "2G"
    volumes:
      - ./minecraft-data:/data
    restart: unless-stopped

EULA обязателен, иначе контейнер не стартует. MEMORY задаёт heap для JVM; для ванильного сервера на небольшой круг людей 2G — адекватно. Том ./minecraft-data:/data сохраняет мир и конфиги между пересозданиями контейнера — без него всё уедет в никуда.

Запуск и логи:

docker compose up -d
docker logs -f <имя_контейнера>

Для Valheim логика похожая, но есть нюанс: сервер распространяется через SteamCMD, а не через прямой jar. Образ didstopia/valheim-server принимает имя сервера, мир и пароль через переменные, а также умеет автоматически проверять обновления. Пароль обязателен — без него сервер не запустится. Порты — UDP 2456-2458, это важно для файрвола.

Если хочется единого инструмента для разных игр, присмотритесь к LinuxGSM — это набор скриптов, который ставит, обновляет и бэкапит десятки выделенных серверов, включая Minecraft и Valheim. Он не отменяет понимания systemd, но снимает часть рутины с обновлениями и мониторингом.

Docker vs bare metal: что выбрать

Короткий ответ: для одного‑двух серверов «для друзей» — systemd на хосте, потому что меньше слоёв и проще диагностика. Для нескольких инстансов или если хочется легко переезжать между машинами — Docker. По производительности разница между контейнером и «голым железом» в типичных сценариях небольшая; Docker добавляет минимальный оверхед на I/O, но взамен даёт изоляцию и повторяемость. Если сервер упирается в диск или сеть, это обычно не из‑за контейнера, а из‑за железа или настроек.

Безопасность: что нельзя оставлять «на потом»

Игровой сервер — это открытый порт в интернет. Даже если там «просто майнкрафт», его найдут сканеры.

Файрвол. Открывайте только те порты, которые реально нужны. Для Minecraft это TCP 25565, для Valheim — UDP 2456-2458. Всё остальное закрыто. UFW делает это в две команды:

sudo ufw allow 25565/tcp
sudo ufw allow 2456:2458/udp
sudo ufw enable

Правило простое: если порт не нужен для игры или администрирования — он не должен быть доступен снаружи.

Пользователь и права. Сервер не должен работать от root. Отдельный пользователь с минимальными правами, Protect* в systemd или --read-only/--cap-drop в Docker — базовый минимум.

Сеть. Если играете только с друзьями и не хотите светить сервер в интернет, посмотрите в сторону Tailscale или WireGuard: сервер будет доступен только внутри вашей приватной сети, а публичный порт можно закрыть. Это не всегда удобно для больших сообществ, но для узкого круга — отличный вариант.

Производительность: где чаще всего «болит»

Для Minecraft главный враг — не количество ядер, а скорость одного ядра и объём памяти. Сервер использует дополнительные ядра, но основная нагрузка ложится на одно. Поэтому гнаться за 16 ядрами на дешёвом VPS смысла нет — лучше взять меньше ядер, но с высоким clock speed.

Второй рычаг — view-distance и simulation-distance в server.properties. Если сервер начинает «подтормаживать» при большом онлайне, снижение simulation-distance до 4–6 и view-distance до 6–12 даёт заметный выигрыш по TPS без катастрофической потери картинки для игроков. Сначала режьте simulation-distance: именно он влияет на тики и нагрузку, тогда как view-distance — больше про то, что видит игрок.

Для Valheim узкое место — сеть и UDP‑порты; на стороне сервера стоит убедиться, что LD_LIBRARY_PATH указывает на linux64 внутри папки сервера, иначе он может не найти библиотеки.

В заключение

Свой игровой сервер — это не «сложно», а «нужно один раз сделать аккуратно». systemd даёт контроль и понимание, Docker — скорость и воспроизводимость. В любом случае три вещи решают больше, чем остальные: отдельный пользователь, закрытый файрвол и внятный unit‑файл (или docker-compose.yml). Дальше — только обновления и бэкапы.