dotfiles/modules/nixos/gaming/minecraft-server.nix

161 lines
4.3 KiB
Nix
Raw Normal View History

2024-04-20 13:42:06 +00:00
{
config,
pkgs,
lib,
...
}:
2022-10-14 01:34:35 +00:00
let
localPort = 25564;
2022-10-15 12:16:05 +00:00
publicPort = 49732;
2022-10-14 01:34:35 +00:00
rconPort = 25575;
rconPassword = "thiscanbeanything";
2024-04-20 13:42:06 +00:00
in
{
2022-10-10 23:09:32 +00:00
config = lib.mkIf config.services.minecraft-server.enable {
2022-12-21 21:18:03 +00:00
unfreePackages = [ "minecraft-server" ];
services.minecraft-server = {
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;
};
2022-10-14 01:34:35 +00:00
};
2022-12-21 21:18:03 +00:00
networking.firewall.allowedTCPPorts = [ publicPort ];
2022-10-14 01:34:35 +00:00
cloudflare.noProxyDomains = [ config.hostnames.minecraft ];
2022-12-21 21:18:03 +00:00
## Automatically start and stop Minecraft server based on player connections
2022-10-14 01:34:35 +00:00
2022-12-21 21:18:03 +00:00
# Adapted shamelessly from:
# https://dataswamp.org/~solene/2022-08-20-on-demand-minecraft-with-systemd.html
2022-10-14 01:34:35 +00:00
2022-12-21 21:18:03 +00:00
# Prevent Minecraft from starting by default
2024-04-20 13:42:06 +00:00
systemd.services.minecraft-server = {
wantedBy = pkgs.lib.mkForce [ ];
};
2022-10-14 01:34:35 +00:00
2022-12-21 21:18:03 +00:00
# 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}" ];
};
2022-10-14 01:34:35 +00:00
2022-12-21 21:18:03 +00:00
# Proxy traffic to local port, and trigger hook-minecraft
systemd.services.listen-minecraft = {
path = [ pkgs.systemd ];
2024-04-20 13:42:06 +00:00
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}";
2022-12-21 21:18:03 +00:00
};
# Start Minecraft if required and wait for it to be available
# Then unlock the listen-minecraft.service
systemd.services.hook-minecraft = {
2024-04-20 13:42:06 +00:00
path = with pkgs; [
systemd
libressl
busybox
];
2022-12-21 21:18:03 +00:00
# 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
2024-04-20 13:42:06 +00:00
if ${pkgs.libressl.nc}/bin/nc -z 127.0.0.1 ${toString localPort} > /dev/null ; then
2022-12-21 21:18:03 +00:00
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"
2022-10-14 01:34:35 +00:00
exit 0
fi
2022-12-21 21:18:03 +00:00
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
'';
2022-10-10 23:09:32 +00:00
};
};
}