compsigh-minecraft/modules/minecraft.nix

162 lines
4 KiB
Nix

{ config, pkgs, lib, ... }:
let
mcDataDir = "/srv/minecraft/data";
modrinthMods = builtins.concatStringsSep "," [
# Performance
"lithium"
"krypton"
"ferrite-core"
"c2me-fabric"
"noisium"
"linearly-optimized"
"vmp-fabric"
"ksyxis"
"scalablelux"
"lmd"
"structure-layout-optimizer"
"threadtweak"
"crashexploitfixer"
# Anti-cheat
"anti-xray"
"grimac"
"no-chat-reports"
# Worldgen — terrain (Stardust Labs suite)
"terralith"
"tectonic"
"amplified-nether"
"nullscape"
# Worldgen — structures (YUNG's suite)
"yungs-api"
"yungs-better-dungeons"
"yungs-better-strongholds"
"yungs-better-ocean-monuments"
"yungs-better-mineshafts"
"yungs-better-desert-temples"
"yungs-better-jungle-temples"
"yungs-better-witch-huts"
"yungs-better-nether-fortresses"
"yungs-better-end-island"
"yungs-extras"
"yungs-bridges"
# Client mod compatibility (optional on client side)
"appleskin"
"simple-voice-chat"
# QoL
"oneplayersleep"
"netherportalfix"
"blossomlib"
"blossomtpa"
"double-shulker-shell-drops"
"afkplus"
# Moderation
"ledger"
"styled-chat"
# Discord bridge
"discord-mc-chat"
# Utilities
"chunky"
];
jvmFlags = builtins.concatStringsSep " " [
"-XX:+UseG1GC"
"-XX:+ParallelRefProcEnabled"
"-XX:MaxGCPauseMillis=200"
"-XX:+UnlockExperimentalVMOptions"
"-XX:+DisableExplicitGC"
"-XX:G1NewSizePercent=30"
"-XX:G1MaxNewSizePercent=40"
"-XX:G1HeapRegionSize=8M"
"-XX:G1ReservePercent=20"
"-XX:G1MixedGCCountTarget=4"
"-XX:InitiatingHeapOccupancyPercent=15"
"-XX:G1MixedGCLiveThresholdPercent=90"
"-XX:SurvivorRatio=32"
"-XX:+PerfDisableSharedMem"
"-XX:MaxTenuringThreshold=1"
];
in
{
virtualisation.docker.enable = true;
virtualisation.oci-containers.backend = "docker";
virtualisation.oci-containers.containers.minecraft = {
image = "itzg/minecraft-server:java21";
ports = [
"25565:25565" # Minecraft
"24454:24454/udp" # Simple Voice Chat
];
volumes = [
"${mcDataDir}:/data"
];
environment = {
EULA = "TRUE";
TYPE = "FABRIC";
VERSION = "1.21.4";
MEMORY = "2560M";
MAX_PLAYERS = "10";
DIFFICULTY = "hard";
PVP = "FALSE";
VIEW_DISTANCE = "10";
SIMULATION_DISTANCE = "10";
ENABLE_WHITELIST = "TRUE";
ENFORCE_WHITELIST = "TRUE";
WHITELIST = "jetpham";
OPS = "jetpham";
MOTD = "meet cool people \\u00A7e\\u0026\\u0026\\u00A7r build cool things";
OVERRIDE_ICON = "TRUE";
MODRINTH_PROJECTS = modrinthMods;
JVM_XX_OPTS = jvmFlags;
};
environmentFiles = [ "/run/minecraft-seed.env" ];
extraOptions = [
"--memory=3g"
"--cpus=2"
"--pids-limit=256"
"--security-opt=no-new-privileges"
];
};
# Ensure data directory exists
systemd.tmpfiles.rules = [
"d ${mcDataDir} 0755 root root -"
];
# Write seed env file and copy mod configs before container starts
systemd.services.minecraft-mod-configs = {
description = "Set up mod configs and seed for Minecraft container";
wantedBy = [ "multi-user.target" ];
before = [ "docker-minecraft.service" ];
after = [ "agenix.service" ];
serviceConfig = {
Type = "oneshot";
ExecStart = pkgs.writeShellScript "setup-mod-configs" ''
set -euo pipefail
# Write seed from agenix secret
SEED=$(cat ${config.age.secrets.minecraft-seed.path})
printf 'SEED=%s\n' "$SEED" > /run/minecraft-seed.env
chmod 600 /run/minecraft-seed.env
# Server icon
cp ${../server-icon.png} ${mcDataDir}/server-icon.png
# Mod configs
mkdir -p ${mcDataDir}/plugins/Chunky
cp ${../configs/chunky.yml} ${mcDataDir}/plugins/Chunky/config.yml
mkdir -p ${mcDataDir}/config
cp ${../configs/anti-xray.toml} ${mcDataDir}/config/anti-xray.toml
'';
};
};
}