about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSilvan Mosberger <infinisil@icloud.com>2019-02-05 01:49:24 +0100
committerGitHub <noreply@github.com>2019-02-05 01:49:24 +0100
commit2d6f84c1090ae39c58dcec8f35a3ca62a43ad38c (patch)
tree08eb1d8c3c95d4442a8503d1929bfa1667c87239
parent904e9ab04859f976dbf3b84e1274a9e41a9cfc50 (diff)
parent58c89ec26a5d3c34e34bcb9f23db9fc62d7cf98a (diff)
downloadnixlib-2d6f84c1090ae39c58dcec8f35a3ca62a43ad38c.tar
nixlib-2d6f84c1090ae39c58dcec8f35a3ca62a43ad38c.tar.gz
nixlib-2d6f84c1090ae39c58dcec8f35a3ca62a43ad38c.tar.bz2
nixlib-2d6f84c1090ae39c58dcec8f35a3ca62a43ad38c.tar.lz
nixlib-2d6f84c1090ae39c58dcec8f35a3ca62a43ad38c.tar.xz
nixlib-2d6f84c1090ae39c58dcec8f35a3ca62a43ad38c.tar.zst
nixlib-2d6f84c1090ae39c58dcec8f35a3ca62a43ad38c.zip
Merge pull request #45412 from costrouc/costrouc/minecraft-server
minecraft-server: 1.12.2 -> 1.13.2 + service refactor
-rw-r--r--nixos/modules/services/games/minecraft-server.nix201
-rw-r--r--pkgs/games/minecraft-server/default.nix80
-rw-r--r--pkgs/top-level/all-packages.nix8
3 files changed, 241 insertions, 48 deletions
diff --git a/nixos/modules/services/games/minecraft-server.nix b/nixos/modules/services/games/minecraft-server.nix
index f50d2897843a..7d26d1501650 100644
--- a/nixos/modules/services/games/minecraft-server.nix
+++ b/nixos/modules/services/games/minecraft-server.nix
@@ -4,8 +4,41 @@ with lib;
 
 let
   cfg = config.services.minecraft-server;
-in
-{
+
+  # We don't allow eula=false anyways
+  eulaFile = builtins.toFile "eula.txt" ''
+    # eula.txt managed by NixOS Configuration
+    eula=true
+  '';
+
+  whitelistFile = pkgs.writeText "whitelist.json"
+    (builtins.toJSON
+      (mapAttrsToList (n: v: { name = n; uuid = v; }) cfg.whitelist));
+
+  cfgToString = v: if builtins.isBool v then boolToString v else toString v;
+
+  serverPropertiesFile = pkgs.writeText "server.properties" (''
+    # server.properties managed by NixOS configuration
+  '' + concatStringsSep "\n" (mapAttrsToList
+    (n: v: "${n}=${cfgToString v}") cfg.serverProperties));
+
+
+  # To be able to open the firewall, we need to read out port values in the
+  # server properties, but fall back to the defaults when those don't exist.
+  # These defaults are from https://minecraft.gamepedia.com/Server.properties#Java_Edition_3
+  defaultServerPort = 25565;
+
+  serverPort = cfg.serverProperties.server-port or defaultServerPort;
+
+  rconPort = if cfg.serverProperties.enable-rcon or false
+    then cfg.serverProperties."rcon.port" or 25575
+    else null;
+
+  queryPort = if cfg.serverProperties.enable-query or false
+    then cfg.serverProperties."query.port" or 25565
+    else null;
+
+in {
   options = {
     services.minecraft-server = {
 
@@ -13,10 +46,32 @@ in
         type = types.bool;
         default = false;
         description = ''
-          If enabled, start a Minecraft Server. The listening port for
-          the server is always <literal>25565</literal>. The server
+          If enabled, start a Minecraft Server. The server
           data will be loaded from and saved to
-          <literal>${cfg.dataDir}</literal>.
+          <option>services.minecraft-server.dataDir</option>.
+        '';
+      };
+
+      declarative = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to use a declarative Minecraft server configuration.
+          Only if set to <literal>true</literal>, the options
+          <option>services.minecraft-server.whitelist</option> and
+          <option>services.minecraft-server.serverProperties</option> will be
+          applied.
+        '';
+      };
+
+      eula = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether you agree to
+          <link xlink:href="https://account.mojang.com/documents/minecraft_eula">
+          Mojangs EULA</link>. This option must be set to
+          <literal>true</literal> to run Minecraft server.
         '';
       };
 
@@ -24,7 +79,7 @@ in
         type = types.path;
         default = "/var/lib/minecraft";
         description = ''
-          Directory to store minecraft database and other state/data files.
+          Directory to store Minecraft database and other state/data files.
         '';
       };
 
@@ -32,21 +87,84 @@ in
         type = types.bool;
         default = false;
         description = ''
-          Whether to open ports in the firewall (if enabled) for the server.
+          Whether to open ports in the firewall for the server.
+        '';
+      };
+
+      whitelist = mkOption {
+        type = let
+          minecraftUUID = types.strMatching
+            "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" // {
+              description = "Minecraft UUID";
+            };
+          in types.attrsOf minecraftUUID;
+        default = {};
+        description = ''
+          Whitelisted players, only has an effect when
+          <option>services.minecraft-server.declarative</option> is
+          <literal>true</literal> and the whitelist is enabled
+          via <option>services.minecraft-server.serverProperties</option> by
+          setting <literal>white-list</literal> to <literal>true</literal>.
+          This is a mapping from Minecraft usernames to UUIDs.
+          You can use <link xlink:href="https://mcuuid.net/"/> to get a
+          Minecraft UUID for a username.
+        '';
+        example = literalExample ''
+          {
+            username1 = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
+            username2 = "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy";
+          };
+        '';
+      };
+
+      serverProperties = mkOption {
+        type = with types; attrsOf (either bool (either int str));
+        default = {};
+        example = literalExample ''
+          {
+            server-port = 43000;
+            difficulty = 3;
+            gamemode = 1;
+            max-players = 5;
+            motd = "NixOS Minecraft server!";
+            white-list = true;
+            enable-rcon = true;
+            "rcon.password" = "hunter2";
+          }
+        '';
+        description = ''
+          Minecraft server properties for the server.properties file. Only has
+          an effect when <option>services.minecraft-server.declarative</option>
+          is set to <literal>true</literal>. See
+          <link xlink:href="https://minecraft.gamepedia.com/Server.properties#Java_Edition_3"/>
+          for documentation on these values.
         '';
       };
 
+      package = mkOption {
+        type = types.package;
+        default = pkgs.minecraft-server;
+        defaultText = "pkgs.minecraft-server";
+        example = literalExample "pkgs.minecraft-server_1_12_2";
+        description = "Version of minecraft-server to run.";
+      };
+
       jvmOpts = mkOption {
-        type = types.str;
+        type = types.separatedString " ";
         default = "-Xmx2048M -Xms2048M";
-        description = "JVM options for the Minecraft Service.";
+        # Example options from https://minecraft.gamepedia.com/Tutorials/Server_startup_script
+        example = "-Xmx2048M -Xms4092M -XX:+UseG1GC -XX:+CMSIncrementalPacing "
+          + "-XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 "
+          + "-XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10";
+        description = "JVM options for the Minecraft server.";
       };
     };
   };
 
   config = mkIf cfg.enable {
+
     users.users.minecraft = {
-      description     = "Minecraft Server Service user";
+      description     = "Minecraft server service user";
       home            = cfg.dataDir;
       createHome      = true;
       uid             = config.ids.uids.minecraft;
@@ -57,17 +175,60 @@ in
       wantedBy      = [ "multi-user.target" ];
       after         = [ "network.target" ];
 
-      serviceConfig.Restart = "always";
-      serviceConfig.User    = "minecraft";
-      script = ''
-        cd ${cfg.dataDir}
-        exec ${pkgs.minecraft-server}/bin/minecraft-server ${cfg.jvmOpts}
-      '';
-    };
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/minecraft-server ${cfg.jvmOpts}";
+        Restart = "always";
+        User = "minecraft";
+        WorkingDirectory = cfg.dataDir;
+      };
+
+      preStart = ''
+        ln -sf ${eulaFile} eula.txt
+      '' + (if cfg.declarative then ''
+
+        if [ -e .declarative ]; then
+
+          # Was declarative before, no need to back up anything
+          ln -sf ${whitelistFile} whitelist.json
+          cp -f ${serverPropertiesFile} server.properties
+
+        else
 
-    networking.firewall = mkIf cfg.openFirewall {
-      allowedUDPPorts = [ 25565 ];
-      allowedTCPPorts = [ 25565 ];
+          # Declarative for the first time, backup stateful files
+          ln -sb --suffix=.stateful ${whitelistFile} whitelist.json
+          cp -b --suffix=.stateful ${serverPropertiesFile} server.properties
+
+          # server.properties must have write permissions, because every time
+          # the server starts it first parses the file and then regenerates it..
+          chmod +w server.properties
+          echo "Autogenerated file that signifies that this server configuration is managed declaratively by NixOS" \
+            > .declarative
+
+        fi
+      '' else ''
+        if [ -e .declarative ]; then
+          rm .declarative
+        fi
+      '');
     };
+
+    networking.firewall = mkIf cfg.openFirewall (if cfg.declarative then {
+      allowedUDPPorts = [ serverPort ];
+      allowedTCPPorts = [ serverPort ]
+        ++ optional (! isNull queryPort) queryPort
+        ++ optional (! isNull rconPort) rconPort;
+    } else {
+      allowedUDPPorts = [ defaultServerPort ];
+      allowedTCPPorts = [ defaultServerPort ];
+    });
+
+    assertions = [
+      { assertion = cfg.eula;
+        message = "You must agree to Mojangs EULA to run minecraft-server."
+          + " Read https://account.mojang.com/documents/minecraft_eula and"
+          + " set `services.minecraft-server.eula` to `true` if you agree.";
+      }
+    ];
+
   };
 }
diff --git a/pkgs/games/minecraft-server/default.nix b/pkgs/games/minecraft-server/default.nix
index 050e0126fa72..c2f20f53e9a8 100644
--- a/pkgs/games/minecraft-server/default.nix
+++ b/pkgs/games/minecraft-server/default.nix
@@ -1,37 +1,63 @@
 { stdenv, fetchurl, jre }:
 
-stdenv.mkDerivation rec {
-  name    = "minecraft-server-${version}";
-  version = "1.13.2";
-
-  src  = fetchurl {
-    # Old url
-    # https://s3.amazonaws.com/Minecraft.Download/versions/${version}/minecraft_server.${version}.jar
+let
+  common = { version, sha256, url }:
+    stdenv.mkDerivation (rec {
+      name = "minecraft-server-${version}";
+      inherit version;
+
+      src = fetchurl {
+        inherit url sha256;
+      };
+
+      preferLocalBuild = true;
+
+      installPhase = ''
+        mkdir -p $out/bin $out/lib/minecraft
+        cp -v $src $out/lib/minecraft/server.jar
+
+        cat > $out/bin/minecraft-server << EOF
+        #!/bin/sh
+        exec ${jre}/bin/java \$@ -jar $out/lib/minecraft/server.jar nogui
+        EOF
+
+        chmod +x $out/bin/minecraft-server
+      '';
+
+      phases = "installPhase";
+
+      meta = {
+        description = "Minecraft Server";
+        homepage    = "https://minecraft.net";
+        license     = stdenv.lib.licenses.unfreeRedistributable;
+        platforms   = stdenv.lib.platforms.unix;
+        maintainers = with stdenv.lib.maintainers; [ thoughtpolice tomberek costrouc];
+      };
+    });
+
+in {
+  minecraft-server_1_13_2 = common {
+    version = "1.13.2";
     url    = "https://launcher.mojang.com/v1/objects/3737db93722a9e39eeada7c27e7aca28b144ffa7/server.jar";
     sha256 = "13h8dxrrgqa1g6sd7aaw26779hcsqsyjm7xm0sknifn54lnamlzz";
   };
 
-  preferLocalBuild = true;
-
-  installPhase = ''
-    mkdir -p $out/bin $out/lib/minecraft
-    cp -v $src $out/lib/minecraft/server.jar
-
-    cat > $out/bin/minecraft-server << EOF
-    #!/bin/sh
-    exec ${jre}/bin/java \$@ -jar $out/lib/minecraft/server.jar nogui
-    EOF
-
-    chmod +x $out/bin/minecraft-server
-  '';
+  minecraft-server_1_13_1 = common {
+    version = "1.13.1";
+    url = "https://launcher.mojang.com/mc/game/1.13.1/server/fe123682e9cb30031eae351764f653500b7396c9/server.jar";
+    sha256 = "1lak29b7dm0w1cmzjn9gyix6qkszwg8xgb20hci2ki2ifrz099if";
+  };
 
-  phases = "installPhase";
+  minecraft-server_1_13_0 = common {
+    version = "1.13.0";
+    url = "https://launcher.mojang.com/mc/game/1.13/server/d0caafb8438ebd206f99930cfaecfa6c9a13dca0/server.jar";
+    sha256 = "1fahqnylxzbvc0fdsqk0x15z40mcc5b7shrckab1qcsdj0kkjvz7";
+  };
 
-  meta = {
-    description = "Minecraft Server";
-    homepage    = "https://minecraft.net";
-    license     = stdenv.lib.licenses.unfreeRedistributable;
-    platforms   = stdenv.lib.platforms.unix;
-    maintainers = [ stdenv.lib.maintainers.thoughtpolice stdenv.lib.maintainers.tomberek ];
+  minecraft-server_1_12_2 = common {
+    version = "1.12.2";
+    url = "https://s3.amazonaws.com/Minecraft.Download/versions/1.12.2/minecraft_server.1.12.2.jar";
+    sha256 = "0zhnac6yvkdgdaag0gb0fgrkgizbwrpf7s76yqdiknfswrs947zy";
   };
+
 }
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 035889134a09..a2a7d5185c14 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -20783,7 +20783,13 @@ in
 
   minecraft = callPackage ../games/minecraft { };
 
-  minecraft-server = callPackage ../games/minecraft-server { };
+  minecraft-server = minecraft-server_1_13_2;
+
+  inherit (callPackages ../games/minecraft-server { })
+    minecraft-server_1_13_2
+    minecraft-server_1_13_1
+    minecraft-server_1_13_0
+    minecraft-server_1_12_2;
 
   moon-buggy = callPackage ../games/moon-buggy {};