nix-flake/modules/system/homelab/mc-backup.nix
2026-05-07 22:37:08 +07:00

103 lines
3.2 KiB
Nix

{ 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
};
};
}