backup-archive: switch to NixOS borg module

While Borgmatic is great, the NixOS module does have easier
configuration for various use cases such as backups in removable
devices. To make this possible in Borgmatic, you have to go through some
loops.

Borgmatic does have easier way of indicating paths. However, in recent
versions of Borg, they have the experimental feature of indicate both
include and exclude through patterns which is close enough.

Also, because of this, we'll be deprecating the custom borgmatic service
at this point. It'll be removed once all of my NixOS-related backup
setups are not using it.
This commit is contained in:
Gabriel Arazas 2022-02-19 16:58:08 +08:00
parent 9d318a9a74
commit 207a682045
10 changed files with 128 additions and 45 deletions

View File

@ -1,43 +0,0 @@
# This is my external hard drive.
{ config, options, lib, pkgs, ... }:
# TODO: Make this a generic service.
# There are multiple external storage drives now.
let cfg = config.hardware-setup.backup-archive;
in {
options.hardware-setup.backup-archive.enable = lib.mkEnableOption
"external hard drive and automated backup service with BorgBackup";
config = lib.mkIf cfg.enable {
assertions = [{
assertion = config.profiles.agenix.enable;
message = "Agenix module is not enabled.";
}];
age.secrets.external-backup-borgmatic-settings.file =
lib.getSecret "archive/borgmatic.json";
fileSystems."/mnt/external-storage" = {
device = "/dev/disk/by-uuid/665A391C5A38EB07";
fsType = "ntfs";
noCheck = true;
options = [
"nofail"
"noauto"
"user"
# See systemd.mount.5 and systemd.automount.5 manual page for more
# details.
"x-systemd.automount"
"x-systemd.device-timeout=2"
"x-systemd.idle-timeout=2"
];
};
# This uses the custom borgmatic NixOS service.
services.borgmatic-fds.jobs.external-storage = {
startAt = "04/6:00:00";
configPath = config.age.secrets.external-backup-borgmatic-settings.path;
};
};
}

View File

@ -0,0 +1,5 @@
= BorgBackup setup for the archive
It's a NixOS configuration that configures my basic BorgBackup backup battlestation for my local archive.
Not all of the required files are here (i.e., the SSH key used for Borg).
In other words, if it's not yours, don't attempt to activate this setup.

View File

@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ1IdisweU/qW+Np36K1WoR+RsPSyG6JcLNp96m1rDWx foo-dogsquared@ni

View File

@ -0,0 +1,114 @@
# This is my external hard drive with the backup setup with borg.
{ config, options, lib, pkgs, ... }:
let
cfg = config.hardware-setup.backup-archive;
borgJobCommonSetting = { patterns ? [ ] }: {
compression = "zstd,9";
dateFormat = "+%F-%H-%M-%S-%z";
doInit = true;
encryption = {
mode = "repokey-blake2";
passCommand = "cat ${config.age.secrets.borg-password.path}";
};
extraCreateArgs = lib.concatStringsSep " "
(builtins.map (patternFile: "--patterns-from ${patternFile}") patterns);
extraInitArgs = "--make-parent-dirs";
# We're emptying them since we're specifying them all through the patterns file.
paths = [ ];
persistentTimer = true;
preHook = ''
extraCreateArgs="$extraCreateArgs --exclude-if-present .nobackup"
extraCreateArgs="$extraCreateArgs --stats"
'';
prune = {
keep = {
within = "1d";
hourly = 8;
daily = 30;
weekly = 4;
monthly = 6;
yearly = 3;
};
};
};
in {
options.hardware-setup.backup-archive.enable =
lib.mkEnableOption "backup setup with BorgBackup";
config = lib.mkIf cfg.enable {
assertions = [{
assertion = config.profiles.agenix.enable;
message = ''
Agenix module is not enabled. This is for the borgmatic configuration
we're using.
'';
}];
age.secrets.borg-password.file = lib.getSecret "archive/password";
age.secrets.borg-patterns.file = lib.getSecret "archive/borg-patterns";
age.secrets.borg-patterns-local.file =
lib.getSecret "archive/borg-patterns-local";
age.secrets.borg-ssh-key.file = lib.getSecret "archive/borg-ssh-key";
fileSystems."/mnt/external-storage" = {
device = "/dev/disk/by-uuid/665A391C5A38EB07";
fsType = "ntfs";
noCheck = true;
options = [
"nofail"
"noauto"
"user"
# See systemd.mount.5 and systemd.automount.5 manual page for more
# details.
"x-systemd.automount"
"x-systemd.device-timeout=2"
"x-systemd.idle-timeout=2"
];
};
services.borgbackup.jobs = {
local = borgJobCommonSetting {
patterns = [
config.age.secrets.borg-patterns-local.path
config.age.secrets.borg-patterns.path
];
} // {
doInit = true;
repo = "/archives/";
startAt = "04/5:00:00";
};
local-archive = borgJobCommonSetting {
patterns = [
config.age.secrets.borg-patterns-local.path
config.age.secrets.borg-patterns.path
];
} // {
doInit = false;
removableDevice = true;
repo = "/mnt/external-storage/backups";
startAt = "daily";
};
remote-borgbase = borgJobCommonSetting {
patterns = [ config.age.secrets.borg-patterns.path ];
} // {
doInit = false;
repo = "m9s7d92s@m9s7d92s.repo.borgbase.com:repo";
startAt = "daily";
environment.BORG_RSH = "ssh -i ${config.age.secrets.borg-ssh-key.path}";
};
};
programs.ssh.extraConfig = ''
Host *.repo.borgbase.com
IdentityFile ${config.age.secrets.borg-ssh-key.path}
'';
};
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
secrets/archive/key Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1,6 +1,9 @@
let
system1 =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG42LafAFOeh3oYz/cm6FXes0ss59/EOCXpGsYvhpI21";
system2 =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHjRjAddjbyoM32tQhCjj8OrnqNBsXj+5D379iryupK+";
systems = [ system1 system2 ];
user1 =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMclb6WPpYRoMVqCCzQcG2XQHczB6vaIEDIHqjVsyQJi";
@ -10,7 +13,10 @@ let
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIytwsseYS6kV8ldiUV767C2Gy7okxckdDRW4aA3q/Ku";
user4 =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGtn+t2D7clY1U1rzKcSCBJjNbuJzbRArEiM3soyFcnv";
users = [ user1 user2 user3 user4 ];
in {
"archive/password".publicKeys = [ system1 user3 user4 ];
"archive/borgmatic.json".publicKeys = [ system1 user3 user4 ];
"archive/borg-patterns".publicKeys = users ++ systems;
"archive/borg-patterns-local".publicKeys = users ++ systems;
"archive/password".publicKeys = users ++ systems;
"archive/key".publicKeys = users ++ systems;
}