feat(servers): setup borgbackup repos
All checks were successful
Discord / discord commits (push) Successful in 34s

This commit is contained in:
matt1432 2024-03-02 22:04:23 -05:00
parent 8b902e9c00
commit 21c94df25a
8 changed files with 294 additions and 102 deletions

View file

@ -19,7 +19,7 @@
home-manager.nixosModules.home-manager
../modules/arion
../modules/borgbackup.nix
../modules/borgbackup
];
nixpkgs = {

View file

@ -18,7 +18,6 @@ in {
# Custom DNS
local-zone = [
"pve.nelim.org redirect"
"headscale.nelim.org redirect"
"git.nelim.org redirect"
"mc.nelim.org transparent"
@ -34,8 +33,6 @@ in {
then "100.64.0.8"
else "100.64.0.9";
in [
"\"pve.nelim.org IN A 100.64.0.4\""
"\"headscale.nelim.org. IN A ${wanIP}\""
"\"git.nelim.org. IN A ${wanIP}\""

View file

@ -26,6 +26,7 @@ in {
extraGroups = [
"wheel"
"adm"
"borg"
];
};

View file

@ -42,13 +42,6 @@
};
};
swapDevices = [
{
device = "/var/lib/swapfile";
size = 16 * 1024;
}
];
zramSwap.enable = true;
hardware.cpu.intel.updateMicrocode = config.hardware.enableRedistributableFirmware;

View file

@ -29,8 +29,8 @@ in {
rwDataDir = configPath;
};
#services.borgbackup.configs.arion = {
# paths = [configPath];
# exclude = ["**/lineageos*"];
#};
services.borgbackup.configs.arion = {
paths = [configPath];
exclude = ["**/lineageos*"];
};
}

View file

@ -1,87 +0,0 @@
{
config,
lib,
pkgs,
...
}: let
inherit (lib) filterAttrs mapAttrs mkDefault mkIf mkOption types;
cfg = config.services.borgbackup;
secrets = config.sops.secrets;
in {
# Make this file declare default settings
options.services.borgbackup = {
defaults = mkOption {
type = types.attrs;
};
configs = mkOption {
type = types.attrs;
default = {};
};
};
config = {
# TODO: change this to nos
programs.ssh.knownHosts = {
pve.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG/4mrp8E4Ittwg8feRmPtDHSDR2+Pq4uZHeF5MweVcW";
};
services.borgbackup = mkIf (cfg.configs != {}) {
defaults = {
environment = mkDefault {BORG_RSH = "ssh -i ${secrets.borg-ssh.path}";};
# TODO: change this to nos
repo = mkDefault "ssh://matt@pve/data/backups/borg";
encryption = mkDefault {
mode = "repokey";
passCommand = let
cat = "${pkgs.coreutils}/bin/cat";
key = secrets.borg-repo.path;
in "${cat} ${key}";
};
# Run every 3 hours
startAt = mkDefault "00/3:00";
compression = mkDefault "auto,lzma";
};
jobs = let
tempJobs = mapAttrs (_: v: cfg.defaults // v) cfg.configs;
in
mapAttrs (n: v: let
attrs = filterAttrs (n: _: n != "preHook" || n != "postHook" || n != "paths") v;
pathPrefix = "/root/snaps";
snapPath = "${pathPrefix}/${n}";
in
attrs
// {
paths = map (x: snapPath + x) v.paths;
preHook =
v.preHook
or ""
+
/*
bash
*/
''
if [[ ! -d ${pathPrefix} ]]; then
mkdir -p ${pathPrefix}
fi
${pkgs.btrfs-progs}/bin/btrfs subvolume snapshot -r / ${snapPath}
'';
postHook =
/*
bash
*/
''
${pkgs.btrfs-progs}/bin/btrfs subvolume delete ${snapPath}
''
+ v.postHook or "";
})
tempJobs;
};
};
}

View file

@ -0,0 +1,20 @@
{...}: {
imports = [./module.nix];
services.borgbackup = {
existingRepos = [
{
name = "arion";
authorizedKeys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPijoxuSwH9IrS4poewzHHwe64UoX4QY7Qix5VhEdqKR root@servivi"
];
}
{
name = "mc";
authorizedKeys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPijoxuSwH9IrS4poewzHHwe64UoX4QY7Qix5VhEdqKR root@servivi"
];
}
];
};
}

View file

@ -0,0 +1,268 @@
{
config,
lib,
pkgs,
...
}: let
inherit (lib) all any attrValues length mapAttrs mkIf mkOption types;
inherit (builtins) listToAttrs removeAttrs;
inherit (config.sops) secrets;
inherit (config.vars) hostName;
cfg = config.services.borgbackup;
in {
options.services.borgbackup = {
configs = mkOption {
# Taken from https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/backup/borgbackup.nix
type = types.attrsOf (types.submodule (
let
globalConfig = config;
in
{
name,
config,
...
}: {
options = {
paths = mkOption {
type = with types; nullOr (coercedTo str lib.singleton (listOf str));
default = null;
};
dumpCommand = mkOption {
type = with types; nullOr path;
default = null;
};
repo = mkOption {
type = types.str;
default = name;
};
removableDevice = mkOption {
type = types.bool;
default = false;
};
archiveBaseName = mkOption {
type = types.nullOr (types.strMatching "[^/{}]+");
default = "${globalConfig.networking.hostName}-${name}";
};
dateFormat = mkOption {
type = types.str;
default = "+%Y-%m-%dT%H:%M:%S";
};
startAt = mkOption {
type = with types; either str (listOf str);
# Run every 3 hours
default = "00/3:00";
};
persistentTimer = mkOption {
default = false;
type = types.bool;
};
inhibitsSleep = mkOption {
default = false;
type = types.bool;
};
user = mkOption {
type = types.str;
default = "root";
};
group = mkOption {
type = types.str;
default = "root";
};
encryption.mode = mkOption {
type = types.enum [
"repokey"
"keyfile"
"repokey-blake2"
"keyfile-blake2"
"authenticated"
"authenticated-blake2"
"none"
];
default = "none";
};
encryption.passCommand = mkOption {
type = with types; nullOr str;
default = null;
};
encryption.passphrase = mkOption {
type = with types; nullOr str;
default = null;
};
compression = mkOption {
type = types.strMatching "none|(auto,)?(lz4|zstd|zlib|lzma)(,[[:digit:]]{1,2})?";
default = "auto,lz4";
};
exclude = mkOption {
type = with types; listOf str;
default = [];
};
patterns = mkOption {
type = with types; listOf str;
default = [];
};
readWritePaths = mkOption {
type = with types; listOf path;
default = [];
};
privateTmp = mkOption {
type = types.bool;
default = true;
};
doInit = mkOption {
type = types.bool;
default = true;
};
appendFailedSuffix = mkOption {
type = types.bool;
default = true;
};
prune.keep = mkOption {
type = with types; attrsOf (either int (strMatching "[[:digit:]]+[Hdwmy]"));
default = {};
};
prune.prefix = mkOption {
type = types.nullOr (types.str);
default = config.archiveBaseName;
};
environment = mkOption {
type = with types; attrsOf str;
default = {};
};
preHook = mkOption {
type = types.lines;
default = "";
};
postInit = mkOption {
type = types.lines;
default = "";
};
postCreate = mkOption {
type = types.lines;
default = "";
};
postPrune = mkOption {
type = types.lines;
default = "";
};
postHook = mkOption {
type = types.lines;
default = "";
};
extraArgs = mkOption {
type = types.str;
default = "";
};
extraInitArgs = mkOption {
type = types.str;
default = "";
};
extraCreateArgs = mkOption {
type = types.str;
default = "";
};
extraPruneArgs = mkOption {
type = types.str;
default = "";
};
extraCompactArgs = mkOption {
type = types.str;
default = "";
};
};
}
));
default = {};
};
existingRepos = mkOption {
type = with types;
listOf (submodule {
options = {
name = mkOption {
type = str;
};
authorizedKeys = mkOption {
type = listOf str;
default = [];
};
};
});
default = [];
};
};
config = mkIf (cfg.configs != {}) {
assertions = [
{
assertion = all (
conf:
any (repo: conf.repo == repo.name) cfg.existingRepos
) (attrValues cfg.configs);
message = ''
The repo you want to backup to needs to exist.
'';
}
];
programs.ssh.knownHosts = {
nos.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG/4mrp8E4Ittwg8feRmPtDHSDR2+Pq4uZHeF5MweVcW";
};
services.borgbackup = let
backupDir = "/data/borgbackups";
in {
repos =
mkIf (hostName == "nos" && length cfg.existingRepos > 0)
(listToAttrs (map (r: {
inherit (r) name;
value = {
authorizedKeysAppendOnly = r.authorizedKeys;
path = "${backupDir}/${r.name}";
};
})
cfg.existingRepos));
jobs = mapAttrs (n: v: let
otherAttrs = removeAttrs v [
"environment"
"paths"
"preHook"
"postHook"
"repo"
];
pathPrefix = "/root/snaps";
snapPath = "${pathPrefix}/${n}";
in
{
environment = v.environment // (mkIf (hostName != "nos") {BORG_RSH = "ssh -i ${secrets.borg-ssh.path}";});
paths = map (x: snapPath + x) v.paths;
preHook =
v.preHook
+ ''
if [[ ! -d ${pathPrefix} ]]; then
mkdir -p ${pathPrefix}
fi
${pkgs.btrfs-progs}/bin/btrfs subvolume snapshot -r / ${snapPath}
'';
postHook =
v.postHook
+ ''
${pkgs.btrfs-progs}/bin/btrfs subvolume delete ${snapPath}
'';
repo =
if (hostName != "nos")
then "ssh://matt@nos${backupDir}/${v.repo}"
else "${backupDir}/${v.repo}";
}
// otherAttrs)
cfg.configs;
};
};
}