Права доступа к файлам игрового сервера — как не открыть дыру
Если ваш сервер Minecraft, Rust или CS2 запущен под root «чтобы не возиться с правами», а веб-панель пишет в те же файлы от того же пользователя — вы одной уязвимой плагиной или кривым модом на расстоянии одной команды от полного захвата машины. Права доступа — это не бюрократия для галочки, а единственная граница между «взломали игровой сервер» и «взломали вообще всё, что на этом VPS есть». Разберём, как развести пользователей, группы и права так, чтобы дыра в игре не стала дырой в системе.
Содержание
Почему root для игрового процесса — плохая идея
Запуск игрового сервера от root — самый частый грех у новичков, и самый опасный. Логика обычно такая: «от root точно ничего не сломается из-за прав, всё разрешено». Именно в этом и проблема. Если в движке игры, в плагине или в моде найдётся уязвимость с выполнением произвольного кода (RCE) — а такие баги периодически всплывают и в популярных модпаках, и в плагинах для Paper/Bukkit, и в аддонах для Rust/Oxide — атакующий получает не доступ к папке с миром, а root-шелл на всей машине. Дальше это уже не «откатили бэкап и погнали дальше», а полная переустановка, смена всех паролей и разбор, что ещё утекло.
Второй риск — жадность до ресурсов. Процесс, упавший в бесконечный цикл записи логов или переполнивший диск, от обычного пользователя упрётся в лимиты (quota, права на системные разделы), а от root спокойно способен затронуть системные файлы или переполнить корневой раздел так, что упадёт вообще всё на хосте, включая панель управления и другие сервисы.
Правило простое: игровой процесс запускается от отдельного непривилегированного пользователя, у которого есть доступ ровно к своей папке с сервером и ни к чему больше. Root нужен ровно один раз — чтобы этого пользователя создать и настроить автозапуск, дальше он в процессе не участвует.
Разделение пользователей: игра, панель, вы
На боевой машине, где крутится и панель управления, и один или несколько игровых серверов, разумно развести минимум три роли:
- системный пользователь под каждый игровой процесс (например,
mc-survival,rust-main) — владеет только своей папкой с сервером, не имеет sudo, часто вообще без прав на вход по паролю (nologinили/usr/sbin/nologinв качестве шелла, если человеку туда не нужно логиниться напрямую); - пользователь веб-панели (например,
panelили сервисный аккаунт вашего Pterodactyl-подобного демона) — отдельный от игровых, у него свои права на запись в конфиги через API панели, но не безусловный root-доступ к диску; - личные аккаунты администраторов — у каждого человека свой пользователь с sudo (об этом подробнее в статье про роли и права администраторов), никто не работает под общим root напрямую.
Создание пользователя под конкретный игровой сервер выглядит так:
sudo useradd -r -m -d /home/mc-survival -s /usr/sbin/nologin mc-survival
sudo passwd -l mc-survival
Флаг -r создаёт системного пользователя (без лишнего UID из диапазона обычных людей), -m -d — с домашней директорией под конкретную папку сервера, -s /usr/sbin/nologin — запрещает интерактивный вход по паролю (процесс всё равно можно запускать от его имени через sudo -u или systemd), passwd -l дополнительно блокирует пароль. Если вам всё же нужен вход по SSH под этим пользователем для ручной отладки — используйте SSH-ключи вместо пароля и оставьте шелл обычным /bin/bash только на время работы.
Нужен игровой сервер?
MAATRIX GAMES — 45+ игр, деплой за минуты, DDoS-защита, автобэкапы. Тарифы от 399 ₽/мес.
Создать серверВладелец файлов: chown и зачем нужны группы
Когда пользователь для игры создан, у папки сервера должен быть правильный владелец. Частая ошибка — установить сервер от root (например, через SteamCMD в интерактивной сессии), а потом запускать процесс от игрового пользователя, который до файлов физически не дотягивается.
sudo chown -R mc-survival:mc-survival /home/mc-survival/server
Это рекурсивно меняет владельца и группу на всех файлах и папках внутри. Группа здесь не просто дубль владельца — она пригождается, когда файлам сервера нужен доступ ещё от одного процесса, кроме основного. Классический случай — веб-панель, которой нужно читать логи или редактировать конфиг через файловый менеджер, не будучи владельцем файлов:
sudo usermod -aG mc-survival panel
sudo chmod -R g+rw /home/mc-survival/server/config
Так пользователь panel добавляется в группу mc-survival и получает право читать и писать в конфиги через групповые права, не становясь владельцем и не получая доступ ко всему остальному на диске. Для новых файлов, которые создаёт сам игровой процесс, полезен setgid-бит на директории — тогда все новые файлы наследуют группу папки автоматически, а не группу того, кто их создал:
sudo chmod g+s /home/mc-survival/server/config
Chmod по смыслу, а не «на всякий случай 777»
Соблазн выставить chmod -R 777 на всю папку сервера, когда что-то не открывается, огромный — и это худшее, что можно сделать. 777 означает «читать, писать и выполнять может кто угодно», включая любой другой процесс и пользователя на этой же машине, а на многопользовательском VPS или при взломе соседнего сервиса это прямой путь к перезаписи ваших конфигов и world-файлов кем-то посторонним.
Разумная схема прав для типичного игрового сервера:
| Что | Права | Смысл |
|---|---|---|
| Папка сервера в целом | 750 | владелец — всё, группа — читать и заходить, остальные — ничего |
| Исполняемые файлы (бинарник сервера, скрипты запуска) | 750 или 700 | выполнение только владельцу (и группе, если нужно) |
Конфиги (server.properties, .yml, .cfg) | 640 | владелец пишет, группа читает, остальные — нет |
| Папка с миром/сохранениями | 750, файлы 640 | тот же принцип, но без исполняемых прав вообще |
| Логи | 640, папка 750 | панели часто нужно только читать, не писать |
find /home/mc-survival/server -type d -exec chmod 750 {} \;
find /home/mc-survival/server -type f -exec chmod 640 {} \;
chmod 750 /home/mc-survival/server/start.sh
Обратите внимание на разницу между find ... -type d и -type f: у директорий обязательно нужен бит выполнения (x), иначе в них нельзя будет зайти даже на чтение содержимого, а у обычных файлов конфигов и мира этот бит не нужен вовсе — не давайте его просто по инерции.
Запуск через systemd: изоляция без лишних телодвижений
Если процесс сервера поднимается через systemd (см. systemd, screen и tmux для игровых процессов), пользователь и группа задаются прямо в unit-файле — это надёжнее, чем надеяться, что кто-то не запустит ./start.sh вручную от root по привычке:
[Service]
User=mc-survival
Group=mc-survival
WorkingDirectory=/home/mc-survival/server
ExecStart=/usr/bin/java -Xmx4G -jar server.jar nogui
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/home/mc-survival/server
Три последние строки — не просто про пользователя, а про дополнительную песочницу от самого systemd: NoNewPrivileges запрещает процессу повышать привилегии даже если найдётся способ, ProtectSystem=strict делает всю файловую систему, кроме явно перечисленных путей, доступной только на чтение, а ReadWritePaths явно называет единственную папку, куда процессу можно писать. Даже если внутри самой игры найдут RCE, атакующий упрётся в то, что процесс физически не может писать за пределы своей папки сервера — не потому что «не должен», а потому что ядро ему это запретит.
Если вы используете Docker-контейнеры под каждый сервер (см. Docker Compose для стека игрового сервера), тот же принцип решается через user: в docker-compose.yml — не давайте контейнеру работать от root внутри, даже если хостовый Docker-демон формально требует root-доступ для своей работы:
services:
rust-server:
image: your-rust-image
user: "1000:1000"
volumes:
- ./data:/server/data
Здесь есть частая грабля: UID внутри контейнера (1000) должен совпадать с владельцем папки ./data на хосте, иначе получите либо permission denied при записи, либо — что хуже — файлы, созданные с UID, которого на хосте вообще нет ни у одного вашего пользователя.
ACL и точечный доступ без общих групп
Иногда групп не хватает — например, нужно дать одному конкретному человеку временный доступ на запись в одну папку, не заводя ради этого отдельную группу и не трогая владельца. Для этого есть списки контроля доступа (ACL), которые накладываются поверх обычных unix-прав:
sudo setfacl -m u:ivan:rwx /home/mc-survival/server/plugins
sudo getfacl /home/mc-survival/server/plugins
Первая команда даёт пользователю ivan полный доступ именно к папке с плагинами, не меняя владельца и не добавляя его ни в какую группу — удобно для временного доступа фрилансеру-разработчику плагина, которого не хочется пускать дальше одной директории. getfacl показывает текущие ACL-правила, которые обычный ls -l не отображает — про них легко забыть, поэтому периодически стоит проверять, не накопились ли на сервере точечные разрешения, о которых никто уже не помнит.
Отозвать ACL так же просто:
sudo setfacl -x u:ivan /home/mc-survival/server/plugins
Нужен игровой сервер?
MAATRIX GAMES — 45+ игр, деплой за минуты, DDoS-защита, автобэкапы. Тарифы от 399 ₽/мес.
Создать серверЧастые вопросы
Обязательно ли заводить отдельного системного пользователя под каждую игру, если сервер один и админ тоже один?
Строго обязательно — нет, но настоятельно рекомендуется. Даже на маленьком проекте разделение пользователей стоит 10 минут один раз и полностью снимает вопрос «а что если в плагине дыра» — процесс просто физически не сможет затронуть ничего, кроме своей папки.
Что делать, если после смены прав сервер перестал запускаться с ошибкой permission denied?
Сначала проверьте владельца через ls -la в папке сервера — часто причина в том, что при обновлении или восстановлении из бэкапа файлы пересоздались от root. Верните владельца через chown -R на игрового пользователя и убедитесь, что у исполняемых файлов и скриптов запуска есть бит x.
Панель управления требует root для некоторых операций — это нормально?
Отдельные операции (открытие портов ниже 1024, управление systemd-юнитами, работа с Docker-демоном) действительно требуют повышенных прав, и хорошо спроектированная панель делает это через ограниченный sudo (конкретные команды в /etc/sudoers.d/, а не безусловный root-доступ пользователю панели) или через systemd D-Bus API, а не через постоянную работу самой панели от root.
Нужно ли что-то менять в правах, если сервер работает в Docker-контейнере?
Да, изоляция контейнера не отменяет unix-права — если контейнер работает от root внутри и монтирует папку с хоста, файлы на хосте тоже создадутся от root, и это та же проблема, только на уровне ниже. Явно задавайте user: в конфигурации контейнера.
Как проверить, что права настроены правильно, если сервер уже давно работает?
Пройдитесь ps aux | grep <имя процесса>, чтобы увидеть, от какого пользователя реально запущен процесс сейчас, и find /home/ваш-пользователь/server -user root — вторая команда найдёт все файлы, которые всё ещё принадлежат root и требуют chown.