mirror of
				https://github.com/nmasur/dotfiles
				synced 2025-11-04 07:03:17 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			167 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
{
 | 
						|
  config,
 | 
						|
  pkgs,
 | 
						|
  lib,
 | 
						|
  ...
 | 
						|
}:
 | 
						|
 | 
						|
let
 | 
						|
  inherit (config.nmasur.settings) hostnames;
 | 
						|
  cfg = config.nmasur.presets.services.minecraft-server;
 | 
						|
  localPort = 25564;
 | 
						|
  publicPort = 49732;
 | 
						|
  rconPort = 25575;
 | 
						|
  rconPassword = "thiscanbeanything";
 | 
						|
in
 | 
						|
 | 
						|
{
 | 
						|
 | 
						|
  options.nmasur.presets.services.minecraft-server.enable = lib.mkEnableOption "Minecraft server";
 | 
						|
 | 
						|
  config = lib.mkIf cfg.enable {
 | 
						|
 | 
						|
    allowUnfreePackages = [ "minecraft-server" ];
 | 
						|
 | 
						|
    services.minecraft-server = {
 | 
						|
      enable = true;
 | 
						|
      eula = true;
 | 
						|
      declarative = true;
 | 
						|
      whitelist = { };
 | 
						|
      openFirewall = false;
 | 
						|
      serverProperties = {
 | 
						|
        server-port = localPort;
 | 
						|
        difficulty = "normal";
 | 
						|
        gamemode = "survival";
 | 
						|
        white-list = false;
 | 
						|
        enforce-whitelist = false;
 | 
						|
        level-name = "world";
 | 
						|
        motd = "Welcome!";
 | 
						|
        pvp = true;
 | 
						|
        player-idle-timeout = 30;
 | 
						|
        generate-structures = true;
 | 
						|
        max-players = 20;
 | 
						|
        snooper-enabled = false;
 | 
						|
        spawn-npcs = true;
 | 
						|
        spawn-animals = true;
 | 
						|
        spawn-monsters = true;
 | 
						|
        allow-nether = true;
 | 
						|
        allow-flight = false;
 | 
						|
        enable-rcon = true;
 | 
						|
        "rcon.port" = rconPort;
 | 
						|
        "rcon.password" = rconPassword;
 | 
						|
      };
 | 
						|
    };
 | 
						|
 | 
						|
    networking.firewall.allowedTCPPorts = [ publicPort ];
 | 
						|
 | 
						|
    nmasur.presets.services.cloudflare.noProxyDomains = [ hostnames.minecraft ];
 | 
						|
 | 
						|
    ## Automatically start and stop Minecraft server based on player connections
 | 
						|
 | 
						|
    # Adapted shamelessly from:
 | 
						|
    # https://dataswamp.org/~solene/2022-08-20-on-demand-minecraft-with-systemd.html
 | 
						|
 | 
						|
    # Prevent Minecraft from starting by default
 | 
						|
    systemd.services.minecraft-server = {
 | 
						|
      wantedBy = pkgs.lib.mkForce [ ];
 | 
						|
    };
 | 
						|
 | 
						|
    # Listen for connections on the public port, to trigger the actual
 | 
						|
    # listen-minecraft service.
 | 
						|
    systemd.sockets.listen-minecraft = {
 | 
						|
      wantedBy = [ "sockets.target" ];
 | 
						|
      requires = [ "network.target" ];
 | 
						|
      listenStreams = [ "${toString publicPort}" ];
 | 
						|
    };
 | 
						|
 | 
						|
    # Proxy traffic to local port, and trigger hook-minecraft
 | 
						|
    systemd.services.listen-minecraft = {
 | 
						|
      path = [ pkgs.systemd ];
 | 
						|
      requires = [
 | 
						|
        "hook-minecraft.service"
 | 
						|
        "listen-minecraft.socket"
 | 
						|
      ];
 | 
						|
      after = [
 | 
						|
        "hook-minecraft.service"
 | 
						|
        "listen-minecraft.socket"
 | 
						|
      ];
 | 
						|
      serviceConfig.ExecStart = "${pkgs.systemd.out}/lib/systemd/systemd-socket-proxyd 127.0.0.1:${toString localPort}";
 | 
						|
    };
 | 
						|
 | 
						|
    # Start Minecraft if required and wait for it to be available
 | 
						|
    # Then unlock the listen-minecraft.service
 | 
						|
    systemd.services.hook-minecraft = {
 | 
						|
      path = with pkgs; [
 | 
						|
        systemd
 | 
						|
        libressl
 | 
						|
        busybox
 | 
						|
      ];
 | 
						|
 | 
						|
      # Start Minecraft and the auto-shutdown timer
 | 
						|
      script = ''
 | 
						|
        systemctl start minecraft-server.service
 | 
						|
        systemctl start stop-minecraft.timer
 | 
						|
      '';
 | 
						|
 | 
						|
      # Keep checking until the service is available
 | 
						|
      postStart = ''
 | 
						|
        for i in $(seq 60); do
 | 
						|
          if ${pkgs.libressl.nc}/bin/nc -z 127.0.0.1 ${toString localPort} > /dev/null ; then
 | 
						|
            exit 0
 | 
						|
          fi
 | 
						|
          ${pkgs.busybox.out}/bin/sleep 1
 | 
						|
        done
 | 
						|
        exit 1
 | 
						|
      '';
 | 
						|
    };
 | 
						|
 | 
						|
    # Run a player check on a schedule for auto-shutdown
 | 
						|
    systemd.timers.stop-minecraft = {
 | 
						|
      timerConfig = {
 | 
						|
        OnCalendar = "*-*-* *:*:0/20"; # Every 20 seconds
 | 
						|
        Unit = "stop-minecraft.service";
 | 
						|
      };
 | 
						|
    };
 | 
						|
 | 
						|
    # If no players are connected, then stop services and prepare to resume again
 | 
						|
    systemd.services.stop-minecraft = {
 | 
						|
      serviceConfig.Type = "oneshot";
 | 
						|
      script = ''
 | 
						|
        # Check when service was launched
 | 
						|
        servicestartsec=$(
 | 
						|
          date -d \
 | 
						|
            "$(systemctl show \
 | 
						|
                 --property=ActiveEnterTimestamp \
 | 
						|
                 minecraft-server.service \
 | 
						|
                 | cut -d= -f2)" \
 | 
						|
          +%s)
 | 
						|
 | 
						|
        # Calculate elapsed time
 | 
						|
        serviceelapsedsec=$(( $(date +%s) - servicestartsec))
 | 
						|
 | 
						|
        # Ignore if service just started
 | 
						|
        if [ $serviceelapsedsec -lt 180 ]
 | 
						|
        then
 | 
						|
          echo "Server was just started"
 | 
						|
          exit 0
 | 
						|
        fi
 | 
						|
 | 
						|
        PLAYERS=$(
 | 
						|
          printf "list\n" \
 | 
						|
            | ${pkgs.rcon.out}/bin/rcon -m \
 | 
						|
            -H 127.0.0.1 -p ${builtins.toString rconPort} -P ${rconPassword} \
 | 
						|
        )
 | 
						|
 | 
						|
        if echo "$PLAYERS" | grep "are 0 of a"
 | 
						|
        then
 | 
						|
          echo "Stopping server"
 | 
						|
          systemctl stop minecraft-server.service
 | 
						|
          systemctl stop hook-minecraft.service
 | 
						|
          systemctl stop stop-minecraft.timer
 | 
						|
        fi
 | 
						|
      '';
 | 
						|
    };
 | 
						|
 | 
						|
  };
 | 
						|
}
 |