add backup thing
This commit is contained in:
parent
f7414548ec
commit
07c7e98316
10 changed files with 302 additions and 0 deletions
|
|
@ -15,6 +15,20 @@
|
|||
immich.enable = true;
|
||||
actual.enable = true;
|
||||
# seafile.enable = true;
|
||||
|
||||
# Backup server - exposes data for pull-based backups
|
||||
backup-server = {
|
||||
enable = true;
|
||||
zfsSnapshots = {
|
||||
enable = true;
|
||||
# Keep snapshots for point-in-time recovery
|
||||
frequent = 4; # 4 x 15min = 1 hour of frequent snapshots
|
||||
hourly = 24; # 24 hours
|
||||
daily = 7; # 1 week
|
||||
weekly = 4; # 1 month
|
||||
monthly = 12; # 1 year
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hardware = {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,20 @@
|
|||
desktopEnvironment.gnome.enable = true;
|
||||
hardware.systemd-boot.enable = false; # Mobile devices use different bootloader
|
||||
programs.graphical.enable = false;
|
||||
|
||||
services = {
|
||||
# Backup client - pulls vaultwarden backup from apollo
|
||||
backup-client = {
|
||||
enable = true;
|
||||
backups = {
|
||||
apollo-vaultwarden = {
|
||||
remoteHost = "apollo";
|
||||
localPath = "/var/backups/apollo-vaultwarden";
|
||||
services = [ "vaultwarden" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# mobile-nixos needs aliases (uses nettools instead of net-tools)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,18 @@
|
|||
wanikani-bypass-lessons.enable = true;
|
||||
wanikani-fetch-data.enable = true;
|
||||
wanikani-stats.enable = true;
|
||||
|
||||
# Backup client - pulls full backup from apollo
|
||||
backup-client = {
|
||||
enable = true;
|
||||
backups = {
|
||||
apollo-full = {
|
||||
remoteHost = "apollo"; # Tailscale hostname
|
||||
localPath = "/var/backups/apollo";
|
||||
fullBackup = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
desktopEnvironment.plasma.enable = true;
|
||||
programs.graphical.enable = false;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,20 @@
|
|||
emulation.aarch64.enable = true;
|
||||
hardware.sound.enable = true;
|
||||
programs.steam.enable = true;
|
||||
|
||||
services = {
|
||||
# Backup client - pulls vaultwarden backup from apollo
|
||||
backup-client = {
|
||||
enable = true;
|
||||
backups = {
|
||||
apollo-vaultwarden = {
|
||||
remoteHost = "apollo";
|
||||
localPath = "/var/backups/apollo-vaultwarden";
|
||||
services = [ "vaultwarden" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
networking.hostName = "tartarus";
|
||||
|
|
|
|||
|
|
@ -8,6 +8,18 @@
|
|||
hydra.enable = true;
|
||||
atticd.enable = true;
|
||||
cloudflared.enable = true;
|
||||
|
||||
# Backup client - pulls full backup from apollo
|
||||
backup-client = {
|
||||
enable = true;
|
||||
backups = {
|
||||
apollo-full = {
|
||||
remoteHost = "apollo"; # Tailscale hostname
|
||||
localPath = "/var/backups/apollo";
|
||||
fullBackup = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,18 @@
|
|||
};
|
||||
services = {
|
||||
ollama.enable = true;
|
||||
|
||||
# Backup client - pulls vaultwarden backup from apollo
|
||||
backup-client = {
|
||||
enable = true;
|
||||
backups = {
|
||||
apollo-vaultwarden = {
|
||||
remoteHost = "apollo";
|
||||
localPath = "/var/backups/apollo-vaultwarden";
|
||||
services = [ "vaultwarden" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
i18n.enable = true;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -147,6 +147,100 @@
|
|||
wanikani-bypass-lessons.enable = lib.mkEnableOption "wanikani-bypass-lessons";
|
||||
wanikani-fetch-data.enable = lib.mkEnableOption "wanikani-fetch-data";
|
||||
wanikani-stats.enable = lib.mkEnableOption "wanikani-stats";
|
||||
|
||||
# Backup server - exposes data for pull-based backups
|
||||
backup-server = {
|
||||
enable = lib.mkEnableOption "backup server (exposes data for pull-based backups)";
|
||||
|
||||
zfsSnapshots = {
|
||||
enable = lib.mkEnableOption "automatic ZFS snapshots of /persist";
|
||||
|
||||
frequent = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 4;
|
||||
description = "Number of frequent (15-min) snapshots to keep";
|
||||
};
|
||||
|
||||
hourly = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 24;
|
||||
description = "Number of hourly snapshots to keep";
|
||||
};
|
||||
|
||||
daily = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 7;
|
||||
description = "Number of daily snapshots to keep";
|
||||
};
|
||||
|
||||
weekly = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 4;
|
||||
description = "Number of weekly snapshots to keep";
|
||||
};
|
||||
|
||||
monthly = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 12;
|
||||
description = "Number of monthly snapshots to keep";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Backup client - pulls backups from remote servers
|
||||
backup-client = {
|
||||
enable = lib.mkEnableOption "backup client (pulls data from remote servers)";
|
||||
|
||||
backups = lib.mkOption {
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule {
|
||||
options = {
|
||||
remoteHost = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Remote host to backup from (e.g., apollo.tail-scale.ts.net)";
|
||||
};
|
||||
|
||||
remoteUser = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "root";
|
||||
description = "Remote user for SSH connection";
|
||||
};
|
||||
|
||||
localPath = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Local path where backups will be stored";
|
||||
};
|
||||
|
||||
fullBackup = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Whether to backup the entire /persist directory";
|
||||
};
|
||||
|
||||
services = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "List of services to backup (e.g., ['vaultwarden', 'immich'])";
|
||||
example = [
|
||||
"vaultwarden"
|
||||
"immich"
|
||||
"forgejo"
|
||||
];
|
||||
};
|
||||
|
||||
schedule = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "daily";
|
||||
description = "Backup schedule (systemd timer format)";
|
||||
example = "daily";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
default = { };
|
||||
description = "Backup configurations";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Hardware
|
||||
|
|
|
|||
95
modules/nixos/services/backup-client.nix
Normal file
95
modules/nixos/services/backup-client.nix
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
# Backup client - pulls backups from remote servers via rsync
|
||||
# Supports full backups and selective service backups over Tailscale
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.osbmModules.services.backup-client;
|
||||
|
||||
# Create a backup job for each configured backup
|
||||
makeBackupService =
|
||||
name: backupCfg:
|
||||
let
|
||||
# Build rsync paths based on what we're backing up
|
||||
sourcePaths =
|
||||
if backupCfg.fullBackup then
|
||||
[ "/persist" ] # Full backup of everything
|
||||
else if backupCfg.services != [ ] then
|
||||
# Selective service backups
|
||||
map (service: "/persist/var/lib/${service}") backupCfg.services
|
||||
++ lib.optional (builtins.elem "vaultwarden" backupCfg.services) "/persist/backup/vaultwarden"
|
||||
else
|
||||
[ ]; # Empty list if nothing to backup
|
||||
|
||||
# Rsync command for each source path
|
||||
rsyncCommands = map (source: ''
|
||||
echo "Backing up ${source} from ${backupCfg.remoteHost}..."
|
||||
${pkgs.rsync}/bin/rsync -avz --delete \
|
||||
-e "${pkgs.openssh}/bin/ssh -o StrictHostKeyChecking=accept-new" \
|
||||
${backupCfg.remoteUser}@${backupCfg.remoteHost}:${source}/ \
|
||||
${backupCfg.localPath}/${builtins.baseNameOf source}/
|
||||
'') sourcePaths;
|
||||
in
|
||||
{
|
||||
description = "Backup ${name} from ${backupCfg.remoteHost}";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = "root";
|
||||
};
|
||||
|
||||
script = ''
|
||||
set -e
|
||||
|
||||
# Create backup directory if it doesn't exist
|
||||
mkdir -p ${backupCfg.localPath}
|
||||
|
||||
# Run rsync for each source path
|
||||
${lib.concatStringsSep "\n" rsyncCommands}
|
||||
|
||||
echo "Backup ${name} completed successfully at $(date)"
|
||||
'';
|
||||
};
|
||||
|
||||
makeBackupTimer = name: backupCfg: {
|
||||
description = "Timer for ${name} backup";
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
OnCalendar = backupCfg.schedule;
|
||||
Persistent = true;
|
||||
RandomizedDelaySec = "30m"; # Randomize to avoid all backups running at once
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
config = lib.mkIf cfg.enable {
|
||||
# Create systemd services for each backup
|
||||
systemd.services = lib.mapAttrs' (
|
||||
name: backupCfg: lib.nameValuePair "backup-${name}" (makeBackupService name backupCfg)
|
||||
) cfg.backups;
|
||||
|
||||
# Create systemd timers for each backup
|
||||
systemd.timers = lib.mapAttrs' (
|
||||
name: backupCfg: lib.nameValuePair "backup-${name}" (makeBackupTimer name backupCfg)
|
||||
) cfg.backups;
|
||||
|
||||
# Ensure rsync and openssh are available
|
||||
environment.systemPackages = with pkgs; [
|
||||
rsync
|
||||
openssh
|
||||
];
|
||||
|
||||
# Ensure Tailscale is enabled for secure connections
|
||||
assertions = [
|
||||
{
|
||||
assertion = config.services.tailscale.enable;
|
||||
message = "backup-client requires Tailscale to be enabled for secure connections";
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
33
modules/nixos/services/backup-server.nix
Normal file
33
modules/nixos/services/backup-server.nix
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# Backup server - exposes data for backup clients to pull
|
||||
# Enables ZFS snapshots for local point-in-time recovery
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.osbmModules.services.backup-server;
|
||||
in
|
||||
{
|
||||
config = lib.mkIf cfg.enable {
|
||||
# Enable ZFS auto-snapshots if requested
|
||||
services.zfs.autoSnapshot = lib.mkIf cfg.zfsSnapshots.enable {
|
||||
enable = true;
|
||||
inherit (cfg.zfsSnapshots)
|
||||
frequent
|
||||
hourly
|
||||
daily
|
||||
weekly
|
||||
monthly
|
||||
;
|
||||
};
|
||||
|
||||
# Ensure SSH is enabled for backup access
|
||||
assertions = [
|
||||
{
|
||||
assertion = config.services.openssh.enable;
|
||||
message = "backup-server requires openssh to be enabled";
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
./actual.nix
|
||||
./anubis.nix
|
||||
./atticd.nix
|
||||
./backup-client.nix
|
||||
./backup-server.nix
|
||||
./cloudflared.nix
|
||||
./ollama.nix
|
||||
./openssh.nix
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue