Running a Valheim Dedicated Server on Linux With SteamCMD
Published and official references checked 2026-08-29 · SameOS operator
The hard parts of Valheim hosting are not the download. Operators need to distinguish Steam networking from Crossplay, avoid losing startup edits during an update, and know where worlds and permission files actually live. This setup installs app 896660 under a dedicated account, shuts it down through systemd, and keeps the recoverable data in one explicit directory.
Choose Steam or Crossplay First
The default Steam backend uses the selected port and the next port; the official default range is UDP 2456-2457. External Steam joins require both to be forwarded to the host. Adding -crossplay selects the PlayFab relay so players on supported platforms can join without router port forwarding.
The official guide notes that a Crossplay server cannot be joined through a local or loopback address; use its public address, join code, or listing. Decide whether LAN-address testing or cross-platform access matters before configuration, because the two backends produce different connection tests.
Install App 896660 as a Dedicated User
SteamCMD permits anonymous installation. Separate replaceable binaries from recoverable data: this example puts the server under /srv/valheim/server and worlds under /srv/valheim/data. The official Linux notes list libatomic and PulseAudio libraries that may be required on a minimal host.
sudo apt update
sudo apt install -y steamcmd libatomic1 libpulse0
sudo useradd --system --create-home --home-dir /srv/valheim \
--shell /usr/sbin/nologin valheim
sudo install -d -o valheim -g valheim /srv/valheim/server /srv/valheim/data
sudo -u valheim steamcmd \
+force_install_dir /srv/valheim/server \
+login anonymous +app_update 896660 validate +quit
Keep Startup Settings Outside Updated Files
The packaged start_server.sh can be reset by a Steam update. Do not edit the only copy; put arguments in a copied script or the systemd unit. -savedir keeps worlds plus adminlist.txt, bannedlist.txt, and permittedlist.txt outside the replaceable application directory.
This example is an unlisted Steam server. Replace PASSWORD with the join password. Command-line arguments can be visible in the process list to other users on the same host, so do not share an untrusted multi-user shell and restrict the service file.
# /etc/systemd/system/valheim.service
[Unit]
Description=Valheim Dedicated Server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=valheim
Group=valheim
WorkingDirectory=/srv/valheim/server
Environment=SteamAppId=892970
Environment=LD_LIBRARY_PATH=/srv/valheim/server/linux64
ExecStart=/srv/valheim/server/valheim_server.x86_64 \
-nographics -batchmode -name "Friends Valheim" \
-port 2456 -world "Dedicated" -password "PASSWORD" \
-savedir /srv/valheim/data -public 0 \
-saveinterval 1800 -backups 4 -backupshort 7200 -backuplong 43200
KillSignal=SIGINT
TimeoutStopSec=90
Restart=on-failure
RestartSec=15
[Install]
WantedBy=multi-user.target
Add the official -crossplay argument only when you choose that backend. Record the choice instead of troubleshooting Steam and Crossplay behavior at the same time.
Verify the Service and Network
The official readiness signal is Game server connected in the log. An active systemd process can still be loading the world or registering its listing. With Steam networking, verify both UDP listeners and perform a LAN join before testing the router.
sudo systemctl daemon-reload
sudo systemctl enable --now valheim
sudo journalctl -u valheim -f
# Steam backend only
sudo ss -lunp | grep -E ':2456|:2457'
sudo ufw allow 2456:2457/udp
Permission Lists and World Backups
adminlist.txt, bannedlist.txt, and permittedlist.txt take one case-sensitive Platform User ID per line, not display names. Adding anyone to permittedlist denies everyone not listed, so make sure all intended players are present before enabling that gate.
A graceful stop is SIGINT—the equivalent of Ctrl+C—not a forced kill. Archive all of /srv/valheim/data after the process exits so worlds and access lists move together. SteamCMD can replace binaries, but record the build or update date if recovery must reproduce an exact release.
sudo systemctl stop valheim
sudo -u valheim tar -C /srv/valheim -czf \
/srv/valheim/valheim-data-$(date +%F-%H%M).tar.gz data
sudo systemctl start valheim
gzip -t /srv/valheim/valheim-data-YYYY-MM-DD-HHMM.tar.gz
tar -tzf /srv/valheim/valheim-data-YYYY-MM-DD-HHMM.tar.gz | head
Update and Connection Checklist
Because startup arguments live in systemd, an update can replace start_server.sh without changing this service. Redact the server name, world, join password, and Platform User IDs from public logs and screenshots.
- Gracefully stop and back up data.
- Run SteamCMD app_update 896660 validate.
- Start and wait for Game server connected.
- For Steam, verify UDP 2456-2457 and forwarding.
- For Crossplay, test through join code, listing, or public address—not LAN IP.
- If builds differ, update both server and clients before changing the network.
Verification scope and official references
Iron Gate’s official Dedicated Server guide was checked for application setup, port range, Crossplay behavior, save directory, automatic backup arguments, and SIGINT shutdown. No production world or join password is used.