{ pkgs, lib, ... }: let inherit (lib) concatStringsSep; in { systemd.services.starbound = { description = "Starbound"; after = ["network.target"]; serviceConfig = { ExecStart = "${pkgs.local.starbound}/bin/launch-starbound ${./configs/starbound.json}"; Type = "simple"; # Credential loading for steam auth (if necessary; prefer # anonymous login wherever possible). LoadCredential = "steam:/run/secrets/steam/tlater"; # Security settings DynamicUser = true; # This is where the StateDirectory ends up WorkingDirectory = "/var/lib/starbound"; # Creates /var/lib/starbound (or rather, a symlink there to # /var/lib/private/starbound), and sets it up to be writeable to # by the dynamic user. StateDirectory = "starbound"; # Note some settings below are basically tautologous with # `NoNewPrivileges`, but they all work slightly differently so # add additional layers in case of bugs. ## THESE SETTINGS ARE A GOOD IDEA BUT THE STEAM CLIENT IS ## REALLY, REALLY BAD, AND FOR SOME REASON I NEED TO USE IT TO ## DOWNLOAD GAME SERVERS AS WELL: ## # To guarantee the above (only permits 64-bit syscalls, 32-bit # syscalls can circumvent the above restrictions). # # Obviously, if running a 32 bit game server, change this. # SystemCallArchitectures = "native"; # Game servers shouldn't need to create new namespaces ever. # # TODO: Since steam uses namespaces for things *entirely # unrelated* to installing game servers, we need to allow # namespace access. Ideally I'd instead do this in an # ExecStartPre, but alas, this isn't possible because of # https://github.com/systemd/systemd/issues/19604. # # RestrictNamespaces = true; # Don't need to let the game server see other user accounts PrivateUsers = true; # *Probably* not harmful for game servers, which probably don't update dynamically ProtectHostname = true; # Yeah, if a game server tries to edit the hardware clock something's fishy ProtectClock = true; # Don't let game servers modify kernel settings, duh ProtectKernelTunables = true; ProtectKernelModules = true; ProtectKernelLogs = true; # Game servers shouldn't use cgroups themselves either ProtectControlGroups = true; # Most game servers will never need other socket types RestrictAddressFamilies = ["AF_UNIX AF_INET AF_INET6"]; # Also a no-brainer, no game server should ever need this LockPersonality = true; # Some game servers will probably try to set this, but they # don't need it. It's only required for audio processing and # such, which the server end doesn't need to do. RestrictRealtime = true; # Don't allow a variety of syscalls that gameservers have no # business using anyway SystemCallFilter = "~" + (concatStringsSep " " [ "@clock" "@cpu-emulation" "@debug" "@keyring" "@memlock" "@module" # "@mount" TODO: Consider adding when steamcmd is run in ExecStartPre "@obsolete" "@raw-io" "@reboot" # "@resources" TODO: Ditto "@setuid" "@swap" ]); # Normally only "read-only", but steamcmd will puke if there is # no home directory to write to (though the nix package will # implicitly symlink to the path that we set in its override, so # no actual files are created, besides a symlink). ProtectHome = "tmpfs"; # Implied by DynamicUser anyway, but it doesn't hurt to add # these explicitly, at least for reference. RemoveIPC = true; PrivateTmp = true; PrivateDevices = true; NoNewPrivileges = true; RestrictSUIDSGID = true; ProtectSystem = "strict"; # ProtectHome = "read-only"; # See further up }; }; }