{ config, pkgs, lib, ... }: let mcDataDir = "/srv/minecraft/data"; modrinthMods = builtins.concatStringsSep "," [ # Performance "lithium" "krypton" "ferrite-core" "c2me-fabric" "vmp-fabric:alpha" "scalablelux" "lmd" "structure-layout-optimizer" "threadtweak" "crashexploitfixer" # Authentication & skins "easyauth" "skinrestorer" "vanish" # Anti-cheat "anti-xray" "grimac" "no-chat-reports" # Worldgen — terrain (Stardust Labs suite) "terralith" "tectonic" "amplified-nether" "nullscape" # Worldgen — structures (Dungeons and Taverns suite) "dungeons-and-taverns" "dungeons-and-taverns-stronghold-overhaul" "dungeons-and-taverns-ocean-monument-overhaul" "dungeons-and-taverns-desert-temple-overhaul" "dungeons-and-taverns-jungle-temple-overhaul" "dungeons-and-taverns-swamp-hut-overhaul" "dungeons-and-taverns-nether-fortress-overhaul" "dungeons-and-taverns-woodland-mansion-overhaul" "dungeons-and-taverns-pillager-outpost-overhaul" "hopo-better-mineshaft" "explorify" "structory" # Client mod compatibility "appleskin" "simple-voice-chat" "jei:beta" # QoL "better-serversleep" "netherportalfix" "blossomlib" "blossomtpa" "shulker-drops-two" "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:java25"; ports = [ "25565:25565" # Minecraft "24454:24454/udp" # Simple Voice Chat ]; volumes = [ "${mcDataDir}:/data" ]; environment = { TZ = "America/Los_Angeles"; EULA = "TRUE"; TYPE = "FABRIC"; VERSION = "1.21.11"; MEMORY = "6144M"; MAX_PLAYERS = "10"; DIFFICULTY = "hard"; PVP = "FALSE"; VIEW_DISTANCE = "10"; SIMULATION_DISTANCE = "10"; SPAWN_PROTECTION = "0"; ALLOW_FLIGHT = "TRUE"; ENABLE_WHITELIST = "FALSE"; ENFORCE_WHITELIST = "FALSE"; ONLINE_MODE = "FALSE"; MOTD = "meet cool people \\u00A76\\u0026\\u0026\\u00A7r build cool things"; OVERRIDE_ICON = "TRUE"; REMOVE_OLD_MODS = "TRUE"; MODRINTH_DOWNLOAD_DEPENDENCIES = "required"; MODRINTH_PROJECTS = modrinthMods; SYNC_CHUNK_WRITES = "false"; JVM_XX_OPTS = jvmFlags; }; environmentFiles = [ "/run/minecraft-seed.env" ]; extraOptions = [ "--memory=7g" "--pids-limit=256" "--security-opt=no-new-privileges" ]; }; # Data directory systemd.tmpfiles.rules = [ "d ${mcDataDir} 0755 root root -" ]; 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 SEED=$(cat ${config.age.secrets.minecraft-seed.path}) printf 'SEED=%s\n' "$SEED" > /run/minecraft-seed.env chmod 600 /run/minecraft-seed.env cp ${../server-icon.png} ${mcDataDir}/server-icon.png mkdir -p ${mcDataDir}/config cp ${../configs/anti-xray.toml} ${mcDataDir}/config/anti-xray.toml mkdir -p ${mcDataDir}/config/skinrestorer cp ${../configs/skinrestorer-config.json} ${mcDataDir}/config/skinrestorer/config.json mkdir -p ${mcDataDir}/config/EasyAuth cp ${../configs/easyauth-main.conf} ${mcDataDir}/config/EasyAuth/main.conf cp ${../configs/easyauth-extended.conf} ${mcDataDir}/config/EasyAuth/extended.conf ''; }; }; }