Running a Valheim Dedicated Server on NixOS v2

Posted

This is an update to a previous post with some improvements and some fixes for more recent versions of Valheim.

Improvements:

  1. Game download is separated from the game running.
    • This allows running multiple isolated instances on the same server sharing the game code.
    • If the download fails (for example Steam is down) the old version continues running.
  2. Updates to game execution. The old method of calling the linker stopped working due to the way that Valheim tries to find it’s data files (it was looking relative to the linker instead of it’s own executable).
  3. Updates to take advantage of new flags.
    • Save resources by disabling graphics.
    • Disable backups since we have our own.

So without further ado here is the new code:

Valheim Service

# valheim.nix
{config, pkgs, lib, ...}: let
	# Set to {id}-{branch}-{password} for betas.
	steam-app = "896660";
in {
	imports = [
		./steam.nix
	];

	users.users.valheim = {
		isSystemUser = true;
		# Valheim puts save data in the home directory.
		home = "/var/lib/valheim";
		createHome = true;
		homeMode = "750";
		group = "valheim";
	};

	users.groups.valheim = {};

	systemd.services.valheim = {
		wantedBy = [ "multi-user.target" ];

		# Install the game before launching.
		wants = [ "steam@${steam-app}.service" ];
		after = [ "steam@${steam-app}.service" ];

		serviceConfig = {
			ExecStart = lib.escapeShellArgs [
				"/var/lib/steam-app-${steam-app}/valheim_server.x86_64"
				"-nographics"
				"-batchmode"
				# "-crossplay" # This is broken because it looks for "party" shared library in the wrong path.
				"-savedir" "/var/lib/valheim/save"
				"-name" "YOUR SERVER NAME"
				"-port" "2456"
				"-world" "Dedicated"
				"-password" "YOUR PASSWORD HERE!!!"
				"-public" "0" # Valheim now supports favourite servers in-game which I am using instead of listing in the public registry.
				"-backups" "0" # I take my own backups, if you don't you can remove this to use the built-in basic rotation system.
			];
			Nice = "-5";
			PrivateTmp = true;
			Restart = "always";
			User = "valheim";
			WorkingDirectory = "~";
		};
		environment = {
			# linux64 directory is required by Valheim.
			LD_LIBRARY_PATH = "/var/lib/steam-app-${steam-app}/linux64:${pkgs.glibc}/lib";
			SteamAppId = "892970";
		};
	};

	# This is my custom backup machinery. Substitute your own 🙂
	kevincox.backup.valheim = {
		paths = [
			"/var/lib/valheim/save/"
		];
	};

Steam Downloader

# steam.nix
{config, pkgs, lib, ...}: {
	users.users.steam = {
		isSystemUser = true;
		group = "steam";
		home = "/var/lib/steam";
		createHome = true;
	};

	users.groups.steam = {};

	systemd.services."steam@" = {
		unitConfig = {
			StopWhenUnneeded = true;
		};
		serviceConfig = {
			Type = "oneshot";
			ExecStart = "${pkgs.resholve.writeScript "steam" {
				interpreter = "${pkgs.zsh}/bin/zsh";
				inputs = with pkgs; [
					patchelf
					steamcmd
				];
				execer = with pkgs; [
					"cannot:${steamcmd}/bin/steamcmd"
				];
			} ''
				set -eux

				instance=''${1:?Instance Missing}
				eval 'args=(''${(@s:_:)instance})'
				app=''${args[1]:?App ID missing}
				beta=''${args[2]:-}
				betapass=''${args[3]:-}

				dir=/var/lib/steam-app-$instance

				cmds=(
					+force_install_dir $dir
					+login anonymous
					+app_update $app validate
				)

				if [[ $beta ]]; then
					cmds+=(-beta $beta)
					if [[ $betapass ]]; then
						cmds+=(-betapassword $betapass)
					fi
				fi

				cmds+=(+quit)

				steamcmd $cmds

				for f in $dir/*; do
					if ! [[ -f $f && -x $f ]]; then
						continue
					fi

					# Update the interpreter to the path on NixOS.
					patchelf --set-interpreter ${pkgs.glibc}/lib/ld-linux-x86-64.so.2 $f || true
				done
			''} %i";
			PrivateTmp = true;
			Restart = "on-failure";
			StateDirectory = "steam-app-%i";
			TimeoutStartSec = 3600; # Allow time for updates.
			User = "steam";
			WorkingDirectory = "~";
		};
	};
}

Connecting

  1. Start the game and get to the “Join Game” dialog.
  2. Click “Add Server”
  3. Enter the IP or hostname. (If you changed the port include it)
  4. Click “Add Server”
  5. Select the entry from the favourites list and click “Connect”.