valheim-thunderstore
Docker app from czerwonowlosy's Repository
Overview
Valheim dedicated server with Thunderstore mod support.
- Installs mods (and their dependencies) straight from thunderstore.io: list them by name or paste an r2modman / Thunderstore Mod Manager profile code.
- Keeps Valheim and your mods up to date automatically, waiting until nobody is online before restarting.
- Lets you choose the world seed, difficulty preset and world modifiers for new worlds.
- Backs up the world before every restart and saves cleanly on stop.
First start downloads about 1 GB of server files, so give it a few minutes. Forward UDP 2456-2457 on your router to play over the internet.
Readme
View on GitHubValheim server for Unraid (Thunderstore mods, auto-updates, custom seed)
A Docker app for Unraid that runs a Valheim dedicated server and:
- Installs mods from Thunderstore: list mods by name or link, or paste an r2modman / Thunderstore Mod Manager profile code. BepInEx and all dependencies are installed for you.
- Updates automatically: checks Valheim and every mod in the background, waits until nobody is online, backs up the world, then restarts with the new versions.
- Lets you pick the world seed (plus difficulty preset and world modifiers) for new worlds.
- Saves the world cleanly when the container stops, restarts the server if it crashes, and keeps rolling world backups.
1. Publish the image (one time)
- Create a GitHub repository called
valheim-unraidand push this folder to it. - Replace
czerwonowlosy666inunraid/valheim-thunderstore.xmlwith your GitHub username (lowercase) and push. - The Build image action runs the tests and publishes
ghcr.io/<you>/valheim-unraid:latest. - On GitHub go to your profile, Packages, valheim-unraid, Package settings, and set visibility to Public so Unraid can pull it without logging in.
The image does not contain the game. Valheim is downloaded by SteamCMD on first start and updated from then on, so you only need to rebuild the image when you change the scripts. The workflow also rebuilds weekly to pick up Debian security fixes.
2. Add it to Unraid
Open the Unraid terminal and run:
wget -O /boot/config/plugins/dockerMan/templates-user/my-valheim-thunderstore.xml \
https://raw.githubusercontent.com/czerwonowlosy666/valheim-unraid/main/unraid/valheim-thunderstore.xml
Then go to Docker, Add Container, choose valheim-thunderstore from the Template list, fill in the settings and click Apply.
The first start downloads about 1 GB, so watch the container log until you see Game server connected. To play over the internet, forward UDP 2456-2457 on your router to your Unraid server.
Settings
The main settings are shown by default; click Show more settings in the template for the rest.
| Setting | Variable | Default | Notes |
|---|---|---|---|
| Server name | SERVER_NAME |
My Valheim Server | |
| World name | WORLD_NAME |
Dedicated | Changing it starts a new world. Old worlds stay in saves/. |
| Password | SERVER_PASS |
At least 5 characters, not part of the server name. | |
| World seed | WORLD_SEED |
random | Only used when the world is created. See below. |
| Public | SERVER_PUBLIC |
false | Show in the community server list. |
| Crossplay | CROSSPLAY |
false | Lets Xbox / Game Pass players join. |
| Admins | ADMINS |
SteamID64s, comma separated. Written to saves/adminlist.txt. |
|
| Mods | MODS |
See below. | |
| Profile code | THUNDERSTORE_PROFILE_CODE |
See below. | |
| Exclude mods | MODS_EXCLUDE |
Mods to skip, e.g. client-only UI mods from your profile. | |
| Auto update | AUTO_UPDATE |
true | Background checks. Updates are always applied when the container starts. |
| Update check interval | UPDATE_CHECK_INTERVAL |
60 | Minutes. |
| Only update when empty | UPDATE_WHEN_IDLE |
true | Waits for 0 players before restarting. |
| Max wait for empty server | UPDATE_MAX_WAIT |
360 | Minutes, then it restarts anyway. 0 = never force. |
| Update Valheim / Update mods | SERVER_AUTO_UPDATE / MODS_AUTO_UPDATE |
true | Turn either part of auto-update off. |
| Steam branch | STEAM_BRANCH |
public | e.g. public-test (with STEAM_BRANCH_PASSWORD). |
| Difficulty preset | WORLD_PRESET |
normal, casual, easy, hard, hardcore, immersive, hammer | |
| World modifiers | WORLD_MODIFIERS |
e.g. combat:hard, raids:none, resources:more |
|
| World keys | WORLD_KEYS |
e.g. nomap, playerevents |
|
| Backup on restart / Backups to keep | BACKUP_ON_RESTART / BACKUP_KEEP |
true / 10 | |
| Extra server arguments | SERVER_ARGS |
Passed straight to valheim_server, e.g. -saveinterval 600. |
|
| PUID / PGID | PUID / PGID |
99 / 100 | Unraid's nobody:users. |
Mods
By name. Put mods in Mods, separated by commas. Each one can be:
Author-ModName: always the latest version, auto-updated.Author-ModName-1.2.3: pinned to that version, never updated.- A Thunderstore link such as
https://thunderstore.io/c/valheim/p/Azumatt/AzuCraftyBoxes/.
Example: ValheimModding-Jotunn, Azumatt-AzuCraftyBoxes, Smoothbrain-ServerCharacters-1.4.0
You don't need to list BepInEx or dependencies. Modpacks work too: add the modpack and everything it depends on gets installed.
From your mod manager. In r2modman or Thunderstore Mod Manager open Settings, Profile, Export profile as code, and paste the code into Profile code.
- Disabled mods in the profile are skipped.
- Mods are updated to their latest versions unless you set Pin profile versions to true.
- The profile's config files are copied the first time, but files you already have are never overwritten.
- Codes expire after a while. The container keeps its own copy of the profile, so it keeps working.
- Many profiles include client-only mods (UI, minimap and so on). Put those in Exclude mods.
Your own plugins. DLLs that aren't on Thunderstore can go in custom-plugins/ inside the Data folder. They are copied into BepInEx on every start, and BepInEx is installed automatically if needed.
Mod configs live in bepinex-config/ inside the Data folder. Edit them there and restart the container.
Removing a mod. Remove it from the list and restart. Its files are deleted, but its config file is kept.
Players need the same gameplay mods on their PC. The easiest way is to share the same r2modman profile code with them.
World seed
Valheim's server has no seed option, so the container writes the new world's metadata file itself, using the 1.0 world format, before the first start. The server then generates the world from that seed.
- The seed is 1-10 characters, exactly as you would type it in the game.
- It only applies to a world that doesn't exist yet. If
WORLD_NAMEalready exists, the log warns you and the existing world is left alone. To use a new seed, choose a new world name. - The seed of the running world is shown in the log at every start (
World: Dedicated (seed: ...)).
You can also use an existing world. Stop the container, copy the world into saves/worlds_local/ (the whole world folder for Valheim 1.0 worlds, or the Name.db + Name.fwl pair for older ones), and set World name to match. Keep a copy of the original until you've checked it loads.
Updates
Every time the container starts it updates Valheim through SteamCMD and syncs mods with Thunderstore. While it runs, the updater checks every UPDATE_CHECK_INTERVAL minutes:
- It compares the installed Valheim build with Steam, and every mod with Thunderstore.
- If something is new, it waits for 0 players. It reads the player count from the Steam query port. With crossplay the count isn't available, so it waits
UPDATE_MAX_WAITminutes instead. - It stops the server, which saves the world. Then it backs up the world, installs the updates and starts the server again.
If Thunderstore is down, the server starts with the mods it already has. Nothing is removed just because a lookup failed.
Folders
Data (/config, default /mnt/user/appdata/valheim/data):
saves/worlds_local/ your worlds
saves/adminlist.txt admins / bannedlist.txt / permittedlist.txt
backups/ world backups (.tar.gz), newest BACKUP_KEEP kept
bepinex-config/ mod config files
custom-plugins/ your own plugin DLLs
logs/valheim.log server log (previous runs: valheim.log.1 ... .4)
Server files (/opt/valheim, default /mnt/user/appdata/valheim/server) holds the game, BepInEx and installed mods. You can delete it at any time; it is re-downloaded.
Restore a backup. Stop the container, delete saves/worlds_local/<World>, and extract the backup inside saves/ with tar -xzf ../backups/<file>.tar.gz. Then start the container.
Troubleshooting
- Players can't find the server. Join with the IP instead: in Valheim choose Join IP and enter
your-public-ip:2456. Check that UDP 2456-2457 is forwarded. The community list can take a few minutes to show a new server. - The server stops right after starting. Check the password rules above, and look at
logs/valheim.log. - A mod breaks the server. Pin it to an older version (
Author-Mod-1.2.3) or add it to Exclude mods, then restart. - The container takes a long time to stop. It is saving the world. The template gives it 120 seconds (
--stop-timeout=120) so Unraid doesn't kill it mid-save.
Development
scripts/supervisor.sh main loop: update, mods, world, start; restart and stop handling
scripts/updater.sh background update checker
scripts/thunderstore.py Thunderstore mod manager (sync / check / list)
scripts/valheim_world.py world metadata writer for custom seeds
scripts/player_count.py Steam A2S player count
tests/ offline tests with a mock Thunderstore, fake SteamCMD and fake server
Run the tests with bash tests/test_mods.sh && bash tests/test_supervisor.sh. They need Python 3 with PyYAML, and no network or Docker.
The seed format is ported from MakeFwl by Crystal Ferrai (Apache-2.0).
Requirements
Categories
Related apps
Explore more like this
Explore allDetails
ghcr.io/czerwonowlosy666/valheim-unraid:latestRuntime arguments
- Network
bridge- Shell
bash- Privileged
- false
- Extra Params
--stop-timeout=120
Template configuration
Valheim game port. Keep host and container port the same as SERVER_PORT.
- Target
- 2456
- Default
- 2456
- Value
- 2456
Steam query port (game port + 1). Used for the server browser and the player count.
- Target
- 2457
- Default
- 2457
- Value
- 2457
Worlds (saves/), backups, mod configs (bepinex-config/), your own plugins (custom-plugins/) and logs.
- Target
- /config
- Default
- /mnt/user/appdata/valheim/data
- Value
- /mnt/user/appdata/valheim/data
Valheim server files, BepInEx and installed mods. Can be deleted; everything here is re-downloaded.
- Target
- /opt/valheim
- Default
- /mnt/user/appdata/valheim/server
- Value
- /mnt/user/appdata/valheim/server
Name shown in the server browser.
- Target
- SERVER_NAME
- Default
- My Valheim Server
- Value
- My Valheim Server
World to load or create (letters and numbers, no spaces recommended). Changing it starts a new world; the old one stays in saves/.
- Target
- WORLD_NAME
- Default
- Dedicated
- Value
- Dedicated
At least 5 characters, and must not be part of the server name.
- Target
- SERVER_PASS
Seed for a NEW world (1-10 characters, e.g. HHcLC5acQt). Leave empty for random. Has no effect on a world that already exists.
- Target
- WORLD_SEED
List the server in the in-game community server browser.
- Target
- SERVER_PUBLIC
- Default
- false|true
- Value
- false
Allow Xbox / Microsoft Store players (uses PlayFab; the player count for idle updates is not available with crossplay).
- Target
- CROSSPLAY
- Default
- false|true
- Value
- false
SteamID64s of admins, separated by commas. Leave empty to manage saves/adminlist.txt yourself.
- Target
- ADMINS
Thunderstore mods, separated by commas: Author-ModName (always latest), Author-ModName-1.2.3 (pinned) or the mod's thunderstore.io link. Dependencies and BepInEx are installed automatically. Example: ValheimModding-Jotunn, Azumatt-AzuCraftyBoxes
- Target
- MODS
Optional. In r2modman or Thunderstore Mod Manager: Settings, Profile, Export profile as code. Installs the same mods as your client profile (saved locally, so it keeps working after the code expires).
- Target
- THUNDERSTORE_PROFILE_CODE
Mods never to install, e.g. client-only UI mods from your profile. Same format as Mods.
- Target
- MODS_EXCLUDE
true = keep the exact mod versions from the profile instead of updating them.
- Target
- PROFILE_PIN_VERSIONS
- Default
- false|true
- Value
- false
Copy config files from the profile code (only files you don't already have).
- Target
- PROFILE_IMPORT_CONFIGS
- Default
- true|false
- Value
- true
Install BepInEx even with no Thunderstore mods. Happens automatically when custom-plugins/ has files.
- Target
- BEPINEX_ENABLED
- Default
- false|true
- Value
- false
Check for Valheim and mod updates in the background and restart to apply them. Updates are always applied when the container starts.
- Target
- AUTO_UPDATE
- Default
- true|false
- Value
- true
Include Valheim itself in background updates.
- Target
- SERVER_AUTO_UPDATE
- Default
- true|false
- Value
- true
Include Thunderstore mods in background updates.
- Target
- MODS_AUTO_UPDATE
- Default
- true|false
- Value
- true
Minutes between update checks.
- Target
- UPDATE_CHECK_INTERVAL
- Default
- 60
- Value
- 60
Wait until no players are online before restarting for an update.
- Target
- UPDATE_WHEN_IDLE
- Default
- true|false
- Value
- true
Minutes to wait for an empty server before restarting anyway (0 = wait forever).
- Target
- UPDATE_MAX_WAIT
- Default
- 360
- Value
- 360
Valheim branch, e.g. public or public-test.
- Target
- STEAM_BRANCH
- Default
- public
- Value
- public
Password for a protected branch (public-test uses yesimadebackups).
- Target
- STEAM_BRANCH_PASSWORD
Optional: normal, casual, easy, hard, hardcore, immersive or hammer.
- Target
- WORLD_PRESET
Optional, comma separated name:value. combat (veryeasy-veryhard), deathpenalty (casual-hardcore), resources (muchless-most), raids (none-muchmore), portals (casual, hard, veryhard). Example: combat:hard, raids:none
- Target
- WORLD_MODIFIERS
Optional, comma separated: nomap, playerevents, passivemobs, nobuildcost, fire, teleportall
- Target
- WORLD_KEYS
Save a .tar.gz of the world to backups/ before every start.
- Target
- BACKUP_ON_RESTART
- Default
- true|false
- Value
- true
Number of world backups to keep.
- Target
- BACKUP_KEEP
- Default
- 10
- Value
- 10
Only change together with both port mappings (host and container) above.
- Target
- SERVER_PORT
- Default
- 2456
- Value
- 2456
Passed straight to valheim_server, e.g. -saveinterval 600 -backups 4
- Target
- SERVER_ARGS
User ID files are owned by (99 = nobody).
- Default
- 99
- Value
- 99
Group ID files are owned by (100 = users).
- Default
- 100
- Value
- 100
Timezone for logs and backup names.
- Target
- TZ
- Default
- Europe/London
- Value
- Europe/London