SteamCMD is Valve's command-line version of the Steam client. It downloads and updates dedicated servers for games such as Valheim, Counter-Strike 2, Rust or Team Fortress 2 without a graphical interface. In this tutorial you will install SteamCMD on Ubuntu 24.04 under a dedicated user, download a Valheim dedicated server as a working example, run it as a systemd service and schedule automatic updates.
Prerequisites
To follow this guide you need:
- A server running Ubuntu 24.04 LTS (x86_64), for example a CubePath VPS.
- A non-root user with
sudoprivileges. - Enough resources for the game you plan to host. The Valheim example needs about 2 vCPU, 4 GB of RAM and 5 GB of free disk space.
- UFW enabled, or another firewall you manage yourself.
SteamCMD only runs on x86_64. It does not work on ARM servers.
Step 1 - Installing the required 32-bit libraries
SteamCMD itself is a 32-bit program, so it needs the 32-bit C runtime. Enable the i386 architecture and install the dependencies:
sudo dpkg --add-architecture i386
sudo apt update
sudo apt install lib32gcc-s1 lib32stdc++6 ca-certificates curl tar
Confirm that the i386 architecture is now enabled:
dpkg --print-foreign-architectures
i386
Step 2 - Creating a dedicated steam user
Game servers should never run as root. Create a system account called steam with its own home directory, where SteamCMD and the game files will live:
sudo useradd -m -s /bin/bash steam
Open a shell as that user. The rest of the SteamCMD steps run as steam:
sudo -iu steam
Your prompt now shows steam@... and pwd returns /home/steam.
Step 3 - Downloading and bootstrapping SteamCMD
Valve distributes SteamCMD as a small tarball that updates itself on first run. Download it into ~/steamcmd and extract it:
mkdir -p ~/steamcmd
cd ~/steamcmd
curl -fsSLO https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz
tar -xzf steamcmd_linux.tar.gz
rm steamcmd_linux.tar.gz
Run it once with +quit so it downloads the rest of the client and exits:
~/steamcmd/steamcmd.sh +quit
The first run takes a minute. The end of the output looks similar to this:
[----] Verifying installation...
Steam Console Client (c) Valve Corporation - version 1727480123
-- type 'quit' to exit --
Loading Steam API...OK
Many dedicated servers look for the Steam client library in ~/.steam/sdk64. Create that link now to avoid the common steamclient.so: cannot open shared object file error later:
mkdir -p ~/.steam/sdk64
ln -sf ~/steamcmd/linux64/steamclient.so ~/.steam/sdk64/steamclient.so
Step 4 - Installing a dedicated server
Every game server on Steam has an app ID. You pass it to app_update together with the directory where the files should go. Some common IDs:
| Game | Dedicated server app ID | Login |
|---|---|---|
| Valheim | 896660 | anonymous |
| Counter-Strike 2 | 730 | anonymous |
| Rust | 258550 | anonymous |
| Team Fortress 2 | 232250 | anonymous |
| Garry's Mod | 4020 | anonymous |
Install the Valheim dedicated server into ~/servers/valheim. Note that +force_install_dir must come before +login:
~/steamcmd/steamcmd.sh +force_install_dir /home/steam/servers/valheim +login anonymous +app_update 896660 validate +quit
When the download finishes SteamCMD prints:
Success! App '896660' fully installed.
List the directory to confirm the server binary is there:
ls ~/servers/valheim/valheim_server.x86_64
The validate flag checks every file against Steam's manifest. Use it on the first install or when you suspect corrupted files. For routine updates, leave it out: it rereads the whole installation and is much slower.
Servers that require a Steam account
A few dedicated servers (for example DayZ or some Arma titles) cannot be downloaded anonymously and require an account that owns the game. Log in interactively once so SteamCMD can cache the credentials and ask for your Steam Guard code:
~/steamcmd/steamcmd.sh +login your_steam_username +quit
After the first successful login, later runs with +login your_steam_username reuse the cached session. Use a separate Steam account for servers rather than your personal one.
Step 5 - Using a SteamCMD script file
Long command lines become hard to read when you manage several servers. SteamCMD can read the same commands from a text file with +runscript. Create one file per server:
mkdir -p ~/scripts
nano ~/scripts/valheim.txt
Add the commands, one per line:
force_install_dir /home/steam/servers/valheim
login anonymous
app_update 896660
quit
Run it with an absolute path:
~/steamcmd/steamcmd.sh +runscript /home/steam/scripts/valheim.txt
When the server is already up to date, SteamCMD finishes in a few seconds with Success! App '896660' already up to date. Leave the steam shell before continuing:
exit
Step 6 - Running the server as a systemd service
A systemd unit starts the server at boot, restarts it if it crashes and runs a SteamCMD update before every start. Create the unit file:
sudo nano /etc/systemd/system/valheim.service
Paste the following, replacing your_server_name and your_server_password (at least 5 characters, and not contained in the server name):
[Unit]
Description=Valheim dedicated server
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=steam
Group=steam
WorkingDirectory=/home/steam/servers/valheim
Environment=LD_LIBRARY_PATH=/home/steam/servers/valheim/linux64
Environment=SteamAppId=892970
ExecStartPre=/home/steam/steamcmd/steamcmd.sh +runscript /home/steam/scripts/valheim.txt
ExecStart=/home/steam/servers/valheim/valheim_server.x86_64 -nographics -batchmode -name "your_server_name" -port 2456 -world "Dedicated" -password "your_server_password" -public 1
KillSignal=SIGINT
TimeoutStartSec=600
TimeoutStopSec=120
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
A few details matter here:
ExecStartPreupdates the game before each start, so a restart is also an update.SteamAppId=892970is the Valheim game ID the server binary expects (the download ID 896660 is different).KillSignal=SIGINTlets Valheim save the world cleanly on stop, andTimeoutStopSecgives it time to do so.
Valheim uses UDP ports 2456 and 2457. Open them in the firewall:
sudo ufw allow 2456:2457/udp
Load the unit, then enable and start it:
sudo systemctl daemon-reload
sudo systemctl enable --now valheim.service
Check the status:
sudo systemctl status valheim.service
● valheim.service - Valheim dedicated server
Loaded: loaded (/etc/systemd/system/valheim.service; enabled; preset: enabled)
Active: active (running) since Thu 2026-09-24 10:12:03 UTC; 45s ago
Follow the log until the world is loaded:
sudo journalctl -u valheim.service -f
A line containing Game server connected means the server registered with Steam and players can join it. Press Ctrl+C to stop following the log.
Step 7 - Scheduling automatic updates
Because the service updates itself on every start, an automatic update is just a scheduled restart. Create a oneshot service that restarts the game server:
sudo nano /etc/systemd/system/valheim-update.service
[Unit]
Description=Restart Valheim to apply SteamCMD updates
[Service]
Type=oneshot
ExecStart=/usr/bin/systemctl restart valheim.service
Then create a timer that triggers it every day at 05:00 server time:
sudo nano /etc/systemd/system/valheim-update.timer
[Unit]
Description=Daily Valheim update
[Timer]
OnCalendar=*-*-* 05:00:00
Persistent=true
[Install]
WantedBy=timers.target
Enable the timer:
sudo systemctl daemon-reload
sudo systemctl enable --now valheim-update.timer
Confirm it is scheduled:
systemctl list-timers valheim-update.timer
NEXT LEFT LAST PASSED UNIT ACTIVATES
Fri 2026-09-25 05:00:00 UTC 18h left - - valheim-update.timer valheim-update.service
Pick a time with few players online, since the restart disconnects everyone.
Step 8 - Adding more servers
To host a second game, repeat the pattern with a new install directory, script file and unit. For example, a Counter-Strike 2 server uses this script at /home/steam/scripts/cs2.txt:
force_install_dir /home/steam/servers/cs2
login anonymous
app_update 730
quit
Give each server its own ports and its own systemd unit (cs2.service, rust.service and so on), so you can start, stop and update them independently. Keep an eye on RAM: each server reserves its memory as soon as it loads a map or world.
Downloading Workshop content
Some games load mods from the Steam Workshop. SteamCMD can fetch an item by game ID and Workshop item ID:
sudo -u steam /home/steam/steamcmd/steamcmd.sh +login anonymous +workshop_download_item 4000 your_item_id +quit
The files land in /home/steam/steamcmd/steamapps/workshop/content/<app_id>/<item_id>/. Many games only allow Workshop downloads from an account that owns the game, in which case you need a real login instead of anonymous.
Troubleshooting
steamclient.so: cannot open shared object file: the link from Step 3 is missing or broken. Recreate it as the steam user and restart the service.
ERROR! Failed to install app '...' (No subscription): the server cannot be downloaded anonymously. Log in with an account that owns the game, as shown in Step 4.
ERROR! Failed to install app '...' (Disk write failure): the install directory is not writable by steam or the disk is full. Check with df -h and ls -ld /home/steam/servers/*.
The service times out while starting: a large update can take longer than TimeoutStartSec. Increase it in the unit, run sudo systemctl daemon-reload and start the service again.
Players cannot see the server: confirm the ports are open with sudo ufw status and that the process is listening with sudo ss -ulpn | grep 2456.
Conclusion
You installed SteamCMD under a dedicated user, downloaded a dedicated server, turned it into a systemd service that updates itself on every start and scheduled a daily update restart. The same four pieces (install directory, script file, service and timer) work for any game on Steam. As next steps, set up regular backups of the world or save directory, restrict SSH access with key-based authentication, and review the game's own server configuration options for player limits and admin lists.
