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.
This commit is contained in:
padreug 2025-10-26 01:21:48 +02:00
parent 253890ac16
commit 17ac393c32
4 changed files with 1031 additions and 0 deletions

View file

@ -0,0 +1,35 @@
{ config, pkgs, ... }:
{
imports = [
./modules/lnbits-backup.nix # Add this line
];
# Enable LNbits Borg backup
services.lnbits-backup = {
enable = true;
# Repository path - update with your actual path
# Option 1: Traditional format
# repository = "borg@192.168.1.100:/mnt/my_ssd/borg-backups/lnbits";
# Option 2: Full SSH URL format (note double slash for absolute path)
repository = "ssh://borg@<your-backup-ip>//mnt/borg-backups/lnbits";
# Backup schedule
schedule = "*:0/15"; # Backup schedule (hourly, daily, or systemd timer format)
# Compression with auto-detection
# "auto" skips compression for already-compressed files (images, videos, etc.)
compression = "auto,lz4"; # For Raspberry Pi (faster)
# compression = "auto,zstd"; # For RockPro64 (better compression)
# Retention policy, leave all of these
retention = {
hourly = 24; # Last 24 hours
daily = 7; # Last 7 days
weekly = 4; # Last 4 weeks
monthly = 6; # Last 6 months
};
};
}

View file

@ -16,6 +16,10 @@ in
# Import boot configuration (bootloader settings)
./boot.nix
# BORG backup
# read docs/lnbits-borg-backup-guide.md
# ./borg-lnbits.nix
# Import any machine-specific services
# Comment out or remove if not needed
# ./example-service.nix

View file

@ -0,0 +1,177 @@
{ 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"
'')
];
};
}