Is there a way I can set a create a template for a service like this? Minecraft servers aren’t that different and the only differences arent that huge.
{ pkgs, ... }: {
systemd.services.name = {
enable = true;
unitConfig = {
Description = "Name's minecraft server";
Wants = "network-online.target";
After = "network-online.target";
};
serviceConfig = {
User = "redhawk";
WorkingDirectory = "/home/redhawk/minecraft/name/";
ExecStart = "${pkgs.jre}/bin/java -jar server.jar";
};
wantedBy = [ "multi-user.target" ];
};
}
If the thing changing is one string, you can use systemd template units (systemd: Template unit files - Fedora Magazine), although be warned that declaring them in NixOS requires a bit of tweaking to make them work as intended.
If you need something more complicated, you can do the templating in Nix by writing a custom function to create the unit defintion:
{ pkgs, ... }:
let
mkMinecraftServerService = {name, user}: {
enable = true;
unitConfig = {
Description = "${name}'s minecraft server";
Wants = "network-online.target";
After = "network-online.target";
};
serviceConfig = {
User = user;
WorkingDirectory = "/home/${user}/minecraft/${name}/";
ExecStart = "${pkgs.jre}/bin/java -jar server.jar";
};
wantedBy = [ "multi-user.target" ];
};
in {
systemd.services = {
alice = mkMinecraftServerService { name = "alice"; user = "alice"; };
bob = mkMinecraftServerService { name = "bob"; user = "bob"; };
bobModded = mkMinectaftService { name = "moddedBob"; user = "bob"; };
};
}
2 Likes
what would the systemd name of this process be? if possible i’d like them to all have something like minecraft-${user}-${name}
Each key in systemd.services
creates a corresponding .service
file in /etc/systemd/system
.
Therefore, you’d want something like this:
systemd.services = {
minecraft-alice-alice = mkMinecraftServerService { name = "alice"; user = "alice"; };
minecraft-bob-bob = mkMinecraftServerService { name = "bob"; user = "bob"; };
minecraft-bob-moddedBob = mkMinectaftService { name = "moddedBob"; user = "bob"; };
}
It might be worthwhile to change the function to return the whole key/value pair instead of just the value:
mkMinecraftServerService = {name, user}: {
"minecraft-${user}-${name}" = {
enable = true;
unitConfig = {
Description = "${name}'s minecraft server";
Wants = "network-online.target";
After = "network-online.target";
};
serviceConfig = {
User = user;
WorkingDirectory = "/home/${user}/minecraft/${name}/";
ExecStart = "${pkgs.jre}/bin/java -jar server.jar";
};
wantedBy = [ "multi-user.target" ];
};
};
You then need to merge the attribute sets into systemd.services
:
systemd.services = lib.attrsets.mergeAttrsList [
(mkMinecraftService {name = "alice"; user = "alice";})
(mkMinecraftService {name = "bob"; user = "bob";})
(mkMinecraftService {name = "moddedBob"; user = "bob";})
];
Nix is so cool, thank you.
So, I’ve come up with something very close to what I want
{ lib, pkgs, ... }:
let
Minecraft = { name }: {
"minecraft-${name}" = {
enable = true;
unitConfig = {
Description = "${name}'s minecraft server";
Wants = "network-online.target";
After = "network-online.target";
};
serviceConfig = {
User = "minecraft";
Group = "minecraft";
StateDirectory = "minecraft/${name}";
StateDirectoryMode = "0775";
WorkingDirectory = "/var/lib/minecraft/${name}"; // <- problem
ExecStart = "${pkgs.jre}/bin/java -jar server.jar";
};
wantedBy = [ "multi-user.target" ];
};
};
in {
systemd.services =
lib.attrsets.mergeAttrsList [ (Minecraft { name = "bob"; }) ];
}
However I can’t seem to set or access the statedirectory of the server, the only way i can fix this currently is set the workingdirectory.
based on what you have this is what i would use:
{ ... }:
{
systemd.services."minecraft@" = {
description = "%i's minecraft server";
wantedBy = [ "multi-user.target" ];
wants = [ "network-online.target" ];
after [ "network-online.target" ];
serviceConfig = {
DynamicUser = true; # or set a user if wanted/needed
StateDirectory = "minecraft/%i";
StateDirectoryMode = "0775";
WorkingDirectory = "%S/minecraft/%i";
ExecStart = "${pkgs.jre}/bin/java -jar server.jar";
};
};
}
then you can spin them up dynamically via systemctl start minecarft@timmy.service
, or have them start automatically via some syntax that is escaping me at the moment ![:thinking: :thinking:](https://discourse.nixos.org/images/emoji/twitter/thinking.png?v=12)
Where do the %
's come from? is this something I haven’t seen in the systemd docs?
Yeah, they’re specifiers.
1 Like