• Incorporates Apprise for sending backup start and completion notifications • Captures and formats backup statistics for richer log details • Updates backup exclusion lists to prevent unneeded data inclusion • Standardizes and extends SMTP configuration in secrets management
224 lines
6.3 KiB
Nix
224 lines
6.3 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
|
|
let
|
|
# Borg backup destinations
|
|
dockerStorageRepo = "/pool/Backups/DockerStorage";
|
|
forgejoRepo = "/pool/Backups/forgejo";
|
|
|
|
# Common borg backup settings
|
|
borgCommonSettings = ''
|
|
# Don't use cache to avoid issues with concurrent backups
|
|
export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes
|
|
|
|
# Set this for non-interactive use
|
|
export BORG_NON_INTERACTIVE=yes
|
|
'';
|
|
|
|
# Initialize a repo if it doesn't exist
|
|
initRepo = repo: ''
|
|
if [ ! -d "${repo}" ]; then
|
|
mkdir -p "${repo}"
|
|
${pkgs.borgbackup}/bin/borg init --encryption=none "${repo}"
|
|
fi
|
|
'';
|
|
|
|
# Function to send notifications
|
|
apprise-url = config.secretsSpec.users.admin.smtp.notifyUrl;
|
|
sendNotification = title: message: ''
|
|
# Send notification through Apprise
|
|
${pkgs.apprise}/bin/apprise -t "${title}" -b "${message}" "${apprise-url}" || true
|
|
'';
|
|
|
|
# Get borg stats in a readable format
|
|
extractBorgStats = logFile: ''
|
|
# Extract and format relevant stats
|
|
echo -e "\nBackup Stats:" > ${logFile}
|
|
grep -A15 "Archive name:" ${logFile} >> ${logFile}.stats || true
|
|
STATS=$(cat ${logFile}.stats || echo "No stats available")
|
|
'';
|
|
|
|
in
|
|
{
|
|
# Make sure borg and apprise are installed
|
|
environment.systemPackages = with pkgs; [
|
|
borgbackup
|
|
apprise
|
|
];
|
|
|
|
# Docker Storage Backup Service
|
|
systemd.services.backup-docker-storage = {
|
|
description = "Backup Docker storage directory with Borg";
|
|
|
|
path = with pkgs; [
|
|
borgbackup
|
|
coreutils
|
|
apprise
|
|
gnugrep
|
|
];
|
|
|
|
script = ''
|
|
${borgCommonSettings}
|
|
|
|
# Set up log file and temporary stats file
|
|
LOG_FILE="/tmp/borg-docker-backup-$(date +%Y%m%d-%H%M%S).log"
|
|
|
|
# Send start notification
|
|
${sendNotification "🚀 Docker Storage Backup Started" "Starting Docker Storage backup on $(hostname) at $(date)"}
|
|
|
|
# Initialize repository if needed
|
|
${initRepo dockerStorageRepo}
|
|
|
|
# Create backup and capture output/stats
|
|
echo "Starting backup at $(date)" > $LOG_FILE
|
|
ARCHIVE_NAME="docker-$(date +%Y-%m-%d_%H%M%S)"
|
|
|
|
# Run backup command and capture exit status
|
|
${pkgs.borgbackup}/bin/borg create \
|
|
--stats \
|
|
--compression zstd,15 \
|
|
--exclude '*.tmp' \
|
|
--exclude '*/tmp/*' \
|
|
${dockerStorageRepo}::$ARCHIVE_NAME \
|
|
/mnt/drive1/DockerStorage >> $LOG_FILE 2>&1
|
|
|
|
BACKUP_STATUS=$?
|
|
|
|
# Extract stats from log file
|
|
${extractBorgStats "$LOG_FILE"}
|
|
|
|
# Prune old backups
|
|
echo -e "\nPruning old backups..." >> $LOG_FILE
|
|
${pkgs.borgbackup}/bin/borg prune \
|
|
--keep-daily 7 \
|
|
--keep-weekly 4 \
|
|
--keep-monthly 3 \
|
|
${dockerStorageRepo} >> $LOG_FILE 2>&1
|
|
|
|
PRUNE_STATUS=$?
|
|
|
|
# Send completion notification
|
|
if [ $BACKUP_STATUS -eq 0 ] && [ $PRUNE_STATUS -eq 0 ]; then
|
|
${sendNotification "✅ Docker Storage Backup Complete" "Docker Storage backup completed successfully on $(hostname) at $(date)\n\n$STATS"}
|
|
else
|
|
${sendNotification "❌ Docker Storage Backup Failed" "Docker Storage backup failed on $(hostname) at $(date)\n\nBackup Status: $BACKUP_STATUS\nPrune Status: $PRUNE_STATUS\n\nSee $LOG_FILE for details"}
|
|
fi
|
|
|
|
# Clean up temp stats file
|
|
rm -f $LOG_FILE.stats
|
|
|
|
# Return exit status from backup operation
|
|
exit $BACKUP_STATUS
|
|
'';
|
|
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
IOSchedulingClass = "idle";
|
|
CPUSchedulingPolicy = "idle";
|
|
Nice = 19;
|
|
};
|
|
};
|
|
|
|
# Docker Storage Backup Timer (Weekly on Monday at 4am)
|
|
systemd.timers.backup-docker-storage = {
|
|
description = "Timer for Docker Storage Backup";
|
|
|
|
wantedBy = [ "timers.target" ];
|
|
|
|
timerConfig = {
|
|
OnCalendar = "Mon *-*-* 04:00:00";
|
|
Persistent = true; # Run backup if system was off during scheduled time
|
|
RandomizedDelaySec = "5min"; # Add randomized delay
|
|
};
|
|
};
|
|
|
|
# Forgejo Backup Service
|
|
systemd.services.backup-forgejo = {
|
|
description = "Backup Forgejo directory with Borg";
|
|
|
|
path = with pkgs; [
|
|
borgbackup
|
|
coreutils
|
|
apprise
|
|
gnugrep
|
|
];
|
|
|
|
script = ''
|
|
${borgCommonSettings}
|
|
|
|
# Set up log file and temporary stats file
|
|
LOG_FILE="/tmp/borg-forgejo-backup-$(date +%Y%m%d-%H%M%S).log"
|
|
|
|
# Send start notification
|
|
${sendNotification "🚀 Forgejo Backup Started" "Starting Forgejo backup on $(hostname) at $(date)"}
|
|
|
|
# Initialize repository if needed
|
|
${initRepo forgejoRepo}
|
|
|
|
# Create backup and capture output/stats
|
|
echo "Starting backup at $(date)" > $LOG_FILE
|
|
ARCHIVE_NAME="forgejo-$(date +%Y-%m-%d_%H%M%S)"
|
|
|
|
# Run backup command and capture exit status
|
|
${pkgs.borgbackup}/bin/borg create \
|
|
--stats \
|
|
--compression zstd,15 \
|
|
--exclude '*.tmp' \
|
|
--exclude '*/tmp/*' \
|
|
${forgejoRepo}::$ARCHIVE_NAME \
|
|
/pool/forgejo >> $LOG_FILE 2>&1
|
|
|
|
BACKUP_STATUS=$?
|
|
|
|
# Extract stats from log file
|
|
${extractBorgStats "$LOG_FILE"}
|
|
|
|
# Prune old backups
|
|
echo -e "\nPruning old backups..." >> $LOG_FILE
|
|
${pkgs.borgbackup}/bin/borg prune \
|
|
--keep-daily 14 \
|
|
--keep-weekly 4 \
|
|
--keep-monthly 3 \
|
|
${forgejoRepo} >> $LOG_FILE 2>&1
|
|
|
|
PRUNE_STATUS=$?
|
|
|
|
# Send completion notification
|
|
if [ $BACKUP_STATUS -eq 0 ] && [ $PRUNE_STATUS -eq 0 ]; then
|
|
${sendNotification "✅ Forgejo Backup Complete" "Forgejo backup completed successfully on $(hostname) at $(date)\n\n$STATS"}
|
|
else
|
|
${sendNotification "❌ Forgejo Backup Failed" "Forgejo backup failed on $(hostname) at $(date)\n\nBackup Status: $BACKUP_STATUS\nPrune Status: $PRUNE_STATUS\n\nSee $LOG_FILE for details"}
|
|
fi
|
|
|
|
# Clean up temp stats file
|
|
rm -f $LOG_FILE.stats
|
|
|
|
# Return exit status from backup operation
|
|
exit $BACKUP_STATUS
|
|
'';
|
|
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
IOSchedulingClass = "idle";
|
|
CPUSchedulingPolicy = "idle";
|
|
Nice = 19;
|
|
};
|
|
};
|
|
|
|
# Forgejo Backup Timer (Every 2 days at 4am)
|
|
systemd.timers.backup-forgejo = {
|
|
description = "Timer for Forgejo Backup";
|
|
|
|
wantedBy = [ "timers.target" ];
|
|
|
|
timerConfig = {
|
|
OnCalendar = "*-*-1/2 04:00:00"; # Every 2 days at 4am
|
|
Persistent = true;
|
|
RandomizedDelaySec = "5min";
|
|
};
|
|
};
|
|
}
|