{ config, pkgs, ... }: let mcDataDir = "/srv/minecraft/data"; b2Bucket = "compsigh-server-backups"; in { systemd.services.minecraft-backup = { description = "Backup Minecraft world to Backblaze B2"; after = [ "docker-minecraft.service" ]; path = [ pkgs.docker pkgs.gzip ]; serviceConfig = { Type = "oneshot"; ExecStart = pkgs.writeShellScript "minecraft-backup" '' set -euo pipefail TEMP_BACKUP="/tmp/minecraft-world-latest.tar.gz" # Check if the container is running if ! docker ps --format '{{.Names}}' | grep -q '^minecraft$'; then echo "Minecraft container not running, skipping backup" exit 0 fi # Flush all chunks to disk and pause saving docker exec minecraft rcon-cli save-all flush sleep 2 docker exec minecraft rcon-cli save-off # Compress world data (re-enable saving even if tar fails) if ! ${pkgs.gnutar}/bin/tar czf "$TEMP_BACKUP" \ -C ${mcDataDir} world; then echo "tar failed, re-enabling saving" docker exec minecraft rcon-cli save-on exit 1 fi # Re-enable saving immediately docker exec minecraft rcon-cli save-on # Upload to B2 (overwrites the single backup file) B2_ACCOUNT=$(cat ${config.age.secrets.b2-account-id.path}) B2_KEY=$(cat ${config.age.secrets.b2-application-key.path}) ${pkgs.rclone}/bin/rclone copyto \ "$TEMP_BACKUP" \ ":b2:${b2Bucket}/world-latest.tar.gz" \ --b2-account "$B2_ACCOUNT" \ --b2-key "$B2_KEY" \ --no-check-dest # Clean up local temp file rm -f "$TEMP_BACKUP" echo "Backup uploaded to Backblaze B2 successfully" ''; }; }; systemd.timers.minecraft-backup = { wantedBy = [ "timers.target" ]; timerConfig = { OnCalendar = "*:00/10"; Persistent = true; }; }; }