Initial commit: LNbits Borg backup NixOS module
This commit is contained in:
commit
5acf4d0f5a
3 changed files with 187 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
result
|
||||||
176
borg-lnbits.nix
Normal file
176
borg-lnbits.nix
Normal file
|
|
@ -0,0 +1,176 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.services.borg-lnbits;
|
||||||
|
|
||||||
|
in {
|
||||||
|
options.services.borg-lnbits = {
|
||||||
|
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"
|
||||||
|
'')
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
10
flake.nix
Normal file
10
flake.nix
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
description = "LNbits Borg backup NixOS module";
|
||||||
|
|
||||||
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs }: {
|
||||||
|
nixosModules.borg-lnbits = import ./borg-lnbits.nix;
|
||||||
|
nixosModules.default = self.nixosModules.borg-lnbits;
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue