diff --git a/spec/eientei/default.nix b/spec/eientei/default.nix index 4da7d086..b5a098e7 100644 --- a/spec/eientei/default.nix +++ b/spec/eientei/default.nix @@ -42,6 +42,5 @@ boot.kernelModules = [ "kvm-intel" ]; boot.extraModulePackages = [ ]; - networking.firewall.allowedTCPPorts = [ 25565 ]; environment.systemPackages = with pkgs; [ python3 ]; } diff --git a/spec/eientei/minecraft.nix b/spec/eientei/minecraft.nix new file mode 100644 index 00000000..fc485da1 --- /dev/null +++ b/spec/eientei/minecraft.nix @@ -0,0 +1,95 @@ +{ pkgs, lib, config, ... }: let + inherit (lib) mapAttrs' nameValuePair; + + servers = { + bungeecord = { + cmdline = "${pkgs.graalvmCEPackages.graalvm-ce}/bin/java -Xms2G -Xmx4G -XX:+UseG1GC -XX:G1HeapRegionSize=4M -XX:+UnlockExperimentalVMOptions -XX:+ParallelRefProcEnabled -XX:+AlwaysPreTouch -jar BungeeCord.jar"; + stop = "end"; + }; + + nfwc = { + cmdline = "${pkgs.jdk}/bin/java @user_jvm_args.txt @libraries/net/minecraftforge/forge/1.19.2-43.3.8/unix_args.txt"; + stop = "stop"; + }; + }; + + prefix = "minecraft-server-"; + data = "/nix/persist/service/minecraft"; +in { + # https://github.com/NixOS/nixpkgs/blob/nixos-unstable/nixos/modules/services/games/minecraft-server.nix + users.users.minecraft = { + description = "Minecraft server service user"; + home = data; + createHome = true; + isSystemUser = true; + uid = 1021; + group = "minecraft"; + }; + users.groups.minecraft.gid = 1021; + + systemd.sockets = mapAttrs' (name: value: with value; (nameValuePair "${prefix}${name}" { + bindsTo = [ "${prefix}${name}.service" ]; + socketConfig = { + ListenFIFO = "/run/minecraft-server/${name}.stdin"; + SocketMode = "0660"; + SocketUser = "minecraft"; + SocketGroup = "minecraft"; + RemoveOnStop = true; + FlushPending = true; + }; + })) servers; + + systemd.services = let + stopScript = { name, stop }: pkgs.writeShellScript "minecraft-server-stop" '' + echo ${stop} > ${config.systemd.sockets."${prefix}${name}".socketConfig.ListenFIFO} + + # Wait for the PID of the minecraft server to disappear before + # returning, so systemd doesn't attempt to SIGKILL it. + while kill -0 "$1" 2> /dev/null; do + sleep 1s + done + ''; + in mapAttrs' (name: value: with value; (nameValuePair "${prefix}${name}" { + description = "Minecraft Server Service for ${name}"; + wantedBy = [ "multi-user.target" ]; + requires = [ "${prefix}${name}.socket" ]; + after = [ "network.target" "${prefix}${name}.socket" ]; + + serviceConfig = { + ExecStart = cmdline; + ExecStop = "${stopScript { inherit name stop; }} $MAINPID"; + Restart = "always"; + User = "minecraft"; + WorkingDirectory = "${data}/${name}"; + + StandardInput = "socket"; + StandardOutput = "journal"; + StandardError = "journal"; + + # Hardening + CapabilityBoundingSet = [ "" ]; + DeviceAllow = [ "" ]; + LockPersonality = true; + PrivateDevices = true; + PrivateTmp = true; + PrivateUsers = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + UMask = "0077"; + }; + })) servers; + + global.fs.zfs.mountpoints.${data} = "service/minecraft"; + networking.firewall.allowedTCPPorts = [ 25565 ]; +}