krops-multi-deploy/config/machines/example-machine/modules/lnbits-backup.nix
padreug 17ac393c32 Adds LNbits Borg backup module
Implements a new module for backing up LNbits data using Borg.

This module automates hourly backups, encrypts the data, and provides point-in-time recovery. It includes scripts for listing, restoring, and mounting backups. A comprehensive setup guide is provided in the documentation.

The configuration allows specifying the Borg repository location, schedule, compression settings, retention policy, and SSH key for secure access.
2025-11-01 11:25:36 +01:00

177 lines
4.9 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.lnbits-backup;
in {
options.services.lnbits-backup = {
enable = mkEnableOption "LNbits Borg Backup Service";
dataPath = mkOption {
type = types.path;
default = "/var/lib/lnbits/data";
description = "Path to LNbits data directory";
};
repository = mkOption {
type = types.str;
example = "ssh://borg@192.168.1.100//mnt/my_ssd/borg-backups/lnbits";
description = "Borg repository location (SSH URL or user@host:/path format)";
};
schedule = mkOption {
type = types.str;
default = "hourly";
description = "Backup schedule (hourly, daily, or systemd timer format)";
};
compression = mkOption {
type = types.str;
default = "auto,lz4";
description = "Compression: auto,lz4 (Pi), auto,zstd (RockPro64). 'auto' skips already-compressed files.";
};
passphraseFile = mkOption {
type = types.path;
default = "/root/secrets/borg-passphrase";
description = "Path to Borg passphrase file";
};
sshKeyFile = mkOption {
type = types.path;
default = "/root/.ssh/borg_backup_key";
description = "SSH private key for repository access";
};
retention = {
hourly = mkOption { type = types.int; default = 24; };
daily = mkOption { type = types.int; default = 7; };
weekly = mkOption { type = types.int; default = 4; };
monthly = mkOption { type = types.int; default = 6; };
};
alertEmail = mkOption {
type = types.nullOr types.str;
default = null;
description = "Email for alerts (optional)";
};
};
config = mkIf cfg.enable {
services.borgbackup.jobs.lnbits = {
paths = [
cfg.dataPath
"/tmp/lnbits-snapshot.sqlite3"
];
exclude = [ "*.log" "*.pyc" "__pycache__" "*.tmp" ];
repo = cfg.repository;
encryption = {
mode = "repokey-blake2";
passCommand = "cat ${cfg.passphraseFile}";
};
compression = cfg.compression;
startAt = cfg.schedule;
persistentTimer = true; # Run missed backups after reboots
prune.keep = {
inherit (cfg.retention) hourly daily weekly monthly;
};
preHook = ''
echo "=== LNbits Backup Starting: $(date) ==="
if [ -f "${cfg.dataPath}/database.sqlite3" ]; then
echo "Creating SQLite snapshot..."
${pkgs.sqlite}/bin/sqlite3 "${cfg.dataPath}/database.sqlite3" \
".backup '/tmp/lnbits-snapshot.sqlite3'"
SIZE=$(stat -c%s "/tmp/lnbits-snapshot.sqlite3")
echo "Snapshot created: $SIZE bytes"
if [ "$SIZE" -lt 1000 ]; then
echo "ERROR: Snapshot too small!"
rm -f /tmp/lnbits-snapshot.sqlite3
exit 1
fi
else
echo "ERROR: Database not found!"
exit 1
fi
'';
postHook = ''
rm -f /tmp/lnbits-snapshot.sqlite3
# Weekly integrity check (Sundays)
if [ $(date +%u) -eq 7 ]; then
echo "Running weekly integrity check..."
${pkgs.borgbackup}/bin/borg check --repository-only ${cfg.repository}
fi
echo "=== Backup Complete: $(date) ==="
'';
environment = {
BORG_RSH = "ssh -i ${cfg.sshKeyFile} -o StrictHostKeyChecking=accept-new";
};
};
# Install required packages and helper commands
environment.systemPackages = with pkgs; [
borgbackup
sqlite
(writeShellScriptBin "lnbits-borg-list" ''
export BORG_PASSPHRASE=$(cat ${cfg.passphraseFile})
export BORG_RSH="ssh -i ${cfg.sshKeyFile}"
${borgbackup}/bin/borg list ${cfg.repository} "$@"
'')
(writeShellScriptBin "lnbits-borg-info" ''
export BORG_PASSPHRASE=$(cat ${cfg.passphraseFile})
export BORG_RSH="ssh -i ${cfg.sshKeyFile}"
${borgbackup}/bin/borg info ${cfg.repository} "$@"
'')
(writeShellScriptBin "lnbits-borg-restore" ''
if [ $# -lt 1 ]; then
echo "Usage: lnbits-borg-restore <archive-name> [destination]"
echo ""
echo "Available archives:"
lnbits-borg-list
exit 1
fi
ARCHIVE="$1"
DEST="''${2:-/tmp/lnbits-restore}"
export BORG_PASSPHRASE=$(cat ${cfg.passphraseFile})
export BORG_RSH="ssh -i ${cfg.sshKeyFile}"
mkdir -p "$DEST"
cd "$DEST"
echo "Restoring to: $DEST"
${borgbackup}/bin/borg extract ${cfg.repository}::$ARCHIVE
echo "Done! Restored files in: $DEST"
'')
(writeShellScriptBin "lnbits-borg-mount" ''
MOUNT="''${1:-/mnt/borg-browse}"
export BORG_PASSPHRASE=$(cat ${cfg.passphraseFile})
export BORG_RSH="ssh -i ${cfg.sshKeyFile}"
mkdir -p "$MOUNT"
${borgbackup}/bin/borg mount ${cfg.repository} "$MOUNT"
echo "Mounted at: $MOUNT"
echo "Unmount: borg umount $MOUNT"
'')
];
};
}