VPS Tutorials
Build a Valheim Dedicated Server on a VPS (2026): SteamCMD, Ports, Crossplay, Backups and Auto-Updates
Set up a Valheim dedicated server from scratch on an Ubuntu VPS with SteamCMD, covering App ID 896660, ports 2456–2457, Crossplay, world migration, admins, backup and restore, and automatic updates.

If you want to explore Valheim and build bases with friends over the long term without one player having to keep their PC running, a self-hosted Valheim dedicated server is the more stable choice. The server stays online around the clock, and you control the world files, access password, admin list, backups and update timing yourself — which also suits squads spread across time zones.
This article uses Ubuntu 24.04 LTS, SteamCMD, the official Valheim Linux server and systemd as examples to complete installation, ports 2456–2457, the Steam and Crossplay backends, world migration, the admin list, automatic backups, updates and troubleshooting. The main text does not depend on third-party game images; the mod section only explains risks and does not treat community mods as official features.
The official Valheim FAQ states that a server supports up to 10 players, but it does not publish a minimum spec for VPS scenarios that guarantees a given concurrency. The following are practical starting points for purchasing and stress testing, not a performance promise from Iron Gate:
| Usage scale | Suggested VPS starting point | Disk | Suitable scenario |
|---|---|---|---|
| 2–5 player vanilla server | 2–4 high-performance vCPUs, 4–8GB RAM | 40GB NVMe | Private world, light building |
| 6–10 player long-term server | 4 high-performance vCPUs, 8GB RAM | 60GB NVMe | Large bases, multiplayer exploration |
| Modded server or multiple instances | 6+ cores, 12–16GB RAM | 80GB+ NVMe | Multiple worlds, extra logs and backups |
Valheim's world simulation and large bases amplify single-core CPU, network jitter and storage latency problems. Don't look only at vCPU count; also consider whether the host is oversold during evening peak hours, UDP packet loss, snapshot pricing, DDoS handling and the cost of switching away from a faulty node. When choosing a data center, prioritize proximity to your main players; you can start with game server VPS configuration and network line selection.
The server does not need a dedicated GPU. The disk must hold the server, SteamCMD update temporary space, world files and off-site backup cache at the same time; don't squeeze the root partition down to a few GB left just to save a few dollars.
| Option | Advantages | Cost | Who it suits |
|---|---|---|---|
| SteamCMD + systemd | Transparent paths, few dependencies, easy to read logs and restore | Managed mainly via SSH | A single VPS, one Valheim world |
| Official Docker script | Can work around outdated GLIBC/GLIBCXX | Requires understanding volumes and container permissions | Old systems or existing Docker operations experience |
| Pterodactyl | Web panel, quotas, multiple instances and user management | Extra maintenance of Panel, Wings and the database | Hosting multiple game servers or multi-person operations |
The official Valheim server ships with docker_start_server.sh, but Ubuntu 24.04 already meets the GLIBC requirements listed officially. This article chooses native SteamCMD + systemd so you can clearly see startup parameters, save directories and stop signals. If you also host Minecraft, CS2, Rust and Valheim together, you can switch to the Pterodactyl game server panel deployment guide.
Valheim has two connection methods:
| Backend | Startup method | Network requirements | Suitable players |
|---|---|---|---|
| Steam | Do not add -crossplay | 2456–2457 UDP must be reachable from the public internet | All players on Steam |
| Crossplay | Add -crossplay | Relayed via PlayFab, no router port forwarding required | Steam mixed with other platforms |
The official guide states that a Crossplay server can be connected via public IP, port, join code or server list, but cannot be connected via the local loopback address or a LAN IP. A VPS has no home broadband NAT, so the Steam backend is usually more direct; enable Crossplay only when the team really includes players on non-Steam platforms.
This article first deploys the Steam backend and opens 2456–2457 UDP, then explains separately how to switch to Crossplay. Don't mix multiple network plugins of unknown origin at the same time, or you will complicate version or connection problems.
Using an admin account with sudo privileges, update the system and install SteamCMD and the Linux dependencies listed in the official Valheim guide:
sudo apt update
sudo apt upgrade -y
sudo apt install -y curl ca-certificates tar lib32gcc-s1 libatomic1 libpulse0 libpulse-dev ufw
Create a valheim account that is not used for daily login, plus a fixed directory:
sudo adduser --disabled-password --gecos "" valheim
sudo install -d -o valheim -g valheim /opt/steamcmd
sudo install -d -o valheim -g valheim /opt/valheim
sudo install -d -o valheim -g valheim /var/lib/valheim
sudo install -d -m 750 -o root -g valheim /var/backups/valheim
The server should not run as root. A dedicated account both limits process privileges and avoids file ownership confusion after SteamCMD updates.
Switch to the service account and download the Linux version of SteamCMD from Valve's Steam CDN:
sudo -iu valheim
cd /opt/steamcmd
curl -fsSL https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz -o steamcmd_linux.tar.gz
tar -xzf steamcmd_linux.tar.gz
./steamcmd.sh +quit
The first run updates SteamCMD. Confirm the entry point is executable:
test -x /opt/steamcmd/steamcmd.sh
The Steam App ID for the Valheim Dedicated Server is 896660. First try installing with an anonymous login; if you just finished another survival game server, you can also compare with the Palworld dedicated server SteamCMD tutorial to avoid mixing up App IDs, ports and save directories.
/opt/steamcmd/steamcmd.sh \
+force_install_dir /opt/valheim \
+login anonymous \
+app_update 896660 validate \
+quit
validate suits a first install or repairing corrupted files; daily updates usually don't need to validate every file each time. If Steam currently returns no license, no app info or an anonymous download failure, don't write your personal account password into a script. Prepare a separate Steam account that owns Valheim, log in to SteamCMD interactively and complete Steam Guard verification, then run app_update 896660 validate.
Check the Linux server and the official startup script:
test -x /opt/valheim/valheim_server.x86_64
test -f /opt/valheim/start_server.sh
ls -lh /opt/valheim/valheim_server.x86_64
du -sh /opt/valheim
exit
Don't modify the official start_server.sh directly. The official guide warns that this file may be overwritten during Steam updates; the systemd unit should store custom parameters separately.
The game password should not be written into public repositories or article commands. Create the environment file:
sudo install -d -m 700 -o root -g root /etc/valheim
sudo nano /etc/valheim/valheim.env
Write:
SERVER_NAME="My Valheim Server"
WORLD_NAME="Dedicated"
SERVER_PASSWORD="REPLACE_WITH_A_LONG_RANDOM_PASSWORD"
Generate a random password:
openssl rand -base64 24
Replace the result into SERVER_PASSWORD, then restrict permissions:
sudo chown root:root /etc/valheim/valheim.env
sudo chmod 600 /etc/valheim/valheim.env
systemd reads this file as PID 1, then starts the game as the valheim user. Administrators with root privileges can still see the service startup parameters, so don't open the server account to untrusted users.
Create the unit:
sudo nano /etc/systemd/system/valheim.service
Write:
[Unit]
Description=Valheim Dedicated Server
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=valheim
Group=valheim
WorkingDirectory=/opt/valheim
EnvironmentFile=/etc/valheim/valheim.env
Environment=SteamAppId=892970
Environment=LD_LIBRARY_PATH=/opt/valheim/linux64
ExecStart=/opt/valheim/valheim_server.x86_64 -nographics -batchmode -name ${SERVER_NAME} -port 2456 -world ${WORLD_NAME} -password ${SERVER_PASSWORD} -savedir /var/lib/valheim -public 1 -saveinterval 1800 -backups 4 -backupshort 7200 -backuplong 43200
Restart=on-failure
RestartSec=10
KillSignal=SIGINT
TimeoutStopSec=120
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
Here -savedir /var/lib/valheim is set explicitly so world files don't scatter into the service account's default Unity directory. The official documentation states that -port 2456 uses both the specified port and port+1, i.e. the default 2456–2457; KillSignal=SIGINT makes systemd simulate the officially recommended Ctrl+C shutdown method, leaving time for the world to save.
Load and start:
sudo systemctl daemon-reload
sudo systemctl enable --now valheim
sudo systemctl status valheim --no-pager
sudo journalctl -u valheim -n 150 --no-pager
Once the log shows Game server connected, the official documentation considers the service ready to accept connections. Creating a world for the first time may take a while; don't force-kill the process during initialization.
Keep the current SSH session open, first confirm SSH is allowed, then open the Valheim default ports:
sudo ufw allow OpenSSH
sudo ufw allow 2456:2457/udp
sudo ufw status numbered
sudo ufw enable
The cloud provider security group must also add the same UDP port range. Check what the service is actually listening on:
sudo ss -lunp | grep -E ':2456|:2457'
The most common mistake is changing only UFW and missing the cloud security group, or mistakenly writing the rule as TCP only. For a single Steam backend instance, open 2456–2457 UDP first; don't open a whole range of high ports without justification.
If the domain valheim.example.com points to the VPS, a normal A record is enough. Cloudflare's orange-cloud HTTP proxy cannot proxy Valheim game UDP traffic; set it to DNS only, or have players use the public IP directly.
In Valheim's join game screen, add a server and enter:
203.0.113.20:2456
Replace the example address with the VPS public IPv4. The domain form is:
valheim.example.com:2456
The server list may take time to refresh. If you can't find it, prefer direct join and check at the same time:
sudo systemctl is-active valheim
sudo journalctl -u valheim -n 200 --no-pager
sudo ss -lunp | grep -E ':2456|:2457'
sudo ufw status numbered
When the team includes players on non-Steam platforms, add this to the end of ExecStart:
-crossplay
Reload and restart:
sudo systemctl daemon-reload
sudo systemctl restart valheim
sudo journalctl -u valheim -n 200 --no-pager
The official documentation states that Crossplay uses PlayFab relay, does not require port forwarding, and supports connection via public IP, port, join code or server list. However, Crossplay cannot connect via the local loopback address or a LAN IP; when testing, use an external client and the join information shown officially.
If everyone is a Steam player, don't blindly enable Crossplay for the sake of "maybe faster". The two backends differ in discovery, connection and failure behavior; fix one option and complete acceptance first, then consider switching.
The official documentation defines three permission files:
adminlist.txt: admins.bannedlist.txt: players banned from joining.permittedlist.txt: players allowed to join; once the list is written, everyone else is rejected.
Because this article uses -savedir /var/lib/valheim, first locate the files actually generated:
sudo find /var/lib/valheim -maxdepth 2 -type f \
\( -name 'adminlist.txt' -o -name 'bannedlist.txt' -o -name 'permittedlist.txt' \) \
-print
Enter one Platform User ID per line in the format [Platform]_[User ID], case-sensitive. This ID can be obtained from the server log or the in-game F2 panel. Don't guess IDs from nicknames, and don't treat permittedlist.txt as an ordinary notes file, or you will accidentally reject all players not listed.
After making changes, restart and review the logs:
sudo systemctl restart valheim
sudo journalctl -u valheim -n 120 --no-pager
A world usually consists of a .db and a .fwl file with the same name. Before migrating, first switch cloud saves to local saves on the original PC and exit the game, then copy the files as a pair; don't upload only one of them.
On the VPS, stop the service and inspect the current save structure:
sudo systemctl stop valheim
sudo find /var/lib/valheim -maxdepth 3 -type f | sort
Upload the existing world files to the worlds_local directory generated by the server; assume the world name is MyWorld:
sudo install -d -o valheim -g valheim /var/lib/valheim/worlds_local
sudo cp /tmp/MyWorld.db /var/lib/valheim/worlds_local/MyWorld.db
sudo cp /tmp/MyWorld.fwl /var/lib/valheim/worlds_local/MyWorld.fwl
sudo chown valheim:valheim /var/lib/valheim/worlds_local/MyWorld.db
sudo chown valheim:valheim /var/lib/valheim/worlds_local/MyWorld.fwl
Change WORLD_NAME in /etc/valheim/valheim.env to MyWorld, then start and verify:
sudo systemctl start valheim
sudo journalctl -u valheim -n 200 --no-pager
If the server generates a new world, it is usually because the files were placed in the wrong directory, the file name case doesn't match, .db and .fwl are not paired, or WORLD_NAME doesn't match the file name. Keep the original copy, and only clean up temporary upload files after confirming the world buildings and character spawn points are correct.
The systemd startup parameters in this article already include:
-saveinterval 1800 -backups 4 -backupshort 7200 -backuplong 43200
The official meanings are as follows:
- Save the world every 1800 seconds.
- Keep 4 automatic backups.
- The first short-cycle backup interval is 7200 seconds.
- Subsequent long-cycle backup intervals are 43200 seconds.
These automatic backups can handle recent mistakes, but they cannot replace off-machine backups. If the disk fails, the account is compromised or the entire VPS is deleted, same-disk backups are lost along with it.
First do a manual consistent backup:
sudo systemctl stop valheim
sudo tar -C /var/lib/valheim -czf \
"/var/backups/valheim/valheim-save-$(date -u +%Y%m%dT%H%M%SZ).tar.gz" \
.
sudo systemctl start valheim
sudo systemctl is-active valheim
Inspect the archive contents:
sudo ls -lh /var/backups/valheim
sudo tar -tzf /var/backups/valheim/valheim-save-YYYYMMDDTHHMMSSZ.tar.gz | head -n 80
Replace the example file name with the real file. Sync at least one backup to another machine or object storage, and set a retention period. For a more complete off-site plan, see the VPS backup and restore drill guide.
Stop the service before restoring, and first keep the current save directory:
sudo systemctl stop valheim
sudo tar -tzf /var/backups/valheim/valheim-save-YYYYMMDDTHHMMSSZ.tar.gz | head -n 80
sudo mv /var/lib/valheim \
"/var/lib/valheim.before-restore-$(date -u +%Y%m%dT%H%M%SZ)"
sudo install -d -o valheim -g valheim /var/lib/valheim
sudo tar -C /var/lib/valheim -xzf \
/var/backups/valheim/valheim-save-YYYYMMDDTHHMMSSZ.tar.gz
sudo chown -R valheim:valheim /var/lib/valheim
sudo systemctl start valheim
Verify the logs, world name, buildings and permission lists:
sudo systemctl status valheim --no-pager
sudo journalctl -u valheim -n 200 --no-pager
sudo find /var/lib/valheim -maxdepth 3 -type f | sort
Restore is only complete after confirming multiplayer connections and world progress are correct. Keep valheim.before-restore-* until acceptance, and don't immediately delete the only rollback copy.
When client and server versions don't match, players encounter incompatible version. Create a maintenance script executable only by root:
sudo nano /usr/local/sbin/update-valheim-server
Write:
#!/usr/bin/env bash
set -euo pipefail
backup_dir=/var/backups/valheim
stamp=$(date -u +%Y%m%dT%H%M%SZ)
was_active=0
install -d -m 750 -o root -g valheim "$backup_dir"
if systemctl is-active --quiet valheim; then
was_active=1
systemctl stop valheim
fi
restart_service() {
if [ "$was_active" -eq 1 ]; then
systemctl start valheim
fi
}
trap restart_service EXIT
tar -C /var/lib/valheim -czf \
"$backup_dir/valheim-before-update-$stamp.tar.gz" \
.
sudo -u valheim /opt/steamcmd/steamcmd.sh \
+force_install_dir /opt/valheim \
+login anonymous \
+app_update 896660 \
+quit
Set permissions and test during a maintenance window:
sudo chown root:root /usr/local/sbin/update-valheim-server
sudo chmod 750 /usr/local/sbin/update-valheim-server
sudo /usr/local/sbin/update-valheim-server
sudo systemctl is-active valheim
sudo journalctl -u valheim -n 150 --no-pager
The script stops the service first and packages the entire save directory; if SteamCMD fails, the exit handler still tries to restore the original service state. If anonymous login is unavailable, don't hardcode the Steam password in the script; update interactively during a maintenance window, or use a dedicated account scheme with stricter credential isolation.
Only enable the timer after confirming anonymous SteamCMD works long-term and players accept a fixed maintenance window. Create the service:
sudo nano /etc/systemd/system/valheim-update.service
[Unit]
Description=Update Valheim Dedicated Server
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/update-valheim-server
Create the timer:
sudo nano /etc/systemd/system/valheim-update.timer
[Unit]
Description=Daily Valheim update maintenance window
[Timer]
OnCalendar=*-*-* 05:40:00
RandomizedDelaySec=10m
Persistent=true
[Install]
WantedBy=timers.target
Enable it and check the next run:
sudo systemctl daemon-reload
sudo systemctl enable --now valheim-update.timer
systemctl list-timers valheim-update.timer
Before large updates, the safer approach is to notify players, back up manually, update the server, then use a test client to confirm the world can be entered. Scheduled tasks should not suddenly stop the server during a boss fight or multiplayer building.
According to the official Valheim FAQ, fixed content such as new terrain, buildings or dungeons usually only appears in previously unexplored areas; explored areas also include roughly a 500-meter radius around player footprints. Before a major version release you should:
- Stop the service and make an off-site backup.
- Read the official patch notes and confirm the server and client versions.
- After updating, have an admin enter first to test.
- To experience new content, travel to unexplored areas, or evaluate whether to create a new world.
Don't directly delete .db, .fwl or backup files just to refresh new content. A world reset is an irreversible business decision and should be confirmed by all players.
The official Valheim FAQ explicitly states that mods are not officially supported. When running BepInEx or other community mods, additionally record mod versions, configuration files and installation sources, and disable automatic updates before game updates.
If version incompatibility, characters unable to enter or world anomalies occur, first test the vanilla server on a backup copy. Don't let the update script automatically overwrite mod files, and don't treat unverified server assemblies as official binaries.
First record real peak data:
free -h
df -h /opt/valheim /var/lib/valheim /var/backups/valheim
uptime
ps -C valheim_server -o pid,%cpu,%mem,rss,etime,cmd
sudo journalctl -u valheim --since "30 minutes ago" --no-pager
Focus on:
- Sustained single-core CPU saturation near large bases: prefer a node with stronger single-core performance and lower overselling.
- Latency and rollbacks during multiplayer exploration: check UDP packet loss, disk latency and save logs.
- Memory continuously growing or OOM: disable mods first, then evaluate scaling up.
- World and backups growing quickly: check the save directory, retention count and off-site sync strategy.
- Evening peak lag while daytime is normal: more likely neighbor overselling or line congestion, not just insufficient specs.
Don't judge only by the panel's average CPU. Valheim lag often occurs at specific bases, at the moment of saving or when players explore separately; reproduce it with timestamps, logs and player locations.
Check the status, the full unit and the logs:
sudo systemctl status valheim --no-pager
sudo journalctl -u valheim -n 250 --no-pager
sudo systemctl cat valheim
Focus on whether libatomic1, libpulse0 and libpulse-dev exist, whether LD_LIBRARY_PATH points to /opt/valheim/linux64, and whether the service account owns /opt/valheim and /var/lib/valheim.
Confirm the binary, network and Steam service status:
test -x /opt/valheim/valheim_server.x86_64
sudo -u valheim test -w /var/lib/valheim
sudo journalctl -u valheim -n 250 --no-pager | grep -iE 'error|steam|connected|failed'
On first startup, wait for world generation. If the log shows missing libraries, don't restart repeatedly; install dependencies by the missing names. If the Steam backend is temporarily unavailable, keep the world files and wait for the service to recover.
Check the service, listening, firewall and cloud security group in order:
sudo systemctl is-active valheim
sudo ss -lunp | grep -E ':2456|:2457'
sudo ufw status numbered
sudo journalctl -u valheim -n 200 --no-pager
Use the public IP for a direct connection to rule out DNS. For the Steam backend, confirm both 2456–2457 UDP are open; for Crossplay, check whether an internal or loopback address was mistakenly used, and check the PlayFab connection logs.
Stop the service first and update App ID 896660:
sudo /usr/local/sbin/update-valheim-server
sudo systemctl is-active valheim
sudo journalctl -u valheim -n 200 --no-pager
Confirm both client and server are on the same stable or test branch. For modded servers, also check BepInEx and each mod version; don't resolve version mismatch by deleting world files.
Stop the service and check the world name and files:
sudo systemctl stop valheim
sudo grep '^WORLD_NAME=' /etc/valheim/valheim.env
sudo find /var/lib/valheim -maxdepth 3 -type f \
\( -name '*.db' -o -name '*.fwl' \) -print
Make sure the base file names of WORLD_NAME and .db/.fwl are exactly the same, the files are in the save directory actually used by the service, and they are owned by valheim:valheim. After fixing, back up both the new and old file sets before starting to verify.
The service must be restarted after the environment file changes:
sudo systemctl restart valheim
sudo systemctl show valheim -p EnvironmentFiles
sudo journalctl -u valheim -n 120 --no-pager
When modifying the systemd unit itself, also run systemctl daemon-reload first. Don't define the same parameter repeatedly across multiple startup scripts, units and panels, or it becomes hard to tell which value finally takes effect.
- SteamCMD installed the Valheim Dedicated Server App ID 896660.
- The service runs as the dedicated
valheimuser, not root. -
systemctl is-active valheimreturnsactive. - The log shows
Game server connected. - The Steam backend's 2456–2457 UDP is allowed in both UFW and the cloud security group.
- Crossplay is enabled only when there really are cross-platform players, and tested with an external client.
-
/etc/valheim/valheim.envhas permissions 600 and is owned by root. - The world
.dband.fwlfiles exist as a pair, with names matchingWORLD_NAME. - Admins and whitelist contain case-sensitive Platform User IDs.
- The official autosave parameters are in effect.
- Backups are taken with the service stopped before updates, and at least one is kept off-machine.
- A world restore has actually been performed, verifying buildings, character spawn points and permission lists.
- Modded servers have untested automatic updates disabled.
Running Valheim stably on a VPS is not just about getting the server started; the key is fixing the save directory, correctly distinguishing the Steam and Crossplay backends, opening 2456–2457 UDP, using SIGINT for graceful shutdown, and building world backup and restore drills into the update process.
A 2–5 player vanilla world can start from a high-performance 2–4 vCPU, 4–8GB RAM setup, while approaching 10 players, large bases or modded servers should scale up gradually based on real CPU peaks, memory and network jitter. Before going live, completing one external connection, world migration, version update and restore test reduces rollbacks and downtime more than blindly adding ports or automation.