Проще всего запустить Valheim в Docker с помощью образа от сообщества lloesche/valheim-server (он опубликован в реестре GitHub как ghcr.io/lloesche/valheim-server). Он скачивает сервер через SteamCMD при первом запуске, работает под супервизором, который каждые пятнадцать минут проверяет обновления и раз в час делает архив-бэкап, а настраивается целиком через переменные окружения: SERVER_NAME, WORLD_NAME, SERVER_PASS, а также SERVER_ARGS для всего остального, например -crossplay. Вы монтируете два тома - /config для миров, бэкапов и файлов списков и /opt/valheim для установки сервера, пробрасываете UDP 2456-2457, задаёте льготный период остановки в пару минут, и всё работает. Значения по умолчанию разумны для ванильного сервера; два, которые стоит поменять на модифицированном, - это расписание обновлений и, если вам важно место на диске, срок хранения бэкапов.
Статья предполагает, что Docker и Compose на машине уже работают. Если нет, до этого доведёт Docker на VDS. Об установке без контейнера читайте в статье Valheim на Linux через SteamCMD.
Зачем вообще запускать Valheim в контейнере#
Обычная установка с юнитом systemd вполне хороша, так что контейнер должен заслужить своё место. Что он даёт:
- Ничего не ставится на хост, кроме Docker. Ни архитектуры
i386, ни пакета SteamCMD, ни библиотек для кроссплея. Пересборка машины - это «установить Docker, вернуть две папки,docker compose up -d». - Уже настроенные по расписанию обновления, перезапуски и бэкапы с проверкой простоя, так что ни одно из них не прерывает игроков. На обычной установке эти задания пришлось бы писать самому.
- Чёткое разделение, когда на той же машине работает что-то ещё - бот Discord, второй игровой сервер, сайт. Каждый живёт в своём контейнере со своими портами и файлами.
Чего это стоит: ещё один слой, в котором придётся разбираться, логи, которые идут через супервизор, а не напрямую от сервера, и зависимость от образа, который поддерживает сообщество. Образ широко используется и активно развивается, но это не продукт Iron Gate; когда что-то меняется, читайте его README, потому что именно README - авторитетный источник по его переменным, а не эта статья. Имена переменных и значения по умолчанию ниже взяты из README на момент написания.
Файл compose#
docker-compose.yml с важными настройками:
services: valheim: image: ghcr.io/lloesche/valheim-server container_name: valheim cap_add: - sys_nice volumes: - ./config:/config - ./data:/opt/valheim ports: - "2456-2457:2456-2457/udp" env_file: - ./valheim.env restart: unless-stopped stop_grace_period: 2mSERVER_NAME=Longship CrewWORLD_NAME=MidgardSERVER_PASS=herring-barrel-42SERVER_PUBLIC=trueTZ=Europe/Berlin$ mkdir -p ~/valheim && cd ~/valheim$ docker compose up -d$ docker compose logs -fПервый запуск занимает несколько минут: контейнер запускает SteamCMD, скачивает сервер в ./data, затем стартует его и создаёт мир. Дождитесь тех же строк лога, что печатает обычный сервер, - Load world: Midgard и Game server connected, - прежде чем пробовать подключиться.
Три строки compose-файла заслуживают пояснения:
stop_grace_period: 2mдаёт серверу время на сохранение. Приdocker compose downилиdocker stopDocker посылает сигнал остановки, супервизор передаёт Valheim команду на чистое завершение, и мир записывается. Льготный период Docker по умолчанию - 10 секунд, после чего он присылаетSIGKILL, а большой мир, не успевший сохраниться, теряет всё с момента последнего сохранения. Это самая важная строка в файле. Вdocker runей соответствует--stop-timeout 120.cap_add: sys_niceпозволяет серверу повышать приоритет собственного процесса, что рекомендует README. Если её убрать, ничего страшного: вы потеряете небольшое преимущество в планировании под нагрузкой.restart: unless-stoppedвозвращает контейнер после перезагрузки или сбоя, но не после того, как вы остановили его намеренно.
Файл с переменными убирает пароль из compose-файла, поэтому compose-файлом можно делиться или коммитить его, ничего не раскрыв. Сделайте valheim.env читаемым только для себя.
Переменные окружения, которые важны#
У образа десятки переменных. Вот те, что задают чаще всего или о которых стоит знать:
| Переменная | По умолчанию | Что делает |
|---|---|---|
SERVER_NAME | My Server | Название в списке серверов |
SERVER_PORT | 2456 | Игровой порт; сервер использует и следующий за ним |
WORLD_NAME | Dedicated | Файл мира, который загружается или создаётся |
SERVER_PASS | secret | Пароль для входа, минимум 5 символов |
SERVER_PUBLIC | true | Показывать в общем списке |
SERVER_ARGS | пусто | Дополнительные аргументы запуска, передаются как есть |
ADMINLIST_IDS | пусто | ID через пробел, записываются в adminlist.txt |
BANNEDLIST_IDS | пусто | ID, записываются в bannedlist.txt |
PERMITTEDLIST_IDS | пусто | ID, записываются в permittedlist.txt |
TZ | Etc/UTC | Часовой пояс, в котором работают расписания cron |
PUID / PGID | 0 | Пользователь и группа - владельцы файлов |
В SERVER_ARGS попадает всё, у чего нет собственной переменной, - кроссплей, модификаторы мира, более короткий интервал сохранения:
SERVER_ARGS=-crossplay -saveinterval 900 -preset casual -modifier portals casualНе повторяйте -name, -world, -password и -port в SERVER_ARGS; образ уже собирает их из отдельных переменных, а дубликаты дают путаные результаты. Каждый аргумент и его подводные камни описаны в справочнике по аргументам запуска Valheim.
У переменных списков есть острый край, хотя пользоваться ими удобно: при запуске образ записывает их в файлы списков, так что ID, который вы добавили в adminlist.txt вручную и забыли внести в ADMINLIST_IDS, может не пережить следующий перезапуск. Выберите один способ и держитесь его. Форматы ID, в том числе платформенные префиксы, нужные кроссплею, описаны в руководстве по файлам списков Valheim.
PUID и PGID определяют, кому принадлежат файлы в томах. При значении по умолчанию 0 они принадлежат root на хосте, и редактировать их по SFTP от обычного пользователя неудобно. Если вы будете править файлы на хосте, до первого запуска задайте оба значения равными ID своего пользователя (id -u и id -g).
Тома: где на самом деле живёт мир#
| Путь в контейнере | Папка на хосте выше | Содержимое |
|---|---|---|
/config | ./config | worlds_local/, backups/, adminlist.txt и остальные, конфигурация BepInEx |
/opt/valheim | ./data | Установка сервера и установка BepInEx |
Беречь нужно /config. Это аналог папки сохранений при обычной установке: миры лежат в /config/worlds_local, бэкапы образа - в /config/backups, три файла списков - на верхнем уровне. /opt/valheim можно выбросить: если он пуст, контейнер снова скачает сервер при следующем запуске. Монтировать его всё же стоит, чтобы при пересборке контейнера не скачивать каждый раз гигабайт-другой.
Чтобы перенести существующий мир, остановите контейнер, скопируйте Midgard.db и Midgard.fwl в ./config/worlds_local/, задайте WORLD_NAME=Midgard - с точным совпадением регистра - и запустите. Если в логе сказано, что мир создаётся, а не загружается, значит, имя не совпало. Полная процедура, включая миры из Steam Cloud, описана в статье загрузка локального мира Valheim на сервер.
Для /config используйте bind-тома (папки на хосте), а не именованные тома. Так вы видите файлы, копируете их обычными средствами и делаете бэкап, не обращаясь к Docker.
Обновления и перезапуски по расписанию#
Образ запускает проверку обновлений по расписанию cron внутри контейнера:
| Переменная | По умолчанию | Значение |
|---|---|---|
UPDATE_CRON | */15 * * * * | Проверять в SteamCMD новую сборку сервера каждые 15 минут |
UPDATE_IF_IDLE | true | Применять обновление, только когда нет подключённых игроков |
RESTART_CRON | 0 5 * * * | Ежедневный перезапуск в 05:00 по TZ |
RESTART_IF_IDLE | true | Пропустить перезапуск, если на сервере игроки |
STEAMCMD_ARGS | validate | Дополнительные аргументы обновления через SteamCMD |
Когда проверка находит новую сборку и никто не играет, образ чисто останавливает сервер, обновляет его и снова запускает. Для ванильной группы это именно то, что нужно: после патча Valheim сервер, как правило, уже актуален раньше, чем все успеют обновить свою игру.
Для модифицированного сервера это как раз то, чего делать нельзя. Патч Valheim ломает моды BepInEx, пока их авторы не обновятся, а образ, который обновляется сам, как только сервер пуст, оставит вам сломанный сервер наутро после дня патча. Отключите это, задав пустое значение UPDATE_CRON, и обновляйтесь сознательно, когда моды будут готовы: сделайте бэкап, затем docker compose restart - образ проверяет обновления при запуске - и проверьте работу. О выборе времени рассказывает статья как обновить сервер Valheim.
Ежедневный перезапуск стоит оставить. Долго работающий мир растёт в памяти, а перезапуск в час, когда никто не играет, держит этот рост на месте. Если ваша группа играет в 05:00 по местному времени, перенесите его и убедитесь, что задан TZ, иначе расписание пойдёт по UTC.
Бэкапы внутри контейнера и вне его#
Образ делает собственные бэкапы, отдельные от встроенной ротации Valheim -backups:
| Переменная | По умолчанию | Значение |
|---|---|---|
BACKUPS | true | Включить задание бэкапа |
BACKUPS_CRON | 5 * * * * | Каждый час, в пять минут |
BACKUPS_DIRECTORY | /config/backups | Куда складывать архивы |
BACKUPS_MAX_AGE | 3 | Удалять архивы старше этого числа дней |
BACKUPS_MAX_COUNT | 0 | Хранить не больше столько (0 - без ограничения по числу) |
BACKUPS_IF_IDLE | true | Продолжать бэкапы, пока сервер пуст |
BACKUPS_IDLE_GRACE_PERIOD | 3600 | Секунд после ухода последнего игрока, пока бэкапы простоя не прекращаются |
BACKUPS_ZIP | true | Сжимать архивы |
Каждый час и хранение три дня - разумное значение по умолчанию: 72 снимка мира, который в сжатом виде редко превышает 100 MB. Бэкапы берутся из файлов на диске, поэтому содержат мир на момент последнего сохранения, а не последней минуты игры; более короткий -saveinterval в SERVER_ARGS делает их свежее.
Слабое место - расположение. /config/backups лежит на том же диске, что и защищаемый мир. Умерший диск, удалённая папка или взломанный хост унесут и то и другое. Копируйте архивы с машины - на другой сервер, в объектное хранилище через rclone или AWS CLI, куда угодно - по собственному расписанию. Образ предлагает POST_BACKUP_HOOK - команду, которую он выполняет после каждого архива, подставляя путь к файлу вместо @BACKUP_FILE@; это удобное место, чтобы повесить загрузку. Как устроена выгрузка, показывает статья бэкапы игровых серверов в S3, а восстановление и распознавание повреждённого мира разобраны в статье бэкапы сервера Valheim и повреждение мира.
Чтобы восстановить мир, остановите контейнер, распакуйте нужный архив в ./config/worlds_local/ поверх текущей пары .db и .fwl (сначала сохраните копию текущей пары) и запустите контейнер.
BepInEx и моды в контейнере#
Задайте BEPINEX=true, и образ при запуске скачает BepInExPack для Valheim и запустит сервер через него. Файлы модов .dll затем кладутся в папку плагинов внутри /config/bepinex/ в текущих версиях образа - точный путь уточните в README, если папка не там, где вы ожидаете, - а их конфигурационные файлы появляются в /config/bepinex/config после первого запуска с загруженным модом. После добавления или удаления мода перезапустите контейнер.
BEPINEX=trueUPDATE_CRON=Есть также VALHEIM_PLUS=true, который ставит Valheim Plus вместо BepInEx. Оригинальный проект Valheim Plus давно не поспевает за игрой, и большинство групп теперь пользуются поддерживаемыми форками или отдельными модами; не включайте его, если не уверены, что полученная версия работает с актуальной игрой. Никогда не включайте оба сразу.
Всё остальное про моды так же, как на обычном сервере: моды, меняющие правила игры, должны быть установлены в одной и той же версии у всех клиентов, игроки с Xbox не смогут зайти на сервер, которому нужны клиентские моды, а моды на основе Jotunn выкидывают любого, чьи версии не совпадают. Какие моды куда ставить, описано в статье моды Valheim с BepInEx на сервере, а самый частый сбой - в статье вылеты из-за несовпадения версий модов.
Устранение неполадок контейнера#
Контейнер запускается, но никто не может подключиться. В пробросе портов нужен /udp; "2456-2457:2456-2457" без него пробрасывает TCP, и Valheim ничего не получает. Затем проверьте файрвол хоста - Docker вставляет собственные правила iptables, но файрвол облачного провайдера всё равно должен пропускать UDP 2456-2457. Полный перечень есть в статье порты Valheim.
Мир сбрасывается при каждом пересоздании. /config не смонтирован или смонтирован в другую папку, чем в прошлый раз. docker compose down с последующим up уничтожает контейнер, но никогда - смонтированную папку.
Прогресс потерян после `docker compose down`. Льготный период был слишком коротким, и сервер убили посреди сохранения. Задайте stop_grace_period: 2m и при следующей остановке следите по логам, завершается ли сохранение.
Перезапуски из-за нехватки памяти. Контейнер с лимитом памяти, который мир перерос, убивается без сохранения. Либо поднимите лимит, либо уберите его; реалистичные цифры есть в статье сколько RAM нужно серверу Valheim.
Файлы в `./config` принадлежат root. PUID и PGID остались равными 0. Задайте их и один раз выполните chown для существующих папок.
На RE:NODE каждый сервер и так работает в собственном контейнере, так что вы получаете ту же изоляцию без поддержки образа: аргументы запуска - это поля на вкладке Startup, остановка всегда чисто сохраняет мир, а бэкапы уходят с машины и восстанавливаются кнопкой.
FAQ#
lloesche/valheim-server - официальный образ?
Нет. Это проект сообщества, его не публикуют ни Iron Gate, ни Valve. Он популярен и поддерживается, но единственный авторитетный источник по его переменным и поведению - его README.
Как увидеть код присоединения для кроссплея в Docker?
Добавьте -crossplay в SERVER_ARGS, перезапустите и прочитайте его в docker compose logs. Код печатается при каждом запуске и каждый раз меняется.
Как выполнить команду в консоли сервера?
В ванильном Valheim у сервера нет ввода в консоль и нет RCON. Админские команды вводит в игре по F5 игрок из adminlist.txt, и в контейнере это работает так же.
Можно ли запустить два сервера Valheim с этим образом?
Да. Используйте два сервиса с разными container_name, отдельными папками config и data, разными значениями SERVER_PORT с разницей не меньше трёх и соответствующими пробросами портов. Оба могут работать на одной машине, пока хватает памяти.
Добавляет ли Docker лаги?
Заметно - нет. Проброс портов добавляет несколько микросекунд на пакет, что намного меньше всего, что игрок способен увидеть. Используйте network_mode: host, только если есть причина: он убирает проброс, но и изоляцию тоже.


