From 00cc68b7cc21a1089f06eba8f129b7540a540473 Mon Sep 17 00:00:00 2001 From: satr14 Date: Thu, 7 May 2026 22:37:08 +0700 Subject: [PATCH] init --- modules/system/homelab/mc-backup.nix | 103 +++++++++++++++++++++++++++ modules/system/server.nix | 1 + 2 files changed, 104 insertions(+) create mode 100644 modules/system/homelab/mc-backup.nix diff --git a/modules/system/homelab/mc-backup.nix b/modules/system/homelab/mc-backup.nix new file mode 100644 index 0000000..1a2cb96 --- /dev/null +++ b/modules/system/homelab/mc-backup.nix @@ -0,0 +1,103 @@ +{ pkgs, ... }: let + serverName = "mc0-explorers-creativity"; + serviceName = "minecraft-server-${serverName}"; + backupDir = "/mnt/data/backups/mc"; + keepBackups = 7; # number of backups to retain + rconHost = "localhost"; + rconPort = "25575"; + rconPassword = "howdy"; + ntfyUrl = "http://127.0.0.1:8067"; + ntfyTopic = "mc-backup"; + + backupScript = pkgs.writeShellScriptBin "mc-backup" '' + set -euo pipefail + + rcon() { + ${pkgs.rcon-cli}/bin/rcon-cli --address "${rconHost}:${rconPort}" --password "${rconPassword}" "$@" || true + } + + BACKUP_OK=false + + on_exit() { + # Always restart the server first + echo "[mc-backup] Restarting server..." + systemctl start ${serviceName}.service + + # Notify via ntfy only on failure + if [ "$BACKUP_OK" != "true" ]; then + echo "[mc-backup] Sending failure notification..." + ${pkgs.curl}/bin/curl -s -o /dev/null \ + -H "Title: Minecraft Backup Failed" \ + -H "Priority: high" \ + -H "Tags: warning" \ + -d "Nightly backup failed at $(date '+%Y-%m-%d %H:%M:%S'). Check logs with: journalctl -u mc-backup -n 50" \ + "${ntfyUrl}/${ntfyTopic}" + fi + } + + # Always restart the server on exit, even if the script fails mid-backup + trap on_exit EXIT + + # --- Countdown warnings via RCON --- + echo "[mc-backup] Sending 5-minute warning..." + rcon "say §c[Backup] §fServer will restart in §e5 minutes §ffor a scheduled backup." + + sleep 240 + + echo "[mc-backup] Sending 1-minute warning..." + rcon "say §c[Backup] §fServer restarting in §e1 minute§f." + + sleep 50 + + echo "[mc-backup] Sending 10-second warning..." + rcon "say §c[Backup] §fServer restarting in §e10 seconds§f." + + sleep 10 + + rcon "say §c[Backup] §fShutting down now. Back shortly!" + + # --- Save world & stop --- + echo "[mc-backup] Saving world..." + rcon "save-all" + sleep 5 + + echo "[mc-backup] Stopping ${serviceName}..." + systemctl stop ${serviceName}.service + + # --- Backup --- + echo "[mc-backup] Backing up to ${backupDir}..." + mkdir -p "${backupDir}" + TIMESTAMP=$(date +%Y-%m-%d_%H-%M-%S) + XZ_OPT="-9e" tar -cJf "${backupDir}/mc-backup-$TIMESTAMP.tar.xz" \ + -C /srv/minecraft ${serverName} + + # Prune old backups, keeping the last ${toString keepBackups} + ls -t "${backupDir}"/mc-backup-*.tar.xz | tail -n +${toString (keepBackups + 1)} | xargs -r rm -- + + echo "[mc-backup] Backup complete: mc-backup-$TIMESTAMP.tar.xz" + BACKUP_OK=true + # Server restart is handled by the EXIT trap above + ''; +in { + environment.systemPackages = [ backupScript ]; + + systemd.services.mc-backup = { + description = "Nightly Minecraft server backup"; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${backupScript}/bin/mc-backup"; + User = "root"; + StandardOutput = "journal"; + StandardError = "journal"; + }; + }; + + systemd.timers.mc-backup = { + description = "Nightly Minecraft backup timer"; + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = "daily"; # fires at 00:00:00 every day + Persistent = true; # catch up if the machine was off at midnight + }; + }; +} diff --git a/modules/system/server.nix b/modules/system/server.nix index 57a3ff0..0916649 100644 --- a/modules/system/server.nix +++ b/modules/system/server.nix @@ -26,6 +26,7 @@ in { ./homelab/ai.nix ./homelab/db.nix ./homelab/mc.nix + ./homelab/mc-backup.nix ./core/swapfile.nix ./core/oom.nix