{ 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 waterfall-1.20-578.jar"; # stop = "end"; #}; #limbo = { # cmdline = "${pkgs.graalvmCEPackages.graalvm-ce}/bin/java -Xms1G -Xmx1G -jar NanoLimbo-1.8-all.jar"; # stop = "stop"; #}; greedycraft = { cmdline = "${pkgs.jdk8}/bin/java -Xmx10G -Xms10G -Xss4M -Dfile.encoding=GBK -Dsun.rmi.dgc.server.gcInterval=1800000 -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=20 -XX:G1ReservePercent=20 -XX:MaxGCPauseMillis=50 -XX:+AlwaysPreTouch -XX:+UseStringDeduplication -Dfml.ignorePatchDiscrepancies=true -Dfml.ignoreInvalidMinecraftCertificates=true -XX:-OmitStackTraceInFastThrow -XX:+OptimizeStringConcat -XX:+UseAdaptiveGCBoundary -XX:G1HeapRegionSize=32M -jar forge-1.12.2-14.23.5.2855.jar nogui"; stop = "stop"; }; 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" ]; path = [ pkgs.bash ]; 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 ]; }