A Valheim server on Linux belongs under systemd: one unit file in /etc/systemd/system/valheim.service that runs the server as its own user, starts it at boot, restarts it after a crash, and - the line people forget - stops it with KillSignal=SIGINT so the world is saved on the way out. Add TimeoutStopSec=120 so a large world has time to finish writing, read the log with journalctl -u valheim, and use systemd timers instead of cron for the weekly restart and the nightly backup. This post builds that unit line by line, explains what each setting protects you from, and covers the cases that go wrong: crash loops, a stop that turns into a kill, logs that vanish, and several servers on one machine.
It assumes the server is already installed with SteamCMD as a valheim user in /home/valheim/server, with a start script of your own. If it is not, install a Valheim server on Linux with SteamCMD gets you to that point in about fifteen minutes, and this post picks up where its systemd section leaves off.
Why systemd, and not tmux or screen#
Three things have to be true of a server you leave running for months: it comes back after a reboot, it comes back after a crash, and it stops cleanly when you ask it to. A process started from an SSH session dies with the session. tmux and screen keep it alive after you disconnect, which is why so many guides use them, but neither starts anything at boot and neither notices when the process exits. You find out the server crashed when someone messages you about it.
systemd covers all three, and it adds things a terminal multiplexer never will:
- A controlled stop. systemd sends the signal you choose, waits as long as you allow, and only then escalates. With the right signal, every planned stop is a saved stop.
- A log you can search. Everything the server prints goes to the journal, with timestamps, kept across restarts, filterable by time and pattern.
- Restart policy with a brake. It restarts on failure, but gives up if the server crashes in a tight loop, instead of hammering the disk with a broken world.
- Resource limits. A memory ceiling, CPU weight and filesystem restrictions are a line each.
- Timers. Scheduled restarts and backups that are logged, visible in one list, and can depend on the service itself.
What you lose is the interactive console. Valheim's dedicated server does not read commands from standard input anyway - admin commands are typed in the game client's F5 console by someone in adminlist.txt - so on this game the loss is close to nothing. If you want an attachable console for other reasons, that is the main argument for LinuxGSM, which runs the server inside tmux and wraps it with its own tooling.
The start script the unit runs#
systemd should start a script, not the binary directly, because the server needs two environment variables and a working directory. Do not point the unit at the bundled start_server.sh; SteamCMD restores it on every update and validate, so your arguments vanish with the next patch. Keep your own copy:
#!/bin/bashcd "$(dirname "$0")"export LD_LIBRARY_PATH=./linux64:$LD_LIBRARY_PATHexport SteamAppId=892970exec ./valheim_server.x86_64 -nographics -batchmode \ -name "Longship Crew" -port 2456 -world "Midgard" \ -password "herring-barrel-42" -public 1 \ -saveinterval 900 -backups 4The detail that matters for systemd is exec. Without it, the script runs as a shell process with the server as its child, and the signal systemd sends at stop time lands on the shell. Bash does not forward signals to a foreground child the way you might expect, so the server can miss the clean-stop signal entirely and get killed at the timeout. With exec, the shell replaces itself with valheim_server.x86_64, the server becomes the service's main process, and the signal goes straight to it.
Every argument on that line is covered in the Valheim launch arguments reference. Two are worth choosing deliberately for a service: -saveinterval (default 1800 seconds) caps how much you lose to a crash, and -logFile, which you should leave out if you want the log in the journal.
The unit file, line by line#
[Unit]Description=Valheim dedicated serverWants=network-online.targetAfter=network-online.targetStartLimitIntervalSec=600StartLimitBurst=4[Service]Type=simpleUser=valheimGroup=valheimWorkingDirectory=/home/valheim/serverExecStart=/home/valheim/server/start_valheim.shKillSignal=SIGINTTimeoutStopSec=120Restart=on-failureRestartSec=15[Install]WantedBy=multi-user.target$ sudo systemctl daemon-reload$ sudo systemctl enable --now valheim$ systemctl status valheimWhat each line is for:
| Line | Why it is there |
|---|---|
Wants= / After=network-online.target | Start after the network is up, so Steam registration does not fail at boot |
StartLimitIntervalSec=600, StartLimitBurst=4 | More than four starts in ten minutes and systemd stops trying |
Type=simple | The script stays in the foreground; systemd tracks it directly |
User= / Group= | Never run a game server as root |
WorkingDirectory= | The library path in the script is relative to the install |
KillSignal=SIGINT | systemctl stop behaves like Ctrl+C, which saves the world |
TimeoutStopSec=120 | How long systemd waits for the save before it sends SIGKILL |
Restart=on-failure, RestartSec=15 | Come back after a crash, with a pause first |
WantedBy=multi-user.target | What enable hooks into, so it starts at boot |
The start-limit settings live in [Unit] on current systemd versions. Older releases accepted StartLimitInterval= in [Service]; if systemctl status warns about an unknown key, check man systemd.unit on your machine for the spelling it expects.
Stopping cleanly: SIGINT, timeouts and the save#
This is the part of the unit that decides whether a reboot costs you anything. Valheim holds the world in memory and writes it to disk every -saveinterval seconds. A clean shutdown writes it one last time; anything less does not.
When you run systemctl stop valheim with the unit above, the sequence is:
- systemd sends
SIGINTto the main process - the server, thanks toexec. - The server logs that it is shutting down, saves the world and exits. On a small world that takes a second or two; on a long-lived world with large bases it can take noticeably longer, and slow disks stretch it further.
- If the process is still running after
TimeoutStopSec, systemd sendsSIGKILLand logs that the stop timed out.
Confirm it works once, on purpose, before you trust it:
$ sudo systemctl stop valheim$ journalctl -u valheim -n 40 --no-pagerYou want to see the world save in the last lines of output before the process exits, and a plain Stopped Valheim dedicated server from systemd. If instead you see State 'stop-sigterm' timed out. Killing. or Main process exited, code=killed, status=9/KILL, the server did not finish in time or never received the signal. Check, in this order: that KillSignal=SIGINT is in the unit and you ran daemon-reload after adding it; that the script uses exec; and that TimeoutStopSec is long enough for your world.
systemctl restart is a stop followed by a start, so it gets the same clean stop. systemctl kill valheim does not - by default it sends SIGTERM to every process in the unit - and neither does the kernel's out-of-memory killer, a power cut or a host crash. For those, the only protection is a short save interval and backups that live somewhere else. Valheim server backups and world corruption covers what a half-written world looks like and how to recover from one.
Restart policy and crash loops#
Restart=on-failure restarts the server when it exits with a non-zero status, is killed by a signal it did not expect, or times out - and does not restart it after systemctl stop, which is what you want. The alternatives:
| Policy | Restarts after | Use it when |
|---|---|---|
no | Nothing | You want to investigate every exit by hand |
on-failure | Crashes, kills, non-zero exits | The normal choice for a game server |
on-abnormal | Signals and timeouts, not non-zero exits | The server exits non-zero on purpose for some reason |
always | Everything, including a clean exit | Rarely right here; a deliberate in-game shutdown comes straight back |
RestartSec=15 is a pause before each restart. It gives the old process's UDP ports time to be released and keeps a crash loop from spinning at full speed.
The start limit is the brake. If the world file is corrupt, or a game update broke a BepInEx mod, the server will crash on every start. Without a limit, systemd restarts it forever, which fills the journal with the same error thousands of times and buries the first, most useful occurrence of it. With StartLimitBurst=4 in ten minutes, systemd marks the unit failed and stops:
$ systemctl status valheim# Active: failed (Result: start-limit-hit)$ journalctl -u valheim -b --no-pager | tail -n 80$ sudo systemctl reset-failed valheim$ sudo systemctl start valheimRead the log before you reset anything. The common start-up failures - a missing steamclient.so, a port already in use, a BepInEx preloader error, a world that will not load - each have a recognisable line, and Valheim server crashes on start lists them.
Logs in journalctl#
With no -logFile argument, the server prints to standard output, systemd captures it, and the journal becomes the server log. The commands you will actually use:
# follow the log live$ journalctl -u valheim -f# everything since the current boot$ journalctl -u valheim -b# a time window$ journalctl -u valheim --since "2026-10-14 19:00" --until "2026-10-14 23:00"# search: connections, the join code, errors$ journalctl -u valheim -g "Got connection|join code|Exception"# the last 200 lines without the pager$ journalctl -u valheim -n 200 --no-pagerValheim's log is chatty, and on some distributions the journal is kept only in memory, so it disappears at reboot. If /var/log/journal does not exist, set Storage=persistent in /etc/systemd/journald.conf and restart systemd-journald. To stop the journal growing without bound, set SystemMaxUse= in the same file - 500M is plenty for one game server - or check current usage with journalctl --disk-usage.
The other choice is a file: add -logFile /home/valheim/valheim.log to the start line and the server writes there instead of the journal. That suits people who like tail and grep on a plain file, but then rotation is your job, through logrotate with copytruncate, because the server keeps the file open. Pick one; splitting the log between the two makes every investigation harder. What the lines mean - start-up, the join code, connections, the errors worth acting on - is in the Valheim server log explained.
Updates: on every start, or by hand#
The unit above does not update the game. You can make it do so with one extra line in [Service]:
ExecStartPre=/usr/games/steamcmd +force_install_dir /home/valheim/server +login anonymous +app_update 896660 +quitThen every start, including every restart and every boot, checks for a new server build first. That is convenient for a vanilla server: when a Valheim patch lands and players see Incompatible version, a systemctl restart valheim fixes it.
It is the wrong choice for a modded server. A game patch usually breaks BepInEx mods until their authors catch up, and an automatic update means a 5 a.m. restart can leave you with a server that crash-loops until someone notices. On a modded server, leave ExecStartPre out and update deliberately: stop the server, back up, run SteamCMD by hand as the valheim user, check that your mods have been updated, start again. Two smaller notes: an update check adds the time SteamCMD takes to every start, and if the update fails - Steam down, disk full - ExecStartPre fails and the server does not start at all. Prefix the path with - (ExecStartPre=-/usr/games/steamcmd ...) to let the server start on the old build when the update step fails. Updating a Valheim server and fixing version mismatches covers the timing question for groups.
Timers: weekly restarts and nightly backups#
systemd timers do what cron does, with two advantages for a game server: their runs are logged in the journal next to the server's own output, and systemctl list-timers shows exactly when each one fires next. A timer is a pair of files: a .timer that says when, and a .service that says what.
A weekly restart, early Monday morning:
[Unit]Description=Restart the Valheim server[Service]Type=oneshotExecStart=/usr/bin/systemctl restart valheim.service[Unit]Description=Weekly Valheim restart[Timer]OnCalendar=Mon *-*-* 05:00:00[Install]WantedBy=timers.targetA nightly backup of the whole save directory, run as the valheim user:
#!/bin/bashset -euo pipefaildest=/home/valheim/backupsmkdir -p "$dest"tar -czf "$dest/valheim-$(date +%F-%H%M).tar.gz" \ -C /home/valheim/.config/unity3d/IronGate Valheimfind "$dest" -name 'valheim-*.tar.gz' -mtime +14 -delete[Unit]Description=Back up Valheim worlds[Service]Type=oneshotUser=valheimExecStart=/home/valheim/backup_valheim.sh[Unit]Description=Nightly Valheim backup[Timer]OnCalendar=*-*-* 05:10:00Persistent=true[Install]WantedBy=timers.target$ chmod +x /home/valheim/backup_valheim.sh$ sudo systemctl daemon-reload$ sudo systemctl enable --now valheim-restart.timer valheim-backup.timer$ systemctl list-timers 'valheim*'$ systemd-analyze calendar "Mon *-*-* 05:00:00"The backup runs ten minutes after the restart on Mondays, so on those days it archives a world that was saved moments before. On other days it runs against a live server, and an archive taken while the server is mid-save can catch a half-written file. Either point the timer at a time just after a restart every day, or have the script copy the newest complete pair from Valheim's own -backups rotation. Persistent=true runs a missed backup at the next boot if the machine was off at 05:10; leave it off the restart timer, where catching up late would restart the server in the middle of an evening. Note that the save path above is the default; if you use -savedir, archive that instead - where Valheim keeps its files lists every location.
A backup on the same disk as the world protects against a bad save and nothing else. Copy the archives off the machine as well; game server backups to S3 shows one way. And there is no in-game broadcast from the server side on vanilla Valheim - no RCON, no stdin console - so tell players about the restart window in your Discord rather than expecting a warning in game.
Limits, hardening and more than one server#
A few [Service] lines are worth adding once the basics work:
MemoryMax=6GNoNewPrivileges=truePrivateTmp=trueProtectSystem=fullNice=-5MemoryMax= is a hard ceiling enforced by cgroups: hit it and the kernel kills the server, unsaved, which is better than the whole machine swapping itself to a standstill but is still a crash. Set it well above the server's normal working set - the Valheim RAM guide has realistic numbers - or use MemoryHigh= first, which throttles instead of killing. ProtectSystem=full makes /usr, /boot and /etc read-only for the service; do not add ProtectHome=, because the server and its saves live in a home directory. Nice=-5 gives the server a little priority over other work on a shared box.
To run several worlds on one machine, turn the unit into a template, valheim@.service, with EnvironmentFile=/etc/valheim/%i.env and a start line built from variables such as $NAME, $WORLD, $PORT and $PASSWORD. Each instance needs its own port pair, two apart at minimum (2456, then 2458), its own world name, and ideally its own -savedir. Start them as valheim@main and valheim@test. The port arithmetic is in Valheim ports 2456-2458 explained.
If you cannot use root at all, the same unit works as a user service in ~/.config/systemd/user/, managed with systemctl --user. It only survives logout if lingering is enabled for that user (loginctl enable-linger valheim, which does need root once). For a wider introduction to units, dependencies and limits beyond Valheim, see systemd services for your apps.
FAQ#
Does Valheim save when systemd stops it?
Yes, if the unit sends SIGINT and the signal reaches the server process. That means KillSignal=SIGINT in the unit and exec in the start script. With the default SIGTERM, or a shell sitting between systemd and the server, the save is not guaranteed.
How long should TimeoutStopSec be?
Long enough for your biggest save plus a margin. 120 seconds is comfortable for almost every world. If the journal ever shows the stop timing out and a SIGKILL, raise it - and check the disk, because a save that slow usually points at storage.
Why does systemctl say start-limit-hit?
The server crashed more times than StartLimitBurst allows inside StartLimitIntervalSec, so systemd stopped retrying. Read journalctl -u valheim -b for the real error, fix it, then run systemctl reset-failed valheim before starting again.
Should I use a systemd timer or cron for restarts?
Either works. Timers log each run in the journal, show their next run in systemctl list-timers, and can catch up missed runs with Persistent=true, which is useful for backups. Cron is fine if you already manage everything else there; cron expressions explained covers the syntax.
Can I type commands into the server through systemd?
Not usefully. The Valheim dedicated server has no stdin console and no RCON in vanilla. Admin commands are run from the game client's F5 console by players listed in adminlist.txt, and that works the same however the server is started.


