From 766b738a6a6323921352e4fe82c11b4642609177 Mon Sep 17 00:00:00 2001 From: kalipso Date: Sun, 16 Mar 2025 00:54:31 +0100 Subject: [PATCH 1/9] [malovpn] change peers.nix address to string without CIDR notation this way we can easily use ip by hostname in other modules --- machines/modules/malobeo/peers.nix | 12 ++++++------ machines/modules/malobeo/wireguard.nix | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/machines/modules/malobeo/peers.nix b/machines/modules/malobeo/peers.nix index febf4c5..5f2de9b 100644 --- a/machines/modules/malobeo/peers.nix +++ b/machines/modules/malobeo/peers.nix @@ -2,7 +2,7 @@ "vpn" = { role = "server"; publicIp = "5.9.153.217"; - address = [ "10.100.0.1/24" ]; + address = "10.100.0.1"; allowedIPs = [ "10.100.0.0/24" ]; listenPort = 51821; publicKey = "hF9H10Y8Ar7zvZXFoNM8LSoaYFgPCXv30c54SSEucX4="; @@ -11,35 +11,35 @@ "celine" = { role = "client"; - address = [ "10.100.0.2/24" ]; + address = "10.100.0.2"; allowedIPs = [ "10.100.0.2/32" ]; publicKey = "Jgx82tSOmZJS4sm1o8Eci9ahaQdQir2PLq9dBqsWZw4="; }; "desktop" = { role = "client"; - address = [ "10.100.0.3/24" ]; + address = "10.100.0.3"; allowedIPs = [ "10.100.0.3/32" ]; publicKey = "FtY2lcdWcw+nvtydOOUDyaeh/xkaqHA8y9GXzqU0Am0="; }; "atlan-pc" = { role = "client"; - address = [ "10.100.0.5/24" ]; + address = "10.100.0.5"; allowedIPs = [ "10.100.0.5/32" ]; publicKey = "TrJ4UAF//zXdaLwZudI78L+rTC36zEDodTDOWNS4Y1Y="; }; "hetzner" = { role = "client"; - address = [ "10.100.0.6/24" ]; + address = "10.100.0.6"; allowedIPs = [ "10.100.0.6/32" ]; publicKey = "csRzgwtnzmSLeLkSwTwEOrdKq55UOxZacR5D3GopCTQ="; }; "fanny" = { role = "client"; - address = [ "10.100.0.101/24" ]; + address = "10.100.0.101"; allowedIPs = [ "10.100.0.101/32" ]; publicKey = "3U59F6T1s/1LaZBIa6wB0qsVuO6pRR9jfYZJIH2piAU="; }; diff --git a/machines/modules/malobeo/wireguard.nix b/machines/modules/malobeo/wireguard.nix index b2a534f..6c5a320 100644 --- a/machines/modules/malobeo/wireguard.nix +++ b/machines/modules/malobeo/wireguard.nix @@ -70,7 +70,7 @@ in interfaces = { malovpn = { mtu = 1340; #seems to be necessary to proxypass nginx traffic through vpn - address = myPeer.address; + address = [ "${myPeer.address}/24" ]; autostart = cfg.autostart; listenPort = mkIf (myPeer.role == "server") myPeer.listenPort; -- 2.51.2 From 286e03c8530725c744d6cfb47821b7be2b6a0bb8 Mon Sep 17 00:00:00 2001 From: kalipso Date: Sun, 16 Mar 2025 00:57:24 +0100 Subject: [PATCH 2/9] [backup] WIP setup sanoid/syncoid module --- machines/modules/malobeo/backup.nix | 84 +++++++++++++++++++++++++++++ outputs.nix | 1 + 2 files changed, 85 insertions(+) create mode 100644 machines/modules/malobeo/backup.nix diff --git a/machines/modules/malobeo/backup.nix b/machines/modules/malobeo/backup.nix new file mode 100644 index 0000000..9ae4b30 --- /dev/null +++ b/machines/modules/malobeo/backup.nix @@ -0,0 +1,84 @@ +{ config, lib, pkgs, ... }: +with lib; +let + cfg = config.malobeo.backup; + newfunc = (hostname: datasetNames: (map (dataset: { name = "${hostname}_${dataset.sourceDataset}"; value = { inherit hostname; inherit dataset; }; } ) datasetNames)); + peers = import ./peers.nix; +in +{ + options.malobeo.backup = { + enable = mkOption { + type = types.bool; + default = false; + description = "Enable sharing metrics"; + }; + + snapshots = mkOption { + type = types.listOf types.str; + default = []; + description = "Automatic snapshots will be created for the given datasets"; + }; + + #TODO: instead listof str we need dataset here to declare the dataset name on the source host + # and also the dataset name on target host (which stores the backups) + hosts = mkOption { + type = types.attrsOf (types.listOf (types.submodule { + options = { + sourceDataset = mkOption { + type = types.str; + }; + targetDataset = mkOption { + type = types.str; + }; + }; + })); + description = "Hostname with list of datasets to backup."; + }; + }; + + config = mkIf (cfg.enable) { + services.sanoid = { + enable = true; + + templates."default" = { + hourly = 0; + daily = 30; #keep 30 daily snapshots + monthly = 6; #keep 6 monthly backups + yearly = 0; + + autosnap = true; #take snapshots automatically + autoprune = true; #delete old snapshots + }; + + datasets = builtins.listToAttrs (map (name: { inherit name; value = { + useTemplate = [ "default" ]; + recursive = true; + }; }) cfg.snapshots); + }; + + services.syncoid = with config; { + enable = true; + + sshKey = sops.secrets.backup_key.path; + + commonArgs = [ + "--no-sync-snap" + ]; + + interval = "*-*-* 04:15:00"; + + commands = builtins.mapAttrs (name: value: { + source = "backup@${peers.${value.hostname}.address}:${value.dataset.sourceDataset}"; + target = "${value.dataset.targetDataset}"; + sendOptions = "w"; + recvOptions = "\"\""; + recursive = true; + })(builtins.listToAttrs (builtins.concatLists (builtins.attrValues (builtins.mapAttrs newfunc cfg.hosts)))); + }; + + sops.secrets.backup_key = { + owner = config.services.syncoid.user; + key = "backup_key"; + }; + }; +} diff --git a/outputs.nix b/outputs.nix index 4f341e6..b7c2db6 100644 --- a/outputs.nix +++ b/outputs.nix @@ -116,6 +116,7 @@ in (utils.lib.eachSystem (builtins.filter filter_system utils.lib.defaultSystems metrics.imports = [ ./machines/modules/malobeo/metrics.nix ]; disko.imports = [ ./machines/modules/disko ]; users.imports = [ ./machines/modules/malobeo/users.nix ]; + backup.imports = [ ./machines/modules/malobeo/backup.nix ]; }; hydraJobs = nixpkgs.lib.mapAttrs (_: nixpkgs.lib.hydraJob) ( -- 2.51.2 From d5e94b50cbef9f25426de8bad57dfa6830f08add Mon Sep 17 00:00:00 2001 From: kalipso Date: Sun, 16 Mar 2025 10:09:03 +0100 Subject: [PATCH 3/9] [backup] fix errors --- machines/modules/malobeo/backup.nix | 47 +++++++++++++++++------------ 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/machines/modules/malobeo/backup.nix b/machines/modules/malobeo/backup.nix index 9ae4b30..7f20e69 100644 --- a/machines/modules/malobeo/backup.nix +++ b/machines/modules/malobeo/backup.nix @@ -2,8 +2,18 @@ with lib; let cfg = config.malobeo.backup; - newfunc = (hostname: datasetNames: (map (dataset: { name = "${hostname}_${dataset.sourceDataset}"; value = { inherit hostname; inherit dataset; }; } ) datasetNames)); + hostToCommand = (hostname: datasetNames: + (map (dataset: { + name = "${hostname}_${dataset.sourceDataset}"; + value = { + inherit hostname; + inherit (dataset) sourceDataset targetDataset; + }; + } ) datasetNames)); peers = import ./peers.nix; + + enableSnapshots = cfg.snapshots != null; + enableBackups = cfg.hosts != null; in { options.malobeo.backup = { @@ -14,15 +24,14 @@ in }; snapshots = mkOption { - type = types.listOf types.str; - default = []; + type = types.nullOr (types.listOf types.str); + default = null; description = "Automatic snapshots will be created for the given datasets"; }; - #TODO: instead listof str we need dataset here to declare the dataset name on the source host - # and also the dataset name on target host (which stores the backups) hosts = mkOption { - type = types.attrsOf (types.listOf (types.submodule { + default = null; + type = types.nullOr (types.attrsOf (types.listOf (types.submodule { options = { sourceDataset = mkOption { type = types.str; @@ -31,13 +40,19 @@ in type = types.str; }; }; - })); + }))); description = "Hostname with list of datasets to backup."; }; + + sshKey = mkOption { + default = null; + type = types.nullOr types.str; + description = "Set path to ssh key used for pull backups. Otherwise default key is used"; + }; }; config = mkIf (cfg.enable) { - services.sanoid = { + services.sanoid = mkIf (enableSnapshots) { enable = true; templates."default" = { @@ -56,10 +71,9 @@ in }; }) cfg.snapshots); }; - services.syncoid = with config; { + services.syncoid = mkIf (enableBackups) { enable = true; - - sshKey = sops.secrets.backup_key.path; + sshKey = cfg.sshKey; commonArgs = [ "--no-sync-snap" @@ -68,17 +82,12 @@ in interval = "*-*-* 04:15:00"; commands = builtins.mapAttrs (name: value: { - source = "backup@${peers.${value.hostname}.address}:${value.dataset.sourceDataset}"; - target = "${value.dataset.targetDataset}"; + source = "backup@${peers.${value.hostname}.address}:${value.sourceDataset}"; + target = "${value.targetDataset}"; sendOptions = "w"; recvOptions = "\"\""; recursive = true; - })(builtins.listToAttrs (builtins.concatLists (builtins.attrValues (builtins.mapAttrs newfunc cfg.hosts)))); - }; - - sops.secrets.backup_key = { - owner = config.services.syncoid.user; - key = "backup_key"; + })(builtins.listToAttrs (builtins.concatLists (builtins.attrValues (builtins.mapAttrs hostToCommand cfg.hosts)))); }; }; } -- 2.51.2 From 96dee29595e58fe7de2007ce7aa4bf200faac726 Mon Sep 17 00:00:00 2001 From: kalipso Date: Sun, 16 Mar 2025 10:18:39 +0100 Subject: [PATCH 4/9] [fanny] enable backup user --- machines/fanny/configuration.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/machines/fanny/configuration.nix b/machines/fanny/configuration.nix index 786ce20..0fa9c9a 100644 --- a/machines/fanny/configuration.nix +++ b/machines/fanny/configuration.nix @@ -53,6 +53,7 @@ in malobeo.users = { malobeo = true; admin = true; + backup = true; }; malobeo.disks = { -- 2.51.2 From 91d86c49a1cf3c4da950561c55c4b32987aa2a76 Mon Sep 17 00:00:00 2001 From: kalipso Date: Sun, 16 Mar 2025 10:18:57 +0100 Subject: [PATCH 5/9] [fanny] enable automatic snapshots --- machines/fanny/configuration.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/machines/fanny/configuration.nix b/machines/fanny/configuration.nix index 0fa9c9a..40faf29 100644 --- a/machines/fanny/configuration.nix +++ b/machines/fanny/configuration.nix @@ -18,6 +18,7 @@ in inputs.self.nixosModules.malobeo.microvm inputs.self.nixosModules.malobeo.metrics inputs.self.nixosModules.malobeo.users + inputs.self.nixosModules.malobeo.backup ]; virtualisation.vmVariantWithDisko = { @@ -42,6 +43,11 @@ in cacheurl = "https://cache.dynamicdiscord.de"; }; + malobeo.backup = { + enable = true; + snapshots = [ "storage/encrypted" "zroot/encrypted/var" ]; + }; + nix = { settings.experimental-features = [ "nix-command" "flakes" ]; #always update microvms -- 2.51.2 From 70ec63f21384831f0be3854c8fc3dedef99b7a4a Mon Sep 17 00:00:00 2001 From: kalipso Date: Sun, 16 Mar 2025 10:24:17 +0100 Subject: [PATCH 6/9] [users] fix typo --- machines/modules/malobeo/users.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/machines/modules/malobeo/users.nix b/machines/modules/malobeo/users.nix index 8017a51..b159c5c 100644 --- a/machines/modules/malobeo/users.nix +++ b/machines/modules/malobeo/users.nix @@ -68,7 +68,7 @@ in users = [ "backup" ]; commands = [ { - command = "${pkgs.zfs-user}/bin/zfs"; + command = "${pkgs.zfs}/bin/zfs"; options = [ "NOPASSWD" ]; } ]; @@ -94,4 +94,4 @@ in ]; } ]; -} \ No newline at end of file +} -- 2.51.2 From 302171664023ad3ef805fa1fa26b7f4528637a22 Mon Sep 17 00:00:00 2001 From: kalipso Date: Sun, 16 Mar 2025 11:15:52 +0100 Subject: [PATCH 7/9] [backup] update module descriptions --- machines/modules/malobeo/backup.nix | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/machines/modules/malobeo/backup.nix b/machines/modules/malobeo/backup.nix index 7f20e69..d577465 100644 --- a/machines/modules/malobeo/backup.nix +++ b/machines/modules/malobeo/backup.nix @@ -35,13 +35,22 @@ in options = { sourceDataset = mkOption { type = types.str; + description = "The source that needs to be backed up"; }; targetDataset = mkOption { type = types.str; + description = "The target dataset where the backup should be stored"; }; }; }))); - description = "Hostname with list of datasets to backup."; + description = ''' + Hostname with list of datasets to backup. This option should be defined on hosts that will store backups. + + It is necessary to add the machines that get backed up to known hosts. + This can be done for example systemwide using + programs.ssh.knownHosts."10.100.0.101" = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHqp2/YiiIhai7wyScGZJ20gtrzY+lp4N/8unyRs4qhc"; + Or set it for the syncoid user directly. + '''; }; sshKey = mkOption { -- 2.51.2 From 026494c877edba0ec8a0ffcaaaa32b267aca2826 Mon Sep 17 00:00:00 2001 From: kalipso Date: Sun, 16 Mar 2025 11:25:37 +0100 Subject: [PATCH 8/9] [backup] fix typo --- machines/modules/malobeo/backup.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/machines/modules/malobeo/backup.nix b/machines/modules/malobeo/backup.nix index d577465..4a5be46 100644 --- a/machines/modules/malobeo/backup.nix +++ b/machines/modules/malobeo/backup.nix @@ -43,14 +43,14 @@ in }; }; }))); - description = ''' + description = '' Hostname with list of datasets to backup. This option should be defined on hosts that will store backups. It is necessary to add the machines that get backed up to known hosts. This can be done for example systemwide using programs.ssh.knownHosts."10.100.0.101" = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHqp2/YiiIhai7wyScGZJ20gtrzY+lp4N/8unyRs4qhc"; Or set it for the syncoid user directly. - '''; + ''; }; sshKey = mkOption { -- 2.51.2 From be0bb0b08b917841bfb06dce1b6fcffa3839cf42 Mon Sep 17 00:00:00 2001 From: kalipso Date: Sun, 16 Mar 2025 12:53:43 +0100 Subject: [PATCH 9/9] [backup] fix description --- machines/modules/malobeo/backup.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/machines/modules/malobeo/backup.nix b/machines/modules/malobeo/backup.nix index 4a5be46..990318c 100644 --- a/machines/modules/malobeo/backup.nix +++ b/machines/modules/malobeo/backup.nix @@ -20,7 +20,7 @@ in enable = mkOption { type = types.bool; default = false; - description = "Enable sharing metrics"; + description = "Enable sanoid/syncoid based backup functionality"; }; snapshots = mkOption { -- 2.51.2