diff --git a/.sops.yaml b/.sops.yaml index ee31af7..f5bfacd 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -37,7 +37,6 @@ keys: - &summers-monitoring age1vn6ya0japzpgc256jg57fldsqe4udmq50sj5hmkywn7rxfnskevsx2q96u - &summers-nextcloud age1t7zagjfddns4yltupk7nx8xps4gh7mupyz85uuys0wd22cxj5qsq2hw0p7 - &summers-paperless age1rn0pxluh7m8dyeshek06d7scejqlrcewlk8xmyrwt5e5nev2dc2s3s78vq - - &summers-postgresql age12jh5836w3cmazec8ql652p9h3a3xn6quztztzqxg4n0kz7r96dnqqlhxxw - &summers-radicale age1gxg2peektn8x36kk3nsgmeawl73e54kaadqd649ygwrv43kkvejq2cw64z - &summers-storage age1kn34ny229gm0rg7wlcvxmcyjtz4gka6f2vd958fde6vmuzrxcvcsufra90 - &summers-transmission age1y69f2elvmq39lc3t3ucq9y7wt675520n7rvug88qg368qsmmk47qvwrtny @@ -79,7 +78,6 @@ creation_rules: - *summers-monitoring - *summers-nextcloud - *summers-paperless - - *summers-postgresql - *summers-radicale - *summers-storage - *summers-transmission @@ -322,14 +320,6 @@ creation_rules: - *summers - *summers-paperless - - path_regex: hosts/nixos/x86_64-linux/summers/secrets/postgresql/[^/]+\.(yaml|json|env|ini|enc)$ - key_groups: - - pgp: - - *swarsel - age: - - *summers - - *summers-postgresql - - path_regex: hosts/nixos/x86_64-linux/summers/secrets/radicale/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: - pgp: diff --git a/SwarselSystems.org b/SwarselSystems.org index 23924af..26fcf60 100644 --- a/SwarselSystems.org +++ b/SwarselSystems.org @@ -2067,41 +2067,55 @@ The =_module.args= part is needed because we need to set/override the =flake-par More information on the actual packages build can be found in [[#h:64a5cc16-6b16-4802-b421-c67ccef853e1][Packages]]. #+begin_src nix-ts :tangle nix/packages.nix -{ self, inputs, ... }: -{ - imports = [ - ( - { lib, flake-parts-lib, ... }: - flake-parts-lib.mkTransposedPerSystemModule { - name = "pkgs"; - file = ./packages.nix; - option = lib.mkOption { - type = lib.types.unspecified; - }; - } - ) - ]; - flake = _: - let - inherit (self.outputs) lib; - in - { - packages = lib.swarselsystems.forEachLinuxSystem (pkgs: import "${self}/pkgs/flake" { inherit self lib pkgs; }); - }; - - perSystem = { pkgs, system, ... }: - { - # see https://flake.parts/module-arguments.html?highlight=modulewith#persystem-module-parameters - _module.args.pkgs = import inputs.nixpkgs { - inherit system; - config.allowUnfree = true; - overlays = [ - self.overlays.default - ]; + { self, inputs, ... }: + { + imports = [ + ( + { lib, flake-parts-lib, ... }: + flake-parts-lib.mkTransposedPerSystemModule { + name = "pkgs"; + file = ./packages.nix; + option = lib.mkOption { + type = lib.types.unspecified; + }; + } + ) + ]; + flake = _: + let + inherit (self.outputs) lib; + in + { + packages = lib.swarselsystems.forEachLinuxSystem (pkgs: import "${self}/pkgs/flake" { inherit self lib pkgs; }); }; - inherit pkgs; - }; -} + + perSystem = { pkgs, system, ... }: + { + # see https://flake.parts/module-arguments.html?highlight=modulewith#persystem-module-parameters + _module.args.pkgs = import inputs.nixpkgs { + inherit system; + config = { + allowUnfree = true; + + permittedInsecurePackages = [ + # matrix + "olm-3.2.16" + # sonarr + "aspnetcore-runtime-wrapped-6.0.36" + "aspnetcore-runtime-6.0.36" + "dotnet-sdk-wrapped-6.0.428" + "dotnet-sdk-6.0.428" + # + "SDL_ttf-2.0.11" + ]; + }; + overlays = [ + self.overlays.default + ]; + }; + inherit pkgs; + }; + } #+end_src ** Globals :PROPERTIES: @@ -2230,209 +2244,217 @@ The rest of the functions are used to build full NixOS systems as well as halfCo - =ConfigurationsPerArch= does the same for full NixOS systems (NixOS or darwin). These can further be specialized by passing in the corresponding =minimal= arg that is used during bootstrapping. #+begin_src nix-ts :tangle nix/hosts.nix - { self, inputs, ... }: - { - flake = { config, ... }: - let - inherit (self) outputs; - inherit (outputs) lib homeLib; - # lib = (inputs.nixpkgs.lib // inputs.home-manager.lib).extend (_: _: { swarselsystems = import "${self}/lib" { inherit self lib inputs outputs; inherit (inputs) systems; }; }); + { self, inputs, ... }: + { + flake = { config, ... }: + let + inherit (self) outputs; + inherit (outputs) lib homeLib; + # lib = (inputs.nixpkgs.lib // inputs.home-manager.lib).extend (_: _: { swarselsystems = import "${self}/lib" { inherit self lib inputs outputs; inherit (inputs) systems; }; }); - mkNixosHost = { minimal }: configName: arch: - inputs.nixpkgs.lib.nixosSystem { - specialArgs = { - inherit inputs outputs self minimal homeLib configName arch; - inherit (config.pkgs.${arch}) lib; - inherit (config) nodes topologyPrivate; - globals = config.globals.${arch}; - type = "nixos"; - withHomeManager = true; - extraModules = [ "${self}/modules/nixos/common/globals.nix" ]; - }; - modules = [ - inputs.disko.nixosModules.disko - inputs.home-manager.nixosModules.home-manager - inputs.impermanence.nixosModules.impermanence - inputs.lanzaboote.nixosModules.lanzaboote - inputs.microvm.nixosModules.host - inputs.microvm.nixosModules.microvm - inputs.nix-index-database.nixosModules.nix-index - inputs.nix-minecraft.nixosModules.minecraft-servers - inputs.nix-topology.nixosModules.default - inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm - inputs.simple-nixos-mailserver.nixosModules.default - inputs.sops.nixosModules.sops - inputs.stylix.nixosModules.stylix - inputs.swarsel-nix.nixosModules.default - inputs.nixos-nftables-firewall.nixosModules.default - (inputs.nixos-extra-modules + "/modules/guests") - (inputs.nixos-extra-modules + "/modules/interface-naming.nix") - "${self}/hosts/nixos/${arch}/${configName}" - "${self}/profiles/nixos" - "${self}/modules/nixos" - { - _module.args.dns = inputs.dns; + mkNixosHost = { minimal }: configName: arch: + inputs.nixpkgs.lib.nixosSystem { + specialArgs = { + inherit inputs outputs self minimal homeLib configName arch; + inherit (config.pkgs.${arch}) lib; + inherit (config) nodes topologyPrivate; + globals = config.globals.${arch}; + type = "nixos"; + withHomeManager = true; + extraModules = [ "${self}/modules/nixos/common/globals.nix" ]; + }; + modules = [ + inputs.disko.nixosModules.disko + inputs.home-manager.nixosModules.home-manager + inputs.impermanence.nixosModules.impermanence + inputs.lanzaboote.nixosModules.lanzaboote + inputs.microvm.nixosModules.host + inputs.microvm.nixosModules.microvm + inputs.nix-index-database.nixosModules.nix-index + inputs.nix-minecraft.nixosModules.minecraft-servers + inputs.nix-topology.nixosModules.default + inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm + inputs.simple-nixos-mailserver.nixosModules.default + inputs.sops.nixosModules.sops + inputs.stylix.nixosModules.stylix + inputs.swarsel-nix.nixosModules.default + inputs.nixos-nftables-firewall.nixosModules.default + (inputs.nixos-extra-modules + "/modules/guests") + (inputs.nixos-extra-modules + "/modules/interface-naming.nix") + "${self}/hosts/nixos/${arch}/${configName}" + "${self}/profiles/nixos" + "${self}/modules/nixos" + { + _module.args.dns = inputs.dns; - microvm.guest.enable = lib.mkDefault false; + microvm.guest.enable = lib.mkDefault false; - networking.hostName = lib.swarselsystems.mkStrong configName; + networking.hostName = lib.swarselsystems.mkStrong configName; - node = { - name = lib.mkForce configName; - arch = lib.mkForce arch; - type = lib.mkForce "nixos"; - secretsDir = ../hosts/nixos/${arch}/${configName}/secrets; - configDir = ../hosts/nixos/${arch}/${configName}; - lockFromBootstrapping = lib.mkIf (!minimal) (lib.swarselsystems.mkStrong true); - }; + node = { + name = lib.mkForce configName; + arch = lib.mkForce arch; + type = lib.mkForce "nixos"; + secretsDir = ../hosts/nixos/${arch}/${configName}/secrets; + configDir = ../hosts/nixos/${arch}/${configName}; + lockFromBootstrapping = lib.mkIf (!minimal) (lib.swarselsystems.mkStrong true); + }; - swarselprofiles = { - minimal = lib.mkIf minimal (lib.swarselsystems.mkStrong true); - }; + swarselprofiles = { + minimal = lib.mkIf minimal (lib.swarselsystems.mkStrong true); + }; - swarselmodules.server = { - ssh = lib.mkIf (!minimal) (lib.swarselsystems.mkStrong true); - }; + swarselmodules.server = { + ssh = lib.mkIf (!minimal) (lib.swarselsystems.mkStrong true); + }; - swarselsystems = { - mainUser = lib.swarselsystems.mkStrong "swarsel"; - }; - } - ]; - }; + swarselsystems = { + mainUser = lib.swarselsystems.mkStrong "swarsel"; + }; + } + ]; + }; - mkDarwinHost = { minimal }: configName: arch: - inputs.nix-darwin.lib.darwinSystem { - specialArgs = { - inherit inputs lib outputs self minimal configName; - inherit (config) nodes topologyPrivate; - withHomeManager = true; - globals = config.globals.${arch}; - }; - modules = [ - # inputs.disko.nixosModules.disko - # inputs.sops.nixosModules.sops - # inputs.impermanence.nixosModules.impermanence - # inputs.lanzaboote.nixosModules.lanzaboote - # inputs.fw-fanctrl.nixosModules.default - # inputs.nix-topology.nixosModules.default - inputs.home-manager.darwinModules.home-manager - "${self}/hosts/darwin/${arch}/${configName}" - "${self}/modules/nixos/darwin" - # needed for infrastructure - "${self}/modules/shared/meta.nix" - "${self}/modules/nixos/common/globals.nix" - { - node = { - name = lib.mkForce configName; - arch = lib.mkForce arch; - type = lib.mkForce "darwin"; - secretsDir = ../hosts/darwin/${arch}/${configName}/secrets; - }; - } - ]; - }; + mkDarwinHost = { minimal }: configName: arch: + inputs.nix-darwin.lib.darwinSystem { + specialArgs = { + inherit inputs lib outputs self minimal configName; + inherit (config) nodes topologyPrivate; + withHomeManager = true; + globals = config.globals.${arch}; + }; + modules = [ + # inputs.disko.nixosModules.disko + # inputs.sops.nixosModules.sops + # inputs.impermanence.nixosModules.impermanence + # inputs.lanzaboote.nixosModules.lanzaboote + # inputs.fw-fanctrl.nixosModules.default + # inputs.nix-topology.nixosModules.default + inputs.home-manager.darwinModules.home-manager + "${self}/hosts/darwin/${arch}/${configName}" + "${self}/modules/nixos/darwin" + # needed for infrastructure + "${self}/modules/shared/meta.nix" + "${self}/modules/nixos/common/globals.nix" + { + node = { + name = lib.mkForce configName; + arch = lib.mkForce arch; + type = lib.mkForce "darwin"; + secretsDir = ../hosts/darwin/${arch}/${configName}/secrets; + }; + } + ]; + }; - mkHalfHost = configName: type: arch: - let - systemFunc = if (type == "home") then inputs.home-manager.lib.homeManagerConfiguration else inputs.nix-on-droid.lib.nixOnDroidConfiguration; - pkgs = lib.swarselsystems.pkgsFor.${arch}; - in - systemFunc { - inherit pkgs; - extraSpecialArgs = { - inherit inputs lib outputs self configName arch type; - inherit (config) nodes topologyPrivate; - globals = config.globals.${arch}; - minimal = false; - }; - modules = [ - inputs.stylix.homeModules.stylix - inputs.nix-index-database.homeModules.nix-index - inputs.sops.homeManagerModules.sops - inputs.spicetify-nix.homeManagerModules.default - inputs.swarsel-nix.homeModules.default - "${self}/hosts/${type}/${arch}/${configName}" - "${self}/profiles/home" - "${self}/modules/nixos/common/pii.nix" - { - node = { - name = lib.mkForce configName; - arch = lib.mkForce arch; - type = lib.mkForce type; - secretsDir = ../hosts/${type}/${arch}/${configName}/secrets; - }; - } - ]; - }; + mkHalfHost = configName: type: arch: + let + systemFunc = if (type == "home") then inputs.home-manager.lib.homeManagerConfiguration else inputs.nix-on-droid.lib.nixOnDroidConfiguration; + pkgs = lib.swarselsystems.pkgsFor.${arch}; + in + systemFunc { + inherit pkgs; + extraSpecialArgs = { + inherit inputs lib outputs self configName arch type; + inherit (config) nodes topologyPrivate; + globals = config.globals.${arch}; + minimal = false; + }; + modules = [ + inputs.stylix.homeModules.stylix + inputs.nix-index-database.homeModules.nix-index + inputs.sops.homeManagerModules.sops + inputs.spicetify-nix.homeManagerModules.default + inputs.swarsel-nix.homeModules.default + "${self}/hosts/${type}/${arch}/${configName}" + "${self}/profiles/home" + "${self}/modules/nixos/common/pii.nix" + { + node = { + name = lib.mkForce configName; + arch = lib.mkForce arch; + type = lib.mkForce type; + secretsDir = ../hosts/${type}/${arch}/${configName}/secrets; + }; + } + ]; + }; - linuxArches = [ "x86_64-linux" "aarch64-linux" ]; - darwinArches = [ "x86_64-darwin" "aarch64-darwin" ]; - mkArches = type: if (type == "nixos") then linuxArches else if (type == "darwin") then darwinArches else linuxArches ++ darwinArches; + linuxArches = [ "x86_64-linux" "aarch64-linux" ]; + darwinArches = [ "x86_64-darwin" "aarch64-darwin" ]; + mkArches = type: if (type == "nixos") then linuxArches else if (type == "darwin") then darwinArches else linuxArches ++ darwinArches; - readHostDirs = hostDir: - if builtins.pathExists hostDir then - builtins.attrNames - ( - lib.filterAttrs (_: type: type == "directory") - (builtins.readDir hostDir) - ) else [ ]; + readHostDirs = hostDir: + if builtins.pathExists hostDir then + builtins.attrNames + ( + lib.filterAttrs (_: type: type == "directory") + (builtins.readDir hostDir) + ) else [ ]; - mkHalfHostsForArch = type: arch: - let - hostDir = "${self}/hosts/${type}/${arch}"; - hosts = readHostDirs hostDir; - in - lib.genAttrs hosts (host: mkHalfHost host type arch); + mkHalfHostsForArch = type: arch: + let + hostDir = "${self}/hosts/${type}/${arch}"; + hosts = readHostDirs hostDir; + in + lib.genAttrs hosts (host: mkHalfHost host type arch); - mkHostsForArch = type: arch: minimal: - let - hostDir = "${self}/hosts/${type}/${arch}"; - hosts = readHostDirs hostDir; - in - if (type == "nixos") then - lib.genAttrs hosts (host: mkNixosHost { inherit minimal; } host arch) - else if (type == "darwin") then - lib.genAttrs hosts (host: mkDarwinHost { inherit minimal; } host arch) - else { }; + mkHostsForArch = type: arch: minimal: + let + hostDir = "${self}/hosts/${type}/${arch}"; + hosts = readHostDirs hostDir; + in + if (type == "nixos") then + lib.genAttrs hosts (host: mkNixosHost { inherit minimal; } host arch) + else if (type == "darwin") then + lib.genAttrs hosts (host: mkDarwinHost { inherit minimal; } host arch) + else { }; - mkConfigurationsPerArch = type: minimal: - let - arches = mkArches type; - toMake = if (minimal == null) then (arch: _: mkHalfHostsForArch type arch) else (arch: _: mkHostsForArch type arch minimal); - in - lib.concatMapAttrs toMake - (lib.listToAttrs (map (a: { name = a; value = { }; }) arches)); + mkConfigurationsPerArch = type: minimal: + let + arches = mkArches type; + toMake = if (minimal == null) then (arch: _: mkHalfHostsForArch type arch) else (arch: _: mkHostsForArch type arch minimal); + in + lib.concatMapAttrs toMake + (lib.listToAttrs (map (a: { name = a; value = { }; }) arches)); - halfConfigurationsPerArch = type: mkConfigurationsPerArch type null; - configurationsPerArch = type: minimal: mkConfigurationsPerArch type minimal; + halfConfigurationsPerArch = type: mkConfigurationsPerArch type null; + configurationsPerArch = type: minimal: mkConfigurationsPerArch type minimal; - in - { - nixosConfigurations = configurationsPerArch "nixos" false; - nixosConfigurationsMinimal = configurationsPerArch "nixos" true; - darwinConfigurations = configurationsPerArch "darwin" false; - darwinConfigurationsMinimal = configurationsPerArch "darwin" true; - homeConfigurations = halfConfigurationsPerArch "home"; - nixOnDroidConfigurations = halfConfigurationsPerArch "android"; + in + rec { + nixosConfigurations = configurationsPerArch "nixos" false; + nixosConfigurationsMinimal = configurationsPerArch "nixos" true; + darwinConfigurations = configurationsPerArch "darwin" false; + darwinConfigurationsMinimal = configurationsPerArch "darwin" true; + homeConfigurations = halfConfigurationsPerArch "home"; + nixOnDroidConfigurations = halfConfigurationsPerArch "android"; - guestConfigurations = lib.flip lib.concatMapAttrs config.nixosConfigurations ( - _: node: - lib.flip lib.mapAttrs' (node.config.guests or { }) ( - guestName: guestDef: - lib.nameValuePair guestDef.nodeName node.config.microvm.vms.${guestName}.config - ) - ); + guestConfigurations = lib.flip lib.concatMapAttrs config.nixosConfigurations ( + _: node: + lib.flip lib.mapAttrs' (node.config.guests or { }) ( + guestName: guestDef: + lib.nameValuePair guestDef.nodeName node.config.microvm.vms.${guestName}.config + ) + ); - diskoConfigurations.default = import "${self}/files/templates/hosts/nixos/disk-config.nix"; + diskoConfigurations.default = import "${self}/files/templates/hosts/nixos/disk-config.nix"; - nodes = config.nixosConfigurations - // config.darwinConfigurations - // config.guestConfigurations; + nodes = config.nixosConfigurations + // config.darwinConfigurations + // config.guestConfigurations; - "@" = lib.mapAttrs (_: v: v.config.system.build.toplevel) config.nodes; - }; - } + guestResources = lib.mapAttrs + (name: _: let + f = arg: lib.foldr (base: acc: base + acc) 0 (map (node: nodes."${name}-${node}".config.microvm.${arg}) (builtins.attrNames nodes.${name}.config.guests)); + in { + mem = f "mem"; + vcpu = f "vcpu"; + }) nodes; + + "@" = lib.mapAttrs (_: v: v.config.system.build.toplevel) config.nodes; + }; + } #+end_src ** Topology (nix-topology generated network diagram) @@ -4201,26 +4223,6 @@ This is my main server that I run at home. It handles most tasks that require bi serverName = "hintbooth"; }; }; - restic = { - bucketName = "SwarselWinters"; - paths = [ - "/Vault/data/paperless" - "/Vault/data/koillection" - "/Vault/data/postgresql" - "/Vault/data/firefly-iii" - "/Vault/data/radicale" - "/Vault/data/matrix-synapse" - "/Vault/Eternor/Paperless" - "/Vault/Eternor/Bilder" - "/Vault/Eternor/Immich" - ]; - }; - garage = { - data_dir = { - capacity = "200G"; - path = "/Vault/data/garage/data"; - }; - }; }; }; @@ -4232,35 +4234,6 @@ This is my main server that I run at home. It handles most tasks that require bi swarselmodules.server = { diskEncryption = lib.mkForce false; - # nginx = true; # for php stuff - # acme = false; # cert handled by proxy - # wireguard = true; - - # nfs = true; - # kavita = true; - # restic = true; - # jellyfin = true; - # navidrome = true; - # spotifyd = true; - # mpd = true; - # postgresql = true; - # matrix = true; - # nextcloud = true; - # immich = true; - # paperless = true; - # transmission = true; - # syncthing = true; - # grafana = true; - # freshrss = true; - # kanidm = true; - # firefly-iii = true; - # koillection = true; - # radicale = true; - # atuin = true; - # forgejo = true; - # ankisync = true; - # homebox = true; - # opkssh = true; }; networking.nftables.firewall.zones.untrusted.interfaces = [ "lan" "enp3s0" ]; @@ -4385,19 +4358,19 @@ This is my main server that I run at home. It handles most tasks that require bi serverName = "hintbooth"; }; }; - restic = { - bucketName = "SwarselWinters"; - paths = [ - "/Vault/data/paperless" - "/Vault/data/koillection" - "/Vault/data/postgresql" - "/Vault/data/firefly-iii" - "/Vault/data/radicale" - "/Vault/data/matrix-synapse" - "/Vault/Eternor/Paperless" - "/Vault/Eternor/Bilder" - "/Vault/Eternor/Immich" - ]; + restic.targets = { + SwarselState = { + repository = config.repo.secrets.local.resticRepoState; + # nextcloud stores all data in state dir and has no data that needs backup + paths = lib.map (guest: "/Vault/guests/${guest}/state") (builtins.filter (name: name != "nextcloud") (builtins.attrNames config.guests)); + }; + SwarselStorage = { + repository = config.repo.secrets.local.resticRepoStorage; + paths = [ + "/Vault/Eternor/Pictures" + "/Vault/Eternor/Documents/paperless" + ]; + }; }; }; }; @@ -4410,59 +4383,31 @@ This is my main server that I run at home. It handles most tasks that require bi swarselmodules.server = { wireguard = true; - - nginx = true; # for php stuff - acme = false; # cert handled by proxy - - nfs = true; - # kavita = true; restic = true; - jellyfin = true; - navidrome = true; - spotifyd = true; - mpd = true; - postgresql = true; - matrix = true; - nextcloud = true; - immich = true; - paperless = true; - transmission = true; - syncthing = true; - grafana = true; - freshrss = true; - kanidm = true; - firefly-iii = true; - koillection = true; - radicale = true; - atuin = true; - forgejo = true; - ankisync = true; - homebox = true; opkssh = true; }; guests = lib.mkIf (!minimal && config.swarselsystems.withMicroVMs) ( { } - // confLib.mkMicrovm "kavita" { withZfs = true; } - // confLib.mkMicrovm "jellyfin" { withZfs = true; } - // confLib.mkMicrovm "audio" { withZfs = true; } - // confLib.mkMicrovm "postgresql" { withZfs = true; } - // confLib.mkMicrovm "matrix" { withZfs = true; } - // confLib.mkMicrovm "nextcloud" { withZfs = true; } - // confLib.mkMicrovm "immich" { withZfs = true; } - // confLib.mkMicrovm "paperless" { withZfs = true; } - // confLib.mkMicrovm "transmission" { withZfs = true; } - // confLib.mkMicrovm "storage" { withZfs = true; } - // confLib.mkMicrovm "monitoring" { withZfs = true; } - // confLib.mkMicrovm "freshrss" { withZfs = true; } - // confLib.mkMicrovm "kanidm" { withZfs = true; } - // confLib.mkMicrovm "firefly" { withZfs = true; } - // confLib.mkMicrovm "koillection" { withZfs = true; } - // confLib.mkMicrovm "radicale" { withZfs = true; } - // confLib.mkMicrovm "atuin" { withZfs = true; } - // confLib.mkMicrovm "forgejo" { withZfs = true; } // confLib.mkMicrovm "ankisync" { withZfs = true; } + // confLib.mkMicrovm "atuin" { withZfs = true; } + // confLib.mkMicrovm "audio" { withZfs = true; eternorPaths = [ "Music" ]; } + // confLib.mkMicrovm "firefly" { withZfs = true; } + // confLib.mkMicrovm "forgejo" { withZfs = true; } + // confLib.mkMicrovm "freshrss" { withZfs = true; } // confLib.mkMicrovm "homebox" { withZfs = true; } + // confLib.mkMicrovm "immich" { withZfs = true; eternorPaths = [ "Pictures" ]; } + // confLib.mkMicrovm "jellyfin" { withZfs = true; eternorPaths = [ "Videos" ]; } + // confLib.mkMicrovm "kanidm" { withZfs = true; } + // confLib.mkMicrovm "kavita" { withZfs = true; eternorPaths = [ "Books" ]; } + // confLib.mkMicrovm "koillection" { withZfs = true; } + // confLib.mkMicrovm "matrix" { withZfs = true; } + // confLib.mkMicrovm "monitoring" { withZfs = true; } + // confLib.mkMicrovm "nextcloud" { withZfs = true; } + // confLib.mkMicrovm "paperless" { withZfs = true; eternorPaths = [ "Documents" ]; } + // confLib.mkMicrovm "radicale" { withZfs = true; } + // confLib.mkMicrovm "storage" { withZfs = true; eternorPaths = [ "Books" "Videos" "Music" "Pictures" "Software" "Documents" ]; } + // confLib.mkMicrovm "transmission" { withZfs = true; eternorPaths = [ "Books" "Videos" "Music" "Software" ]; } ); networking.nftables.firewall.zones.untrusted.interfaces = [ "lan" "bmc" ]; @@ -4634,6 +4579,16 @@ This is my main server that I run at home. It handles most tasks that require bi :PROPERTIES: :CUSTOM_ID: h:5e571d89-6590-4aa4-a5f4-5c871683d09b :END: + +#+begin_src bash :results output :eval never-export + echo "Currently using $(nix eval .#guestResources.summers.mem 2>/dev/null) MB out of 128GB RAM" + echo "Currently using $(nix eval .#guestResources.summers.vcpu 2>/dev/null) vCPUs. 48 threads are available." +#+end_src + +#+RESULTS: +: Currently using 54272 MB out of 128GB RAM +: Currently using 40 vCPUs. 48 threads are available. + ****** Kavita :PROPERTIES: :CUSTOM_ID: h:14a705ff-1924-41da-a6f8-1537e2f5bfb6 @@ -4670,7 +4625,7 @@ This is my main server that I run at home. It handles most tasks that require bi microvm = { mem = 1024 * 1; - vcpu = 1; + vcpu = 2; }; @@ -4679,7 +4634,7 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # kavita = true; + kavita = true; }; } @@ -4722,7 +4677,7 @@ This is my main server that I run at home. It handles most tasks that require bi microvm = { mem = 1024 * 3; - vcpu = 1; + vcpu = 4; }; swarselprofiles = { @@ -4730,7 +4685,7 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # jellyfin = true; + jellyfin = true; }; } @@ -4781,60 +4736,9 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # navidrome = true; - # spotifyd = true; - # mpd = true; - }; - - } - -#+end_src - -****** Postgresql -:PROPERTIES: -:CUSTOM_ID: h:4dee4e22-33b2-4e6a-b0ab-91061a4efffa -:END: - -#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/summers/guests/postgresql/default.nix - { self, lib, minimal, ... }: - { - imports = [ - "${self}/profiles/nixos/microvm" - "${self}/modules/nixos" - ]; - - swarselsystems = { - isMicroVM = true; - isImpermanence = true; - proxyHost = "twothreetunnel"; - server = { - wireguard.interfaces = { - wgHome = { - isClient = true; - serverName = "hintbooth"; - }; - wgProxy = { - isClient = true; - serverName = "twothreetunnel"; - }; - }; - }; - }; - - - } // lib.optionalAttrs (!minimal) { - - microvm = { - mem = 1024 * 1; - vcpu = 1; - }; - - swarselprofiles = { - microvm = true; - }; - - swarselmodules.server = { - # postgresql = true; + navidrome = true; + spotifyd = true; + mpd = true; }; } @@ -4876,7 +4780,7 @@ This is my main server that I run at home. It handles most tasks that require bi } // lib.optionalAttrs (!minimal) { microvm = { - mem = 1024 * 3; + mem = 1024 * 6; vcpu = 2; }; @@ -4885,7 +4789,7 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # matrix = true; + matrix = true; }; } @@ -4936,9 +4840,9 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # nextcloud = true; - # nginx = true; - # acme = true; + nextcloud = true; + nginx = true; + acme = false; }; } @@ -4980,8 +4884,8 @@ This is my main server that I run at home. It handles most tasks that require bi } // lib.optionalAttrs (!minimal) { microvm = { - mem = 1024 * 8; - vcpu = 8; + mem = 1024 * 16; + vcpu = 14; }; swarselprofiles = { @@ -4989,7 +4893,7 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # immich = true; + immich = true; }; } @@ -5031,7 +4935,7 @@ This is my main server that I run at home. It handles most tasks that require bi } // lib.optionalAttrs (!minimal) { microvm = { - mem = 1024 * 4; + mem = 1024 * 8; vcpu = 4; }; @@ -5040,7 +4944,7 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # paperless = true; + paperless = true; }; } @@ -5063,17 +4967,12 @@ This is my main server that I run at home. It handles most tasks that require bi swarselsystems = { isMicroVM = true; isImpermanence = true; - proxyHost = "twothreetunnel"; server = { wireguard.interfaces = { wgHome = { isClient = true; serverName = "hintbooth"; }; - wgProxy = { - isClient = true; - serverName = "twothreetunnel"; - }; }; }; }; @@ -5091,7 +4990,7 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # transmission = true; + transmission = true; }; } @@ -5142,8 +5041,8 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # nfs = true; - # syncthing = true; + nfs = true; + syncthing = true; }; } @@ -5194,7 +5093,7 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # grafana = true; + grafana = true; }; } @@ -5245,9 +5144,9 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # freshrss = true; - # nginx = true; - # acme = true; + freshrss = true; + nginx = true; + acme = false; }; } @@ -5290,7 +5189,7 @@ This is my main server that I run at home. It handles most tasks that require bi microvm = { mem = 1024 * 4; - vcpu = 1; + vcpu = 2; }; swarselprofiles = { @@ -5298,7 +5197,7 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # kanidm = true; + kanidm = true; }; } @@ -5349,9 +5248,9 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # firefly-iii = true; - # nginx = true; - # acme = true; + firefly-iii = true; + nginx = true; + acme = false; }; } @@ -5402,7 +5301,7 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # koillection = true; + koillection = true; }; } @@ -5453,7 +5352,7 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # radicale = true; + radicale = true; }; } @@ -5504,7 +5403,7 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # atuin = true; + atuin = true; }; } @@ -5555,7 +5454,7 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # forgejo = true; + forgejo = true; }; } @@ -5606,7 +5505,7 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # ankisync = true; + ankisync = true; }; } @@ -5657,7 +5556,7 @@ This is my main server that I run at home. It handles most tasks that require bi }; swarselmodules.server = { - # homebox = true; + homebox = true; }; } @@ -5703,7 +5602,7 @@ This is my main server that I run at home. It handles most tasks that require bi info = "HUNSN RM02, 8GB RAM"; flakePath = "/root/.dotfiles"; isImpermanence = true; - isSecureBoot = false; + isSecureBoot = true; isCrypted = true; isBtrfs = true; isLinux = true; @@ -5722,6 +5621,25 @@ This is my main server that I run at home. It handles most tasks that require bi "hintbooth-adguardhome" "hintbooth-nginx" "summers" + "summers-ankisync" + "summers-atuin" + "summers-audio" + "summers-firefly" + "summers-forgejo" + "summers-freshrss" + "summers-homebox" + "summers-immich" + "summers-jellyfin" + "summers-kanidm" + "summers-kavita" + "summers-koillection" + "summers-matrix" + "summers-monitoring" + "summers-nextcloud" + "summers-paperless" + "summers-radicale" + "summers-storage" + "summers-transmission" "winters" ]; }; @@ -5743,10 +5661,10 @@ This is my main server that I run at home. It handles most tasks that require bi }; guests = lib.mkIf (!minimal && config.swarselsystems.withMicroVMs) ( - { } + { } // confLib.mkMicrovm "adguardhome" { } // confLib.mkMicrovm "nginx" { } - ); + ); } @@ -5911,6 +5829,16 @@ This is my main server that I run at home. It handles most tasks that require bi :PROPERTIES: :CUSTOM_ID: h:c19725c0-0523-40f2-8083-9a4f53b6c2d1 :END: + +#+begin_src bash :results output :eval never-export + echo "Currently using $(nix eval .#guestResources.hintbooth.mem 2>/dev/null) MB out of 8GB RAM" + echo "Currently using $(nix eval .#guestResources.hintbooth.vcpu 2>/dev/null) vCPUs. 4 threads are available." +#+end_src + +#+RESULTS: +: Currently using 4096 MB out of 8GB RAM +: Currently using 2 vCPUs. 2 cores are available for a total of 4 threads. + ****** Adguardhome :PROPERTIES: :CUSTOM_ID: h:f479a908-8071-4d69-97ea-c03bfd7b88bf @@ -6277,11 +6205,13 @@ This machine mainly acts as my proxy server to stand before my local machines. serverName = "twothreetunnel"; }; }; - restic = { - bucketName = "SwarselMoonside"; - paths = [ - "/persist/opt/minecraft" - ]; + restic.targets = { + SwarselMoonside = { + repository = config.repo.secrets.local.resticRepoState; + paths = [ + "/persist/opt/minecraft" + ]; + }; }; }; syncthing = { @@ -7162,6 +7092,24 @@ This machine mainly acts as my proxy server to stand before my local machines. "moonside" "winters" "summers" + "summers-ankisync" + "summers-atuin" + "summers-audio" + "summers-firefly" + "summers-forgejo" + "summers-freshrss" + "summers-homebox" + "summers-immich" + "summers-jellyfin" + "summers-kanidm" + "summers-kavita" + "summers-koillection" + "summers-matrix" + "summers-monitoring" + "summers-nextcloud" + "summers-paperless" + "summers-radicale" + "summers-storage" "belchsfactory" "eagleland" "hintbooth-adguardhome" @@ -9044,6 +8992,18 @@ For that reason, make sure that =sops-nix= is properly working before finishing isNormalUser = true; uid = 1000; autoSubUidGidRange = false; + subUidRanges = [ + { + count = 65534; + startUid = 100001; + } + ]; + subGidRanges = [ + { + count = 999; + startGid = 1001; + } + ]; description = "Leon S"; password = lib.mkIf (minimal || config.swarselsystems.isPublic) "setup"; hashedPasswordFile = lib.mkIf (!minimal && !config.swarselsystems.isPublic) config.sops.secrets.main-user-hashed-pw.path; @@ -11054,9 +11014,10 @@ Auto login for the initial session. Auto login for the initial session. #+begin_src nix-ts :tangle modules/nixos/client/uwsm.nix - { lib, config, ... }: + { lib, config, pkgs, ... }: let moduleName = "uwsm"; + cfg = config.programs.uwsm; in { options.swarselmodules.${moduleName} = lib.mkEnableOption "${moduleName} settings"; @@ -11076,6 +11037,40 @@ Auto login for the initial session. }; }; }; + + services.displayManager.sessionPackages = + let + mk_uwsm_desktop_entry = + opts: + (pkgs.writeTextFile { + name = "${opts.name}-uwsm"; + text = '' + [Desktop Entry] + Name=${opts.prettyName} (UWSM) + Comment=${opts.comment} + Exec=${lib.getExe cfg.package} start -F -- ${opts.binPath} ${lib.strings.escapeShellArgs opts.extraArgs} + Type=Application + ''; + destination = "/share/wayland-sessions/${opts.name}-uwsm.desktop"; + derivationArgs = { + passthru.providedSessions = [ "${opts.name}-uwsm" ]; + }; + }); + in + lib.mkForce (lib.mapAttrsToList + ( + name: value: + mk_uwsm_desktop_entry { + inherit name; + inherit (value) + prettyName + comment + binPath + extraArgs + ; + } + ) + cfg.waylandCompositors); }; } #+end_src @@ -11194,14 +11189,15 @@ Here we just define some aliases for rebuilding the system, and we allow some in mkIf mkOption types - ; + ; cfg = config.users.persistentIds; in - { - options = { - swarselmodules.server.ids = lib.mkEnableOption "enable persistent ids on server"; - users.persistentIds = mkOption { + { + options = { + swarselmodules.server.ids = lib.mkEnableOption "enable persistent ids on server"; + users = { + persistentIds = mkOption { default = { }; description = '' Maps a user or group name to its expected uid/gid values. If a user/group is @@ -11226,7 +11222,7 @@ Here we just define some aliases for rebuilding the system, and we allow some in ); }; - users.users = mkOption { + users = mkOption { type = types.attrsOf ( types.submodule ( { name, ... }: @@ -11235,13 +11231,13 @@ Here we just define some aliases for rebuilding the system, and we allow some in let persistentUid = cfg.${name}.uid or null; in - mkIf (persistentUid != null) (mkDefault persistentUid); + mkIf (persistentUid != null) (mkDefault persistentUid); } ) ); }; - users.groups = mkOption { + groups = mkOption { type = types.attrsOf ( types.submodule ( { name, ... }: @@ -11250,43 +11246,44 @@ Here we just define some aliases for rebuilding the system, and we allow some in let persistentGid = cfg.${name}.gid or null; in - mkIf (persistentGid != null) (mkDefault persistentGid); + mkIf (persistentGid != null) (mkDefault persistentGid); } ) ); }; }; - config = lib.mkIf config.swarselmodules.server.ids { - assertions = - concatLists - ( - flip mapAttrsToList config.users.users ( - name: user: [ - { - assertion = user.uid != null; - message = "non-persistent uid detected for '${name}', please assign one via `users.persistentIds`"; - } - { - assertion = !user.autoSubUidGidRange; - message = "non-persistent subUids/subGids detected for: ${name}"; - } - ] - ) + }; + config = lib.mkIf config.swarselmodules.server.ids { + assertions = + concatLists + ( + flip mapAttrsToList config.users.users ( + name: user: [ + { + assertion = user.uid != null; + message = "non-persistent uid detected for '${name}', please assign one via `users.persistentIds`"; + } + { + assertion = !user.autoSubUidGidRange; + message = "non-persistent subUids/subGids detected for: ${name}"; + } + ] ) - ++ flip mapAttrsToList config.users.groups ( - name: group: { - assertion = group.gid != null; - message = "non-persistent gid detected for '${name}', please assign one via `users.persistentIds`"; - } - ); - users.persistentIds = { - systemd-coredump = confLib.mkIds 998; - systemd-oom = confLib.mkIds 997; - polkituser = confLib.mkIds 973; - nscd = confLib.mkIds 972; - }; + ) + ++ flip mapAttrsToList config.users.groups ( + name: group: { + assertion = group.gid != null; + message = "non-persistent gid detected for '${name}', please assign one via `users.persistentIds`"; + } + ); + users.persistentIds = { + systemd-coredump = confLib.mkIds 998; + systemd-oom = confLib.mkIds 997; + polkituser = confLib.mkIds 973; + nscd = confLib.mkIds 972; }; - } + }; + } #+end_src **** System Packages (Server Programs) @@ -11341,6 +11338,12 @@ This is a collection of packages that are useful for server-type hosts that do n avahi = confLib.mkIds 978; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/cache/samba"; } + ]; + }; + services = { # add a user with sudo smbpasswd -a samba = { @@ -11366,7 +11369,7 @@ This is a collection of packages that are useful for server-type hosts that do n browseable = "yes"; "read only" = "no"; "guest ok" = "no"; - path = "/Vault/Eternor"; + path = "/storage"; writable = "true"; comment = "Eternor"; "valid users" = nfsUser; @@ -11539,8 +11542,15 @@ This is a collection of packages that are useful for server-type hosts that do n networking.firewall.allowedTCPPorts = [ 80 443 ]; - environment.persistence."/persist" = lib.mkIf config.swarselsystems.isImpermanence { - files = [ dhParamsPathBase ]; + environment.persistence = { + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + files = [ dhParamsPathBase ]; + }; + "/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/cache/nginx"; user = "nginx"; group = "nginx"; } + ]; + }; }; services.nginx = { @@ -12429,6 +12439,8 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin }) globals.networks.home-lan.vlans; selectVLANs = vlans: map (vlan: { VLAN = globals.networks.home-lan.vlans.${vlan}.id; }) vlans; + lan1VLANs = selectVLANs [ "home" "devices" "guests" ]; + lan2VLANs = selectVLANs [ "home" "devices" "services" ]; lan3VLANs = selectVLANs [ "home" "devices" "services" ]; lan4VLANs = lan3VLANs; lan5VLANs = selectVLANs [ "home" "devices" "guests" ]; @@ -12608,9 +12620,9 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin Bridge = "br"; ConfigureWithoutCarrier = true; }; - inherit bridgeVLANs; + bridgeVLANs = lan1VLANs; }; - # wifi + # winters "30-lan2" = { matchConfig.MACAddress = config.repo.secrets.local.networking.networks.lan2.mac; linkConfig.RequiredForOnline = "enslaved"; @@ -12618,7 +12630,7 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin Bridge = "br"; ConfigureWithoutCarrier = true; }; - inherit bridgeVLANs; + bridgeVLANs = lan2VLANs; }; # summers "30-lan3" = { @@ -12694,7 +12706,7 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin let inherit (config.swarselsystems) sopsFile; - inherit (confLib.gen { name = "kavita"; port = 8080; }) servicePort serviceName serviceUser serviceDomain serviceAddress proxyAddress4 proxyAddress6; + inherit (confLib.gen { name = "kavita"; port = 8080; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6; inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf nginxAccessRules homeServiceAddress; in { @@ -12721,6 +12733,10 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin icon = "${self}/files/topology-images/${serviceName}.png"; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + globals = { networks = { ${webProxyIf}.hosts = lib.mkIf isProxied { @@ -12742,7 +12758,7 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin user = serviceUser; settings.Port = servicePort; tokenKeyFile = config.sops.secrets.kavita-token.path; - dataDir = "/Vault/data/${serviceName}"; + dataDir = "/var/lib/${serviceName}"; }; nodes = { @@ -12763,69 +12779,76 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin :END: #+begin_src nix-ts :tangle modules/nixos/server/jellyfin.nix - { pkgs, lib, config, globals, dns, confLib, ... }: - let - inherit (confLib.gen { name = "jellyfin"; port = 8096; }) servicePort serviceName serviceUser serviceDomain serviceAddress proxyAddress4 proxyAddress6; - inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf nginxAccessRules homeServiceAddress; - in - { - options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; - config = lib.mkIf config.swarselmodules.server.${serviceName} { - - users = { - persistentIds.jellyfin = confLib.mkIds 994; - users.${serviceUser} = { - extraGroups = [ "video" "render" "users" ]; - }; - }; - # nixpkgs.config.packageOverrides = pkgs: { - # intel-vaapi-driver = pkgs.intel-vaapi-driver.override { enableHybridCodec = true; }; - # }; - - hardware.graphics = { - enable = true; - extraPackages = with pkgs; [ - intel-media-driver # LIBVA_DRIVER_NAME=iHD - # intel-vaapi-driver # LIBVA_DRIVER_NAME=i965 (older but works better for Firefox/Chromium) - libva-vdpau-driver - libvdpau-va-gl - ]; - }; - - topology.self.services.${serviceName}.info = "https://${serviceDomain}"; - - globals = { - networks = { - ${webProxyIf}.hosts = lib.mkIf isProxied { - ${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ]; - }; - ${homeProxyIf}.hosts = lib.mkIf isHome { - ${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ]; - }; - }; - services.${serviceName} = { - domain = serviceDomain; - inherit proxyAddress4 proxyAddress6 isHome serviceAddress; - homeServiceAddress = lib.mkIf isHome homeServiceAddress; - }; - }; - - services.${serviceName} = { - enable = true; - user = serviceUser; - # openFirewall = true; # this works only for the default ports - }; - - nodes = { - ${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { - "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; - }; - ${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 0; }; - ${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; }); - }; + { pkgs, lib, config, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "jellyfin"; port = 8096; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6; + inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf nginxAccessRules homeServiceAddress; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + users = { + persistentIds.jellyfin = confLib.mkIds 994; + users.${serviceUser} = { + extraGroups = [ "video" "render" "users" ]; }; - } + }; + # nixpkgs.config.packageOverrides = pkgs: { + # intel-vaapi-driver = pkgs.intel-vaapi-driver.override { enableHybridCodec = true; }; + # }; + + hardware.graphics = { + enable = true; + extraPackages = with pkgs; [ + intel-media-driver # LIBVA_DRIVER_NAME=iHD + # intel-vaapi-driver # LIBVA_DRIVER_NAME=i965 (older but works better for Firefox/Chromium) + libva-vdpau-driver + libvdpau-va-gl + ]; + }; + + topology.self.services.${serviceName}.info = "https://${serviceDomain}"; + + globals = { + networks = { + ${webProxyIf}.hosts = lib.mkIf isProxied { + ${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ]; + }; + ${homeProxyIf}.hosts = lib.mkIf isHome { + ${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ]; + }; + }; + services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6 isHome serviceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; + }; + }; + + services.${serviceName} = { + enable = true; + user = serviceUser; + # openFirewall = true; # this works only for the default ports + }; + + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; } + { directory = "/var/cache/${serviceName}"; user = serviceUser; group = serviceGroup; } + ]; + }; + + nodes = { + ${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + ${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 0; }; + ${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; }); + }; + + }; + } #+end_src **** navidrome @@ -12912,6 +12935,10 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + services.${serviceName} = { enable = true; # openFirewall = true; @@ -12919,7 +12946,7 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin LogLevel = "debug"; Address = "0.0.0.0"; Port = servicePort; - MusicFolder = "/Vault/Eternor/Music"; + MusicFolder = "/storage/Music"; PlaylistsPath = "./Playlists"; AutoImportPlaylists = false; EnableSharing = true; @@ -13056,6 +13083,12 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin # when another user connects, the service will crash and the new user will login systemd.services.spotifyd.serviceConfig.RestartSec = lib.mkForce 1; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/cache/private/spotifyd"; } + ]; + }; + services.spotifyd = { enable = true; settings = { @@ -13121,9 +13154,13 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin icon = "${self}/files/topology-images/${serviceName}.png"; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = "mpd"; group = "mpd"; }]; + }; + services.${serviceName} = { enable = true; - musicDirectory = "/media"; + musicDirectory = "/storage/Music"; user = serviceUser; group = serviceGroup; network = { @@ -13161,6 +13198,10 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin users.persistentIds.rtkit = confLib.mkIds 996; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/pipewire"; user = "pipewire"; group = "pipewire"; }]; + }; + services.pipewire = { enable = true; pulse.enable = true; @@ -13187,7 +13228,7 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin let inherit (confLib.gen { name = "postgresql"; port = 3254; }) serviceName; postgresVersion = 14; - postgresDirPrefix = if config.swarselsystems.isCloud then "/var/lib" else "/Vault/data" ; + postgresDirPrefix = "/var/lib"; in { options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; @@ -13207,9 +13248,14 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin dataDir = "${postgresDirPrefix}/${serviceName}/${builtins.toString postgresVersion}"; }; }; - environment.persistence."/persist".directories = lib.mkIf (config.swarselsystems.isImpermanence && config.swarselsystems.isCloud) [ - { directory = "/var/lib/postgresql"; user = "postgres"; group = "postgres"; mode = "0750"; } - ]; + environment.persistence = { + "/persist".directories = lib.mkIf (config.swarselsystems.isImpermanence && config.swarselsystems.isCloud) [ + { directory = "/var/lib/postgresql"; user = "postgres"; group = "postgres"; mode = "0750"; } + ]; + "/state".directories = lib.mkIf config.swarselsystems.isMicroVM [ + { directory = "/var/lib/postgresql"; user = "postgres"; group = "postgres"; mode = "0750"; } + ]; + }; }; } @@ -13238,6 +13284,12 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin oci-containers.backend = "podman"; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/lib/containers"; } + ]; + }; + networking.nftables.firewall = lib.mkIf config.networking.nftables.enable { zones.podman = { @@ -13265,7 +13317,7 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin } #+end_src -**** matrix +**** matrix (use db) :PROPERTIES: :CUSTOM_ID: h:1e68d84a-8f99-422f-89ac-78f664ac0013 :END: @@ -13274,7 +13326,7 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin { self, lib, config, pkgs, globals, dns, confLib, ... }: let inherit (config.swarselsystems) sopsFile; - inherit (confLib.gen { name = "matrix"; user = "matrix-synapse"; port = 8008; }) servicePort serviceName serviceUser serviceDomain serviceAddress proxyAddress4 proxyAddress6; + inherit (confLib.gen { name = "matrix"; user = "matrix-synapse"; port = 8008; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6; inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules; federationPort = 8448; @@ -13294,6 +13346,10 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { + swarselmodules.server = { + postgresql = true; + }; + environment.systemPackages = with pkgs; [ matrix-synapse lottieconverter @@ -13391,9 +13447,18 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/lib/matrix-synapse"; user = serviceUser; group = serviceGroup; } + { directory = "/var/lib/mautrix-whatsapp"; user = "mautrix-whatsapp"; group = "mautrix-whatsapp"; } + { directory = "/var/lib/mautrix-telegram"; user = "mautrix-telegram"; group = "mautrix-telegram"; } + { directory = "/var/lib/mautrix-signal"; user = "mautrix-signal"; group = "mautrix-signal"; } + ]; + }; + + services = { postgresql = { - enable = true; initialScript = pkgs.writeText "synapse-init.sql" '' CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse'; CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse" @@ -13420,7 +13485,7 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin matrix-synapse = { enable = true; - dataDir = "/Vault/data/matrix-synapse"; + dataDir = "/var/lib/matrix-synapse"; settings = { app_service_config_files = let @@ -13670,152 +13735,171 @@ This is the configuration to make [[#h:58c7563e-6954-42e6-a622-9d06523e8e24][Hin :END: #+begin_src nix-ts :tangle modules/nixos/server/nextcloud.nix - { pkgs, lib, config, globals, dns, confLib, ... }: - let - inherit (config.repo.secrets.local.nextcloud) adminuser; - inherit (config.swarselsystems) sopsFile; - inherit (confLib.gen { name = "nextcloud"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6; - inherit (confLib.static) isHome dnsServer webProxy homeWebProxy homeServiceAddress nginxAccessRules; + { pkgs, lib, config, globals, dns, confLib, ... }: + let + inherit (config.repo.secrets.local.nextcloud) adminuser; + inherit (config.swarselsystems) sopsFile; + inherit (confLib.gen { name = "nextcloud"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6; + inherit (confLib.static) isHome dnsServer webProxy homeWebProxy homeServiceAddress nginxAccessRules; - nextcloudVersion = "32"; - in - { - options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; - config = lib.mkIf config.swarselmodules.server.${serviceName} { + nextcloudVersion = "32"; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { - sops.secrets = { - nextcloud-admin-pw = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - kanidm-nextcloud-client = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - }; - - users.persistentIds = { - nextcloud = confLib.mkIds 990; - redis-nextcloud = confLib.mkIds 976; - }; - - globals.services.${serviceName} = { - domain = serviceDomain; - inherit proxyAddress4 proxyAddress6 isHome serviceAddress; - homeServiceAddress = lib.mkIf isHome homeServiceAddress; - }; - - services = { - ${serviceName} = { - enable = true; - settings = { - trusted_proxies = [ "0.0.0.0" ]; - overwriteprotocol = "https"; + sops.secrets = { + nextcloud-admin-pw = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + kanidm-nextcloud-client = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; }; - package = pkgs."nextcloud${nextcloudVersion}"; - hostName = serviceDomain; - home = "/Vault/data/${serviceName}"; - datadir = "/Vault/data/${serviceName}"; - https = true; - configureRedis = true; - maxUploadSize = "4G"; - extraApps = { - inherit (pkgs."nextcloud${nextcloudVersion}Packages".apps) mail calendar contacts cospend phonetrack polls tasks sociallogin; + + users.persistentIds = { + nextcloud = confLib.mkIds 990; + redis-nextcloud = confLib.mkIds 976; }; - extraAppsEnable = true; - config = { - inherit adminuser; - adminpassFile = config.sops.secrets.nextcloud-admin-pw.path; - dbtype = "sqlite"; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6 isHome serviceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; + + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; } + { directory = "/var/lib/redis-${serviceName}"; user = serviceUser; group = serviceGroup; } + ]; + }; + + services = { + ${serviceName} = { + enable = true; + settings = { + trusted_proxies = [ "0.0.0.0" ]; + overwriteprotocol = "https"; + }; + package = pkgs."nextcloud${nextcloudVersion}"; + hostName = serviceDomain; + home = "/var/lib/${serviceName}"; + datadir = "/var/lib/${serviceName}"; + https = true; + configureRedis = true; + maxUploadSize = "4G"; + extraApps = { + inherit (pkgs."nextcloud${nextcloudVersion}Packages".apps) mail calendar contacts cospend phonetrack polls tasks sociallogin; + }; + extraAppsEnable = true; + config = { + inherit adminuser; + adminpassFile = config.sops.secrets.nextcloud-admin-pw.path; + dbtype = "sqlite"; + }; + }; + }; + + nodes = { + ${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + ${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 0; }; + ${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; }); + }; + }; - }; - - nodes = { - ${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { - "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; - }; - ${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 0; }; - ${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; }); - }; - - }; - } + } #+end_src -**** immich +**** immich (use db) :PROPERTIES: :CUSTOM_ID: h:33bad8ad-b362-4bf1-8a49-b9df92329aed :END: #+begin_src nix-ts :tangle modules/nixos/server/immich.nix - { lib, pkgs, config, globals, dns, confLib, ... }: - let - inherit (confLib.gen { name = "immich"; port = 3001; }) servicePort serviceName serviceUser serviceDomain serviceAddress proxyAddress4 proxyAddress6; - inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules; - in - { - options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; - config = lib.mkIf config.swarselmodules.server.${serviceName} { + { lib, pkgs, config, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "immich"; port = 3001; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6; + inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { - users = { - persistentIds = { - immich = confLib.mkIds 989; - redis-immich = confLib.mkIds 977; + swarselmodules.server = { + postgresql = true; }; - users.${serviceUser} = { - extraGroups = [ "video" "render" "users" ]; - }; - }; - topology.self.services.${serviceName}.info = "https://${serviceDomain}"; - - # networking.firewall.allowedTCPPorts = [ servicePort ]; - globals = { - networks = { - ${webProxyIf}.hosts = lib.mkIf isProxied { - ${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ]; + users = { + persistentIds = { + immich = confLib.mkIds 989; + redis-immich = confLib.mkIds 977; }; - ${homeProxyIf}.hosts = lib.mkIf isHome { - ${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ]; + users.${serviceUser} = { + extraGroups = [ "video" "render" "users" ]; }; }; + + topology.self.services.${serviceName}.info = "https://${serviceDomain}"; + + # networking.firewall.allowedTCPPorts = [ servicePort ]; + globals = { + networks = { + ${webProxyIf}.hosts = lib.mkIf isProxied { + ${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ]; + }; + ${homeProxyIf}.hosts = lib.mkIf isHome { + ${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ]; + }; + }; + services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6 isHome serviceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; + }; + }; + + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; } + { directory = "/var/cache/${serviceName}"; user = serviceUser; group = serviceGroup; } + { directory = "/var/lib/redis-${serviceName}"; user = "redis-${serviceUser}"; group = "redis-${serviceGroup}"; } + ]; + }; + services.${serviceName} = { - domain = serviceDomain; - inherit proxyAddress4 proxyAddress6 isHome serviceAddress; - homeServiceAddress = lib.mkIf isHome homeServiceAddress; - }; - }; - - services.${serviceName} = { - enable = true; - package = pkgs.immich; - host = "0.0.0.0"; - port = servicePort; - # openFirewall = true; - mediaLocation = "/Vault/Eternor/Immich"; # dataDir - environment = { - IMMICH_MACHINE_LEARNING_URL = lib.mkForce "http://localhost:3003"; - }; - }; - - nodes = - let - extraConfigLoc = '' - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_redirect off; - - proxy_read_timeout 600s; - proxy_send_timeout 600s; - send_timeout 600s; - ''; - in - { - ${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { - "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + enable = true; + package = pkgs.immich; + host = "0.0.0.0"; + port = servicePort; + # openFirewall = true; + mediaLocation = "/storage/Pictures/${serviceName}"; # dataDir + environment = { + IMMICH_MACHINE_LEARNING_URL = lib.mkForce "http://localhost:3003"; }; - ${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; }; - ${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; }); }; - }; - } + nodes = + let + extraConfigLoc = '' + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_redirect off; + + proxy_read_timeout 600s; + proxy_send_timeout 600s; + send_timeout 600s; + ''; + in + { + ${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + ${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; }; + ${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; }); + }; + + }; + } #+end_src **** paperless (tika, gotenberg) @@ -13874,11 +13958,21 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; } + { directory = "/var/lib/redis-${serviceName}"; user = "redis-${serviceUser}"; group = "redis-${serviceGroup}"; } + { directory = "/var/lib/private/tika"; } + { directory = "/var/cache/${serviceName}"; user = serviceUser; group = serviceGroup; } + { directory = "/var/cache/private/tika"; } + ]; + }; + services = { ${serviceName} = { enable = true; - mediaDir = "/Vault/Eternor/Paperless"; - dataDir = "/Vault/data/${serviceName}"; + mediaDir = "/storage/Documents/${serviceName}"; + dataDir = "/var/lib/${serviceName}"; user = serviceUser; port = servicePort; passwordFile = config.sops.secrets.paperless-admin-pw.path; @@ -13971,8 +14065,8 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= #+begin_src nix-ts :tangle modules/nixos/server/transmission.nix { self, pkgs, lib, config, confLib, ... }: let - inherit (confLib.gen { name = "transmission"; }) serviceName serviceDomain; - inherit (confLib.static) isHome; + inherit (confLib.gen { name = "transmission"; port = 9091; }) serviceName servicePort serviceDomain; + inherit (confLib.static) isHome homeServiceAddress homeWebProxy nginxAccessRules; lidarrUser = "lidarr"; lidarrGroup = lidarrUser; @@ -14067,6 +14161,16 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= inherit isHome; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/lib/radarr"; user = radarrUser; group = radarrGroup; } + { directory = "/var/lib/readarr"; user = readarrUser; group = readarrGroup; } + { directory = "/var/lib/sonarr"; user = sonarrUser; group = sonarrGroup; } + { directory = "/var/lib/lidarr"; user = lidarrUser; group = lidarrGroup; } + { directory = "/var/lib/private/prowlarr"; user = prowlarrUser; group = prowlarrGroup; } + ]; + }; + services = { radarr = { enable = true; @@ -14074,7 +14178,7 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= group = radarrGroup; settings.server.port = radarrPort; openFirewall = true; - dataDir = "/Vault/data/radarr"; + dataDir = "/var/lib/radarr"; }; readarr = { enable = true; @@ -14082,7 +14186,7 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= group = readarrGroup; settings.server.port = readarrPort; openFirewall = true; - dataDir = "/Vault/data/readarr"; + dataDir = "/var/lib/readarr"; }; sonarr = { enable = true; @@ -14090,7 +14194,7 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= group = sonarrGroup; settings.server.port = sonarrPort; openFirewall = true; - dataDir = "/Vault/data/sonarr"; + dataDir = "/var/lib/sonarr"; }; lidarr = { enable = true; @@ -14098,53 +14202,88 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= group = lidarrGroup; settings.server.port = lidarrPort; openFirewall = true; - dataDir = "/Vault/data/lidarr"; + dataDir = "/var/lib/lidarr"; }; prowlarr = { enable = true; settings.server.port = prowlarrPort; openFirewall = true; }; + }; - nginx = { + nodes = { + ${homeWebProxy}.services.nginx = { + upstreams = { + transmission = { + servers = { + "${homeServiceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + radarr = { + servers = { + "${homeServiceAddress}:${builtins.toString radarrPort}" = { }; + }; + }; + readarr = { + servers = { + "${homeServiceAddress}:${builtins.toString readarrPort}" = { }; + }; + }; + sonarr = { + servers = { + "${homeServiceAddress}:${builtins.toString sonarrPort}" = { }; + }; + }; + lidarr = { + servers = { + "${homeServiceAddress}:${builtins.toString lidarrPort}" = { }; + }; + }; + prowlarr = { + servers = { + "${homeServiceAddress}:${builtins.toString prowlarrPort}" = { }; + }; + }; + }; virtualHosts = { "${serviceDomain}" = { enableACME = false; forceSSL = false; acmeRoot = null; + extraConfig = nginxAccessRules; locations = { "/" = { - proxyPass = "http://localhost:9091"; + proxyPass = "http://transmission"; extraConfig = '' client_max_body_size 0; ''; }; "/radarr" = { - proxyPass = "http://localhost:${builtins.toString radarrPort}"; + proxyPass = "http://radarr"; extraConfig = '' client_max_body_size 0; ''; }; "/readarr" = { - proxyPass = "http://localhost:${builtins.toString readarrPort}"; + proxyPass = "http://readarr"; extraConfig = '' client_max_body_size 0; ''; }; "/sonarr" = { - proxyPass = "http://localhost:${builtins.toString sonarrPort}"; + proxyPass = "http://sonarr"; extraConfig = '' client_max_body_size 0; ''; }; "/lidarr" = { - proxyPass = "http://localhost:${builtins.toString lidarrPort}"; + proxyPass = "http://lidarr"; extraConfig = '' client_max_body_size 0; ''; }; "/prowlarr" = { - proxyPass = "http://localhost:${builtins.toString prowlarrPort}"; + proxyPass = "http://prowlarr"; extraConfig = '' client_max_body_size 0; ''; @@ -14242,12 +14381,16 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + services.${serviceName} = rec { enable = true; user = serviceUser; group = serviceGroup; - dataDir = lib.mkDefault "/Vault/data/${serviceName}"; - configDir = "${cfg.dataDir}/.config/${serviceName}"; + dataDir = if config.swarselsystems.isMicroVM then "/storage/Documents/syncthing" else (lib.mkDefault "/var/lib/${serviceName}"); + configDir = if config.swarselsystems.isMicroVM then "/var/lib/syncthing/.config/syncthing" else "${cfg.dataDir}/.config/${serviceName}"; guiAddress = "0.0.0.0:${builtins.toString servicePort}"; openDefaultPorts = lib.mkIf (!isProxied) true; # opens ports TCP/UDP 22000 and UDP 21027 for discovery relay.enable = false; @@ -14320,68 +14463,92 @@ Note: you still need to run =restic- init= once on the host to get the buc { lib, pkgs, config, ... }: let inherit (config.swarselsystems) sopsFile; + + targets = config.swarselsystems.server.restic.targets; in { options.swarselmodules.server.restic = lib.mkEnableOption "enable restic backups on server"; options.swarselsystems.server.restic = { - bucketName = lib.mkOption { - type = lib.types.str; - }; - paths = lib.mkOption { - type = lib.types.listOf lib.types.str; - }; - withPostgres = lib.mkOption { - type = lib.types.bool; - default = false; + targets = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: { + options = { + bucketName = lib.mkOption { + type = lib.types.str; + default = name; + }; + repository = lib.mkOption { + type = lib.types.str; + }; + paths = lib.mkOption { + type = lib.types.listOf lib.types.str; + }; + withPostgres = lib.mkOption { + type = lib.types.bool; + default = false; + }; + }; + })); + default = { }; }; }; + config = lib.mkIf config.swarselmodules.server.restic { sops = { - secrets = { - resticpw = { inherit sopsFile; }; - resticaccesskey = { inherit sopsFile; }; - resticsecretaccesskey = { inherit sopsFile; }; - }; - templates = { - "restic-env".content = '' - AWS_ACCESS_KEY_ID=${config.sops.placeholder.resticaccesskey} - AWS_SECRET_ACCESS_KEY=${config.sops.placeholder.resticsecretaccesskey} - ''; - }; + secrets = + lib.mkMerge (lib.mapAttrsToList + (name: _: { + "resticpw-${name}" = { inherit sopsFile; }; + "resticaccesskey-${name}" = { inherit sopsFile; }; + "resticsecretaccesskey-${name}" = { inherit sopsFile; }; + }) + targets); + + templates = + lib.mkMerge (lib.mapAttrsToList + (name: _: { + "restic-env-${name}".content = '' + AWS_ACCESS_KEY_ID=${config.sops.placeholder."resticaccesskey-${name}"} + AWS_SECRET_ACCESS_KEY=${config.sops.placeholder."resticsecretaccesskey-${name}"} + ''; + }) + targets); }; - services.restic = - let - inherit (config.repo.secrets.local) resticRepo; - in - { - backups = { - "${config.swarselsystems.server.restic.bucketName}" = { - environmentFile = config.sops.templates."restic-env".path; - passwordFile = config.sops.secrets.resticpw.path; - inherit (config.swarselsystems.server.restic) paths; + services.restic.backups = + lib.mapAttrs' + (name: target: + lib.nameValuePair target.bucketName { + environmentFile = + config.sops.templates."restic-env-${name}".path; + + passwordFile = + config.sops.secrets."resticpw-${name}".path; + + inherit (target) paths repository; + pruneOpts = [ "--keep-daily 3" "--keep-weekly 2" "--keep-monthly 3" "--keep-yearly 100" ]; + backupPrepareCommand = '' ${pkgs.restic}/bin/restic prune ''; - repository = "${resticRepo}"; + initialize = true; + timerConfig = { OnCalendar = "03:00"; }; - }; - - }; - }; - + } + ) + targets; }; } + #+end_src **** monitoring (Grafana, Prometheus) @@ -14441,8 +14608,10 @@ This section exposes several metrics that I use to check the health of my server node-exporter = confLib.mkIds 987; grafana = confLib.mkIds 974; }; + groups.nextcloud-exporter = {}; users = { nextcloud-exporter = { + group = "nextcloud-exporter"; extraGroups = [ "nextcloud" ]; }; @@ -14472,10 +14641,17 @@ This section exposes several metrics that I use to check the health of my server }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; } + { directory = "/var/lib/prometheus2"; user = prometheusUser; group = prometheusGroup; } + ]; + }; + services = { ${serviceName} = { enable = true; - dataDir = "/Vault/data/${serviceName}"; + dataDir = "/var/lib/${serviceName}"; provision = { enable = true; datasources.settings = { @@ -14687,7 +14863,7 @@ This is a WIP Jenkins instance. It is used to automatically build a new system w #+begin_src nix-ts :tangle modules/nixos/server/jenkins.nix { pkgs, lib, config, globals, dns, confLib, ... }: let - inherit (confLib.gen { name = "jenkins"; port = 8088; }) servicePort serviceName serviceDomain serviceAddress proxyAddress4 proxyAddress6; + inherit (confLib.gen { name = "jenkins"; port = 8088; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6; inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules; in { @@ -14710,13 +14886,17 @@ This is a WIP Jenkins instance. It is used to automatically build a new system w }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + services.jenkins = { enable = true; withCLI = true; port = servicePort; packages = [ pkgs.stdenv pkgs.git pkgs.jdk17 config.programs.ssh.package pkgs.nix ]; listenAddress = "0.0.0.0"; - home = "/Vault/apps/${serviceName}"; + home = "/var/lib/${serviceName}"; }; nodes = { @@ -14837,6 +15017,10 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + services.${serviceName} = let inherit (config.repo.secrets.local.freshrss) defaultUser; @@ -14847,7 +15031,7 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with virtualHost = serviceDomain; baseUrl = "https://${serviceDomain}"; authType = "form"; - dataDir = "/Vault/data/tt-rss"; + dataDir = "/var/lib/freshrss"; passwordFile = config.sops.secrets.freshrss-pw.path; }; @@ -14952,9 +15136,13 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + services.${serviceName} = { enable = true; - stateDir = "/Vault/data/${serviceName}"; + stateDir = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; lfs.enable = lib.mkDefault true; @@ -15107,6 +15295,10 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/private/${serviceName}"; }]; + }; + services.anki-sync-server = { enable = true; port = servicePort; @@ -15233,12 +15425,19 @@ kanidm person credential create-reset-token }; }; - environment.persistence."/persist" = lib.mkIf config.swarselsystems.isImpermanence { - files = [ - certPathBase - keyPathBase - ]; + environment.persistence = { + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + files = [ + certPathBase + keyPathBase + ]; + }; + + "/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; }; + systemd.services."generateSSLCert-${serviceName}" = let daysValid = 3650; @@ -15718,6 +15917,10 @@ kanidm person credential create-reset-token }; }; + users = { + persistentIds.oauth2-proxy = confLib.mkIds 966; + }; + # needed for homeWebProxy networking.firewall.allowedTCPPorts = [ servicePort ]; @@ -15856,12 +16059,16 @@ kanidm person credential create-reset-token homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + services = { ${serviceName} = { enable = true; user = serviceUser; group = if cfg.enableNginx then nginxGroup else serviceGroup; - dataDir = "/Vault/data/${serviceName}"; + dataDir = "/var/lib/${serviceName}"; settings = { TZ = config.repo.secrets.common.location.timezone; APP_URL = "https://${serviceDomain}"; @@ -15943,156 +16150,160 @@ kanidm person credential create-reset-token } #+end_src -**** Koillection +**** Koillection (use db) :PROPERTIES: :CUSTOM_ID: h:09c0fed3-b9c6-487f-a5f6-49be039e5fa2 :END: #+begin_src nix-ts :tangle modules/nixos/server/koillection.nix -{ self, lib, config, globals, dns, confLib, ... }: -let - inherit (confLib.gen { name = "koillection"; port = 2282; dir = "/Vault/data/koillection"; }) servicePort serviceName serviceUser serviceDir serviceDomain serviceAddress proxyAddress4 proxyAddress6; - inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules; - serviceDB = "koillection"; + { self, lib, config, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "koillection"; port = 2282; dir = "/var/lib/koillection"; }) servicePort serviceName serviceUser serviceDir serviceDomain serviceAddress proxyAddress4 proxyAddress6; + inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules; + serviceDB = "koillection"; - postgresUser = config.systemd.services.postgresql.serviceConfig.User; # postgres - postgresPort = config.services.postgresql.settings.port; # 5432 - containerRev = "sha256:96693e41a6eb2aae44f96033a090378270f024ddf4e6095edf8d57674f21095d"; + postgresUser = config.systemd.services.postgresql.serviceConfig.User; # postgres + postgresPort = config.services.postgresql.settings.port; # 5432 + containerRev = "sha256:96693e41a6eb2aae44f96033a090378270f024ddf4e6095edf8d57674f21095d"; - inherit (config.swarselsystems) sopsFile; -in -{ - options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; - config = lib.mkIf config.swarselmodules.server.${serviceName} { + inherit (config.swarselsystems) sopsFile; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { - swarselmodules.server = { - podman = true; - postgresql = true; - }; + swarselmodules.server = { + podman = true; + postgresql = true; + }; - sops.secrets = { - koillection-db-password = { inherit sopsFile; owner = postgresUser; group = postgresUser; mode = "0440"; }; - koillection-env-file = { inherit sopsFile; }; - }; + sops.secrets = { + koillection-db-password = { inherit sopsFile; owner = postgresUser; group = postgresUser; mode = "0440"; }; + koillection-env-file = { inherit sopsFile; }; + }; - topology.self.services.${serviceName} = { - name = lib.swarselsystems.toCapitalized serviceName; - info = "https://${serviceDomain}"; - icon = "${self}/files/topology-images/${serviceName}.png"; - }; + topology.self.services.${serviceName} = { + name = lib.swarselsystems.toCapitalized serviceName; + info = "https://${serviceDomain}"; + icon = "${self}/files/topology-images/${serviceName}.png"; + }; - globals = { - networks = { - ${webProxyIf}.hosts = lib.mkIf isProxied { - ${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort postgresPort ]; + globals = { + networks = { + ${webProxyIf}.hosts = lib.mkIf isProxied { + ${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort postgresPort ]; + }; + ${homeProxyIf}.hosts = lib.mkIf isHome { + ${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort postgresPort ]; + }; }; - ${homeProxyIf}.hosts = lib.mkIf isHome { - ${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort postgresPort ]; + services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6 isHome serviceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; }; - services.${serviceName} = { - domain = serviceDomain; - inherit proxyAddress4 proxyAddress6 isHome serviceAddress; - homeServiceAddress = lib.mkIf isHome homeServiceAddress; + + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; }]; }; - }; - virtualisation.oci-containers.containers = { - koillection = { - image = "koillection/koillection@${containerRev}"; + virtualisation.oci-containers.containers = { + koillection = { + image = "koillection/koillection@${containerRev}"; - ports = [ - "${toString servicePort}:80" - ]; + ports = [ + "${toString servicePort}:80" + ]; - volumes = [ - "${serviceDir}/uploads:/uploads" - ]; + volumes = [ + "${serviceDir}/uploads:/uploads" + ]; - environment = { - APP_DEBUG = "0"; - APP_ENV = "prod"; - HTTPS_ENABLED = "1"; - UPLOAD_MAX_FILESIZE = "512M"; - PHP_MEMORY_LIMIT = "512M"; - PHP_TZ = config.repo.secrets.common.location.timezone; + environment = { + APP_DEBUG = "0"; + APP_ENV = "prod"; + HTTPS_ENABLED = "1"; + UPLOAD_MAX_FILESIZE = "512M"; + PHP_MEMORY_LIMIT = "512M"; + PHP_TZ = config.repo.secrets.common.location.timezone; - CORS_ALLOW_ORIGIN = "https?://(localhost|swag\\.swarsel\\.win)(:[0-9]+)?$"; + CORS_ALLOW_ORIGIN = "https?://(localhost|swag\\.swarsel\\.win)(:[0-9]+)?$"; - DB_DRIVER = "pdo_pgsql"; - DB_NAME = serviceDB; - DB_HOST = "host.docker.internal"; - DB_USER = serviceUser; - # DB_PASSWORD set in koillection-env-file - DB_PORT = "${toString postgresPort}"; - DB_VERSION = "16"; + DB_DRIVER = "pdo_pgsql"; + DB_NAME = serviceDB; + DB_HOST = "host.docker.internal"; + DB_USER = serviceUser; + # DB_PASSWORD set in koillection-env-file + DB_PORT = "${toString postgresPort}"; + DB_VERSION = "16"; + }; + + environmentFiles = [ + config.sops.secrets.koillection-env-file.path + ]; + + extraOptions = [ + "--add-host=host.docker.internal:host-gateway" # podman + ]; }; - - environmentFiles = [ - config.sops.secrets.koillection-env-file.path - ]; - - extraOptions = [ - "--add-host=host.docker.internal:host-gateway" # podman - ]; }; - }; - # networking.firewall.allowedTCPPorts = [ servicePort postgresPort ]; + # networking.firewall.allowedTCPPorts = [ servicePort postgresPort ]; - systemd.services.postgresql.postStart = - let - passwordPath = config.sops.secrets.koillection-db-password.path; - in - '' - ${config.services.postgresql.package}/bin/psql -tA <<'EOF' - DO $$ - DECLARE password TEXT; - BEGIN - password := trim(both from replace(pg_read_file('${passwordPath}'), E'\n', ''')); - EXECUTE format('ALTER ROLE ${serviceDB} WITH PASSWORD '''%s''';', password); - END $$; - EOF - ''; - services = { - postgresql = { - enable = true; - enableTCPIP = true; - ensureDatabases = [ serviceDB ]; - ensureUsers = [ - { - name = serviceDB; - ensureDBOwnership = true; - } - ]; - authentication = '' - host ${serviceDB} ${serviceDB} 10.88.0.0/16 scram-sha-256 + systemd.services.postgresql.postStart = + let + passwordPath = config.sops.secrets.koillection-db-password.path; + in + '' + ${config.services.postgresql.package}/bin/psql -tA <<'EOF' + DO $$ + DECLARE password TEXT; + BEGIN + password := trim(both from replace(pg_read_file('${passwordPath}'), E'\n', ''')); + EXECUTE format('ALTER ROLE ${serviceDB} WITH PASSWORD '''%s''';', password); + END $$; + EOF ''; - }; - }; - - nodes = - let - extraConfigLoc = '' - proxy_buffer_size 128k; - proxy_buffers 4 256k; - proxy_busy_buffers_size 256k; - ''; - in - { - ${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { - "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + services = { + postgresql = { + enable = true; + enableTCPIP = true; + ensureDatabases = [ serviceDB ]; + ensureUsers = [ + { + name = serviceDB; + ensureDBOwnership = true; + } + ]; + authentication = '' + host ${serviceDB} ${serviceDB} 10.88.0.0/16 scram-sha-256 + ''; }; - ${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; }; - ${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; }); }; + nodes = + let + extraConfigLoc = '' + proxy_buffer_size 128k; + proxy_buffers 4 256k; + proxy_busy_buffers_size 256k; + ''; + in + { + ${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + ${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; }; + ${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; }); + }; - }; -} + + }; + } #+end_src -**** Atuin +**** Atuin (use db) :PROPERTIES: :CUSTOM_ID: h:27eac8b9-c202-4e45-9b80-42592f1e41c8 :END: @@ -16103,47 +16314,51 @@ in inherit (confLib.gen { name = "atuin"; port = 8888; }) servicePort serviceName serviceDomain serviceAddress proxyAddress4 proxyAddress6; inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules; in - { - options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; - config = lib.mkIf config.swarselmodules.server.${serviceName} { + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { - topology.self.services.${serviceName}.info = "https://${serviceDomain}"; + swarselmodules.server = { + postgresql = true; + }; - globals = { - networks = { - ${webProxyIf}.hosts = lib.mkIf isProxied { - ${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ]; + topology.self.services.${serviceName}.info = "https://${serviceDomain}"; + + globals = { + networks = { + ${webProxyIf}.hosts = lib.mkIf isProxied { + ${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ]; + }; + ${homeProxyIf}.hosts = lib.mkIf isHome { + ${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ]; + }; }; - ${homeProxyIf}.hosts = lib.mkIf isHome { - ${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ]; + services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6 isHome serviceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; }; + services.${serviceName} = { - domain = serviceDomain; - inherit proxyAddress4 proxyAddress6 isHome serviceAddress; - homeServiceAddress = lib.mkIf isHome homeServiceAddress; + enable = true; + host = "0.0.0.0"; + port = servicePort; + # openFirewall = true; + openRegistration = false; }; - }; - services.${serviceName} = { - enable = true; - host = "0.0.0.0"; - port = servicePort; - # openFirewall = true; - openRegistration = false; - }; - - nodes = { - ${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { - "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + nodes = { + ${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + ${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 0; }; + ${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; }); }; - ${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 0; }; - ${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; }); + }; - }; - - } + } #+end_src **** Radicale @@ -16189,6 +16404,10 @@ in topology.self.services.${serviceName}.info = "https://${serviceDomain}"; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + globals = { networks = { ${webProxyIf}.hosts = lib.mkIf isProxied { @@ -16221,7 +16440,7 @@ in htpasswd_encryption = "autodetect"; }; storage = { - filesystem_folder = "/Vault/data/radicale/collections"; + filesystem_folder = "/var/lib/radicale/collections"; }; }; rights = { @@ -16792,7 +17011,7 @@ in hostName = serviceDomain; user = serviceUser; group = serviceGroup; - dataDir = "/Vault/data/snipeit"; + dataDir = "/var/lib/snipeit"; database = { user = serviceUser; port = mysqlPort; @@ -16813,7 +17032,7 @@ in }; } #+end_src -**** Homebox +**** Homebox (use db) :PROPERTIES: :CUSTOM_ID: h:5b4feb1b-e7a3-43f1-9930-8d00012742ad :END: @@ -16821,7 +17040,7 @@ in #+begin_src nix-ts :tangle modules/nixos/server/homebox.nix { self, lib, pkgs, config, globals, dns, confLib, ... }: let - inherit (confLib.gen { name = "homebox"; port = 7745; }) servicePort serviceName serviceDomain serviceAddress proxyAddress4 proxyAddress6; + inherit (confLib.gen { name = "homebox"; port = 7745; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6; inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules; in { @@ -16834,6 +17053,10 @@ in icon = "${self}/files/topology-images/${serviceName}.png"; }; + swarselmodules.server = { + postgresql = true; + }; + users.persistentIds = { homebox = confLib.mkIds 981; }; @@ -16854,14 +17077,14 @@ in }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + systemd.services.homebox = { environment = { TMPDIR = "/var/lib/homebox/.tmp"; - }; - serviceConfig = { - # ReadWritePaths = "/var/lib/homebox"; - RuntimeDirectory = "homebox"; - BindPaths="/run/homebox:/var/lib/homebox/.tmp"; + HOME = "/var/lib/homebox"; }; }; @@ -16903,7 +17126,7 @@ in kanidmDomain = globals.services.kanidm.domain; inherit (config.swarselsystems) mainUser; - inherit (config.repo.secrets.local) persons; + mailAddress = config.repo.secrets.common.mail.address4; in { options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; @@ -16927,7 +17150,7 @@ in authorizations = [ { user = mainUser; - principal = builtins.head persons.${mainUser}.mailAddresses; + principal = mailAddress; inherit (config.services.opkssh.providers.kanidm) issuer; } ]; @@ -17702,7 +17925,7 @@ When changing the hashed passwords, =dovecot= needs to be restarted manually, it { self, lib, config, globals, dns, confLib, ... }: let inherit (config.swarselsystems) sopsFile; - inherit (confLib.gen { name = "mailserver"; dir = "/var/lib/dovecot"; user = "virtualMail"; group = "virtualMail"; port = 443; }) serviceName serviceDir servicePort serviceUser serviceGroup serviceAddress serviceDomain proxyAddress4 proxyAddress6; + inherit (confLib.gen { name = "mailserver"; dir = "/var/lib/dovecot"; user = "virtualMail"; group = "virtualMail"; port = 80; }) serviceName serviceDir servicePort serviceUser serviceGroup serviceAddress serviceDomain proxyAddress4 proxyAddress6; inherit (confLib.static) isHome webProxy homeWebProxy dnsServer homeServiceAddress nginxAccessRules; inherit (config.repo.secrets.local.mailserver) user1 alias1_1 alias1_2 alias1_3 alias1_4 user2 alias2_1 alias2_2 alias2_3 user3; baseDomain = globals.domains.main; @@ -19643,8 +19866,6 @@ Some standard options that should be set for every microvm guest. We set the def # NOTE: this is needed, we dont import sevrer network module for microvms globals.hosts.${config.node.name}.isHome = true; - fileSystems."/persist".neededForBoot = lib.mkForce true; - systemd.network.networks."10-vlan-services" = { dhcpV6Config = { WithoutRA = "solicit"; @@ -27167,210 +27388,220 @@ In short, the options defined here are passed to the modules systems using =_mod :CUSTOM_ID: h:a33322d5-014a-4072-a4a5-91bc71c343b8 :END: #+begin_src nix-ts :noweb yes :tangle modules/shared/config-lib.nix - { self, config, lib, globals, inputs, outputs, minimal, nixosConfig ? null, ... }: - let - domainDefault = service: config.repo.secrets.common.services.domains.${service}; - proxyDefault = config.swarselsystems.proxyHost; + { self, config, lib, globals, inputs, outputs, minimal, nixosConfig ? null, ... }: + let + domainDefault = service: config.repo.secrets.common.services.domains.${service}; + proxyDefault = config.swarselsystems.proxyHost; - addressDefault = - if - config.swarselsystems.proxyHost != config.node.name - then + addressDefault = if - config.swarselsystems.server.wireguard.interfaces.wgProxy.isClient + config.swarselsystems.proxyHost != config.node.name then - globals.networks."${config.swarselsystems.server.wireguard.interfaces.wgProxy.serverNetConfigPrefix}-wgProxy".hosts.${config.node.name}.ipv4 - else - globals.networks.${config.swarselsystems.server.netConfigName}.hosts.${config.node.name}.ipv4 - else - "localhost"; - in - { - _module.args = { - confLib = rec { - getConfig = if nixosConfig == null then config else nixosConfig; - - gen = { name ? "n/a", user ? name, group ? name, dir ? null, port ? null, domain ? (domainDefault name), address ? addressDefault, proxy ? proxyDefault }: rec { - servicePort = port; - serviceName = name; - specificServiceName = "${name}-${config.node.name}"; - serviceUser = user; - serviceGroup = group; - serviceDomain = domain; - baseDomain = lib.swarselsystems.getBaseDomain domain; - subDomain = lib.swarselsystems.getSubDomain domain; - serviceDir = dir; - serviceAddress = address; - serviceProxy = proxy; - proxyAddress4 = globals.hosts.${proxy}.wanAddress4 or null; - proxyAddress6 = globals.hosts.${proxy}.wanAddress6 or null; - }; - - static = rec { - inherit (globals.hosts.${config.node.name}) isHome; - inherit (globals.general) homeProxy webProxy dnsServer homeDnsServer homeWebProxy idmServer oauthServer; - webProxyIf = "${webProxy}-wgProxy"; - homeProxyIf = "home-wgHome"; - isProxied = config.node.name != webProxy; - nginxAccessRules = '' - allow ${globals.networks.home-lan.vlans.home.cidrv4}; - allow ${globals.networks.home-lan.vlans.home.cidrv6}; - allow ${globals.networks.home-lan.vlans.services.hosts.${homeProxy}.ipv4}; - allow ${globals.networks.home-lan.vlans.services.hosts.${homeProxy}.ipv6}; - deny all; - ''; - homeServiceAddress = lib.optionalString (config.swarselsystems.server.wireguard.interfaces ? wgHome) globals.networks."${config.swarselsystems.server.wireguard.interfaces.wgHome.serverNetConfigPrefix}-wgHome".hosts.${config.node.name}.ipv4; - }; - - mkIds = id: { - uid = id; - gid = id; - }; - - mkDeviceMac = id: - let - mod = n: d: n - (n / d) * d; - toHexByte = n: - let - hex = "0123456789abcdef"; - hi = n / 16; - lo = mod n 16; - in - builtins.substring hi 1 hex - + builtins.substring lo 1 hex; - - max = 16777215; # 256^3 - 1 - - b1 = id / (256 * 256); - r1 = mod id (256 * 256); - b2 = r1 / 256; - b3 = mod r1 256; - in if - (id <= max) + config.swarselsystems.server.wireguard.interfaces.wgProxy.isClient then - (builtins.concatStringsSep ":" - (map toHexByte [ b1 b2 b3 ])) + globals.networks."${config.swarselsystems.server.wireguard.interfaces.wgProxy.serverNetConfigPrefix}-wgProxy".hosts.${config.node.name}.ipv4 else - (throw "Device MAC ID too large (max is 16777215)"); + globals.networks.${config.swarselsystems.server.netConfigName}.hosts.${config.node.name}.ipv4 + else + "localhost"; + in + { + _module.args = { + confLib = rec { + getConfig = if nixosConfig == null then config else nixosConfig; - mkMicrovm = - if config.swarselsystems.withMicroVMs then - (guestName: - { enableStorage ? false - , withZfs ? false - , ... - }: - { - ${guestName} = { - backend = "microvm"; - autostart = true; - zfs = lib.mkIf withZfs { - # stateful config that should be backed up - "/state" = { - pool = "Vault"; - dataset = "guests/${guestName}/state"; - }; - # data that should be backed up - "/storage" = lib.mkIf enableStorage { - pool = "Vault"; - dataset = "guests/${guestName}/storage"; - }; - # other stuff that should only reside on disk, not backed up - "/persist" = { - pool = "Vault"; - dataset = "guests/${guestName}/persist"; - }; - }; - modules = [ - (config.node.configDir + /guests/${guestName}/default.nix) - { - node.secretsDir = config.node.configDir + /secrets/${guestName}; - node.configDir = config.node.configDir + /guests/${guestName}; - networking.nftables.firewall = { - zones.untrusted.interfaces = lib.mkIf - ( - lib.length config.guests.${guestName}.networking.links == 1 - ) - config.guests.${guestName}.networking.links; - }; - } - "${self}/modules/nixos/optional/microvm-guest.nix" - "${self}/modules/nixos/optional/systemd-networkd-base.nix" - ]; - microvm = { - system = config.node.arch; - baseMac = config.repo.secrets.local.networking.networks.lan.mac; - interfaces.vlan-services = { - mac = lib.mkForce "02:${lib.substring 3 5 config.guests.${guestName}.microvm.baseMac}:${mkDeviceMac globals.networks.home-lan.vlans.services.hosts."${config.node.name}-${guestName}".id}"; - - }; - }; - extraSpecialArgs = { - inherit (inputs.self) nodes; - inherit (inputs.self.pkgs.${config.node.arch}) lib; - inherit inputs outputs minimal; - inherit (inputs) self; - withHomeManager = false; - microVMParent = config.node.name; - globals = inputs.self.globals.${config.node.arch}; - }; - }; - }) else - (_: { - _ = { }; - }); - - genNginx = - { serviceAddress - , serviceName - , serviceDomain - , servicePort - , protocol ? "http" - , maxBody ? (-1) - , maxBodyUnit ? "" - , noSslVerify ? false - , proxyWebsockets ? false - , oauth2 ? false - , oauth2Groups ? [ ] - , extraConfig ? "" - , extraConfigLoc ? "" - }: { - upstreams = { - ${serviceName} = { - servers = { - "${serviceAddress}:${builtins.toString servicePort}" = { }; - }; - }; - }; - virtualHosts = { - "${serviceDomain}" = { - useACMEHost = globals.domains.main; - forceSSL = true; - acmeRoot = null; - oauth2 = { - enable = lib.mkIf oauth2 true; - allowedGroups = lib.mkIf (oauth2Groups != [ ]) oauth2Groups; - }; - locations = { - "/" = { - proxyPass = "${protocol}://${serviceName}"; - proxyWebsockets = lib.mkIf proxyWebsockets true; - extraConfig = lib.optionalString (maxBody != (-1)) '' - client_max_body_size ${builtins.toString maxBody}${maxBodyUnit}; - '' + extraConfigLoc; - }; - }; - extraConfig = lib.optionalString noSslVerify '' - proxy_ssl_verify off; - '' + extraConfig; - }; - }; + gen = { name ? "n/a", user ? name, group ? user, dir ? null, port ? null, domain ? (domainDefault name), address ? addressDefault, proxy ? proxyDefault }: rec { + servicePort = port; + serviceName = name; + specificServiceName = "${name}-${config.node.name}"; + serviceUser = user; + serviceGroup = group; + serviceDomain = domain; + baseDomain = lib.swarselsystems.getBaseDomain domain; + subDomain = lib.swarselsystems.getSubDomain domain; + serviceDir = dir; + serviceAddress = address; + serviceProxy = proxy; + proxyAddress4 = globals.hosts.${proxy}.wanAddress4 or null; + proxyAddress6 = globals.hosts.${proxy}.wanAddress6 or null; }; + static = rec { + inherit (globals.hosts.${config.node.name}) isHome; + inherit (globals.general) homeProxy webProxy dnsServer homeDnsServer homeWebProxy idmServer oauthServer; + webProxyIf = "${webProxy}-wgProxy"; + homeProxyIf = "home-wgHome"; + isProxied = config.node.name != webProxy; + nginxAccessRules = '' + allow ${globals.networks.home-lan.vlans.home.cidrv4}; + allow ${globals.networks.home-lan.vlans.home.cidrv6}; + allow ${globals.networks.home-lan.vlans.services.hosts.${homeProxy}.ipv4}; + allow ${globals.networks.home-lan.vlans.services.hosts.${homeProxy}.ipv6}; + deny all; + ''; + homeServiceAddress = lib.optionalString (config.swarselsystems.server.wireguard.interfaces ? wgHome) globals.networks."${config.swarselsystems.server.wireguard.interfaces.wgHome.serverNetConfigPrefix}-wgHome".hosts.${config.node.name}.ipv4; + }; + + mkIds = id: { + uid = id; + gid = id; + }; + + mkDeviceMac = id: + let + mod = n: d: n - (n / d) * d; + toHexByte = n: + let + hex = "0123456789abcdef"; + hi = n / 16; + lo = mod n 16; + in + builtins.substring hi 1 hex + + builtins.substring lo 1 hex; + + max = 16777215; # 256^3 - 1 + + b1 = id / (256 * 256); + r1 = mod id (256 * 256); + b2 = r1 / 256; + b3 = mod r1 256; + in + if + (id <= max) + then + (builtins.concatStringsSep ":" + (map toHexByte [ b1 b2 b3 ])) + else + (throw "Device MAC ID too large (max is 16777215)"); + + mkMicrovm = + if config.swarselsystems.withMicroVMs then + (guestName: + { eternorPaths ? [ ] + , withZfs ? false + , ... + }: + { + ${guestName} = + { + backend = "microvm"; + autostart = true; + zfs = lib.mkIf withZfs + ({ + # stateful config usually bind-mounted to /var/lib/ that should be backed up remotely + "/state" = { + pool = "Vault"; + dataset = "guests/${guestName}/state"; + }; + # other stuff that should only reside on zfs, not backed up remotely + "/persist" = { + pool = "Vault"; + dataset = "guests/${guestName}/persist"; + }; + } // lib.optionalAttrs (eternorPaths != [ ]) + (lib.listToAttrs (map + # data that is pulled in externally by services, some of which is backed up externally + (eternorPath: + lib.nameValuePair "/storage/${eternorPath}" { + pool = "Vault"; + dataset = "Eternor/${eternorPath}"; + }) eternorPaths))); + modules = [ + (config.node.configDir + /guests/${guestName}/default.nix) + { + node.secretsDir = config.node.configDir + /secrets/${guestName}; + node.configDir = config.node.configDir + /guests/${guestName}; + networking.nftables.firewall = { + zones.untrusted.interfaces = lib.mkIf + ( + lib.length config.guests.${guestName}.networking.links == 1 + ) + config.guests.${guestName}.networking.links; + }; + + fileSystems = { + "/persist".neededForBoot = true; + } // lib.optionalAttrs withZfs { + "/state".neededForBoot = true; + }; + } + "${self}/modules/nixos/optional/microvm-guest.nix" + "${self}/modules/nixos/optional/systemd-networkd-base.nix" + ]; + microvm = { + system = config.node.arch; + baseMac = config.repo.secrets.local.networking.networks.lan.mac; + interfaces.vlan-services = { + mac = lib.mkForce "02:${lib.substring 3 5 config.guests.${guestName}.microvm.baseMac}:${mkDeviceMac globals.networks.home-lan.vlans.services.hosts."${config.node.name}-${guestName}".id}"; + + }; + }; + extraSpecialArgs = { + inherit (inputs.self) nodes; + inherit (inputs.self.pkgs.${config.node.arch}) lib; + inherit inputs outputs minimal; + inherit (inputs) self; + withHomeManager = false; + microVMParent = config.node.name; + globals = inputs.self.globals.${config.node.arch}; + }; + }; + }) else + (_: { + _ = { }; + }); + + genNginx = + { serviceAddress + , serviceName + , serviceDomain + , servicePort + , protocol ? "http" + , maxBody ? (-1) + , maxBodyUnit ? "" + , noSslVerify ? false + , proxyWebsockets ? false + , oauth2 ? false + , oauth2Groups ? [ ] + , extraConfig ? "" + , extraConfigLoc ? "" + }: { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + useACMEHost = globals.domains.main; + forceSSL = true; + acmeRoot = null; + oauth2 = { + enable = lib.mkIf oauth2 true; + allowedGroups = lib.mkIf (oauth2Groups != [ ]) oauth2Groups; + }; + locations = { + "/" = { + proxyPass = "${protocol}://${serviceName}"; + proxyWebsockets = lib.mkIf proxyWebsockets true; + extraConfig = lib.optionalString (maxBody != (-1)) '' + client_max_body_size ${builtins.toString maxBody}${maxBodyUnit}; + '' + extraConfigLoc; + }; + }; + extraConfig = lib.optionalString noSslVerify '' + proxy_ssl_verify off; + '' + extraConfig; + }; + }; + }; + + }; }; - }; - } + } #+end_src *** Packages @@ -29895,6 +30126,7 @@ Modules that need to be loaded on the NixOS level. Note that these will not be a ssh = lib.mkDefault true; wireguard = lib.mkDefault true; dns-home = lib.mkDefault true; + opkssh = true; }; }; }; diff --git a/hosts/nixos/aarch64-linux/moonside/default.nix b/hosts/nixos/aarch64-linux/moonside/default.nix index bfbd912..09d244b 100644 --- a/hosts/nixos/aarch64-linux/moonside/default.nix +++ b/hosts/nixos/aarch64-linux/moonside/default.nix @@ -82,11 +82,13 @@ in serverName = "twothreetunnel"; }; }; - restic = { - bucketName = "SwarselMoonside"; - paths = [ - "/persist/opt/minecraft" - ]; + restic.targets = { + SwarselMoonside = { + repository = config.repo.secrets.local.resticRepoState; + paths = [ + "/persist/opt/minecraft" + ]; + }; }; }; syncthing = { diff --git a/hosts/nixos/aarch64-linux/moonside/secrets/pii.nix.enc b/hosts/nixos/aarch64-linux/moonside/secrets/pii.nix.enc index e0d419c..a22bd90 100644 --- a/hosts/nixos/aarch64-linux/moonside/secrets/pii.nix.enc +++ b/hosts/nixos/aarch64-linux/moonside/secrets/pii.nix.enc @@ -1,5 +1,5 @@ { - "data": "ENC[AES256_GCM,data:t3En0FAhzVnLIv9tuvrTtmYMGeKvZ5e3FoVZHlEbHsmvUlVl+t1Po2uANatzIeKX3HRZJ1mURXMKh7Xk9O9DsKssadBYa2YqZTugU5m9o4+xESQlqHlnnKALaiyfSXFlhAZ6X50e8nfPCDLicjKzQnk7S/0XMaFB7XN9T4SfonVLElHSZtmOC+85WgAn4uAyfPq44UDVw116g7ogpjztsCG3deqTxP/mcY5trtk+SCEEHLHO6AiEe+Jz628Z+t+3YttQMKQulrakUzzvP07jQhW4m8X1cQOfX2xeTVTwNiqEq75Pt7g+mycKO952BVmMPYIvQAU2xUNC3YIqaFHUDS2QbooAeSJq8TT/s/zM/tjXXLsA7EsFTcduDKDGXhBFt7AlicruhymgtuGv2IwQLeprytRpwz2wcWFGLeiOKp/Zdqwf/3yhGeYlOEv+yhCXI2oZxS+8q4Vu0ejDkTtSeGzm5EtTrxzmS4X2psq2In+9Jb70TrkutAA6F50VyKJV6WQX7Q9yFU6Z6URHlxpwOUzwpto4Z3gxOn9Hm9VyrhTSJZ7sjd9sYf0WO4CJpUYrTu5/ZRcdy8i6Wu2GA/ylt+XXsG1yicgPxDvUcWSg6VfD5/tSTEHtUUVD/sAf7xl/sPcd76Z1DFfgkfA/s4BbbyZKzaZpAz1WYTuhambFpKWDY8YKCoLZdSCahP0jupm3OcnNw7ZCYu43k2JHp4X1mW0gb4TPvIGOcpC+pJvLsa2Q4AUAt4eUmlMCogJ7R89LPLy3fTYDeQV9ly6Z54N70kfsJVCuzrqOjFS4WxqJPZZ4HcRth4JmFE0mcCDsWQVOGJdJmShFxr7kijEoAyfrrZeRG29PgU+2CCcm2dvswJ8DdEtI4E8i/tOwQlHpUmWAM5dFFvKWZjxd89tofYyB/mrAQwXhD7+9Yu4KJM1C3v2IbrvkOgaSMVL7Ekn5YqU+g2BfGYQbkCYMM3DLpllTMGjiMFeOLgvHPAhA3ozR0KxJUaUVZe5B5XscA1xaKedl3hDxR6A9r/g1EQvv7F0n1rWpJvMVSZ3oo8YmzO2DKDwsfKglkR3TrmvQyPvwO/F5wnKMb2+GWh0EmeQLcxHldB6j5CpAj6O1AqfOZjZNcFc8/RfAdLS+OMXgNaWvahVjlPKqI17zLTSJCaCF8KP/T9Chj90l5XqgPsV0t6bPDueOrBOrieQD8UKOjQHR/fgSunjZQrVfYgDBTilb3UyGJ3sqlL9zcTjTgLkNSkNd41EmnCm6SdB3RpQb1fcXfzuCp4bD5Ty01PU380YWXXkAinXDP8961uexWryckhsCqkfbdDnjti3CPfEOBWc6u1R9cI6oLZRw34NpY/4z/fuLAnxgjEgwLAQLG0am/tT1ySH/Cmfy,iv:aa5FNi/z0WnPHFsLUk3odDnghUq7YyA9U6nI71ug4fI=,tag:kd3TDY3mWiEEXsB9RopnUg==,type:str]", + "data": "ENC[AES256_GCM,data:MeJM7Y4TN0doXAHHxa5y+ZuatVyEsx4HL5sMBGJ77J6VIuqS1GvY9D2p+/JETZx5iwEf+oJ5CMUD4/PQtXbUM7RKzhyzU9AjCdfNos4ZTEyLUhmHgAup2AP0yVO/Qb7dYjDPwbT5wycAAQUx+3xc1GKX93MqsKfNVUqIHWAr20s5ct0RxBylvPWeZA6eNDmcdgNaA5QgKoEDrZtfK3inTg1UmhQZrvw7MWzFN68DdC7FRxeDxSdn1ctucGTJW8k1LT5MdwGCA7nX08vAMG7VBIuj61ZXXU3zFtNRtdHBiyzlqjgInHRWevajK7L/Vjxpy3ffBRAFFQYZi6jVaui5acOywSvCvvrzVKN6Z2Rzc72KfC/np0NElJBrTAqBfQ+8tXrjjd8uaTQXbcXc3qk/y6+kfjOcYB8lk0opA/r33xUR7QkMElu7zuw1+u5ClKTOIZSqkdqrEbTCnw+hn5fL2VH0bShEACXQal6z/XnJSULmzxE5YfSK7qsJxakVux+Ksz3E5EHYgyyMCNk5WEyJtFz5FFBV0+FDbar9ChdLPvY/SEGLGS7ekx6aA/PQGQtb/xsk5pylt5Ie6vxL4YBDAxgm1ss4ciK3HfoAZJnQbfa6kkqm1rfAvzr2rM4WH/Vyocakpqxv16QH4AtbX0A02Y4lwMhxTz+8XRFxLOm4CBXYBddKSMKEaW0VCMEl3U3g4e7vPRg2tp+1WxouJSjbejgnVeq/A026j6ZwQ44xADkWjG+4lCvIO0NLZIv5uE3Sb3a4sW4dphqrQPWMaiOmtzxxZWbO0GTnQ5/U2U6DCdyspGjFEFAGOxduFTBMhIeDzWfHLty/S17Hjaxp+v3qEnOs7aMznIzV/LmzAxMp0CVA6I7ehtzbHVNdaY4DfrrNZJgYzkoUG1F0De5in+Bk6g22UecAXBW2sLugmxPwV14sa0iD4IpAvrGE4LwdnGOFAXWunYvOK2zsn92v7ymESayGj9PqH9srL/yaB/RZuJ3VtwLNgPTc+Ly9G6PL3XMInjWdmI9+wIuBaDyWdUxLZhhlH+njc9Bc/rxQWbXHlggrTFQw+rLlQtw0w6rS+avbC+KDpnhhTKDV4gQZsvY8PpKlsmvgN8g6BKrY25JE9sLBMMxmzSbLfIUDGgfUi7BM9p0l4wpdWrHB+rBQtoULDXCWR3LRD4SnyBoNSgXhoXxMaelUVpfOlY105sLLYxMzkzSijQ+OJ1pST1ED+XEnjddcLJtJ+1zIQ5aRZCYDcRr0FGvLcfW+M2yORIc03r/RI/wKTASezuydtMGibUUwBq1jjb5ZDGQEVdABPCEdqBgubDllFm3JdkyPV6V0EoQ4Qq+dv021exQqclentdBqK/A/LJ+h1QQyg7+wDdeC0sJF0EHP,iv:5u/hx1/P7QsLpx/tXceGMjI2Hh5crdguiI30+HJfd/w=,tag:8k5G2WALcjD8S8lZ30EWGw==,type:str]", "sops": { "age": [ { @@ -7,8 +7,8 @@ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2YjdYNFF5Q1VzQTZ0WU1z\nN2R6cEVObU9RMXdpd2x0Mjh2cmpvY0VvNjE4CmF5Sm1vZWRoOTFIY2pkQUVRQ3FY\nVEd3eGpCbGQ3cUpvTE9JdjJMWnQvckEKLS0tIFRpZDZ1ZGZKaXpObFhZVlNqV0hB\nT20rRGV6S3gvWkZLUzQzVVNGQWNGVkUK0bAeRuI0vb7MJTtpxuD56nwZAk39sHAa\njEhntqsV9ts1Vbw2f0mZEqDdzd64NTtDm/YIwygZ2udV27mXNhVUVw==\n-----END AGE ENCRYPTED FILE-----\n" } ], - "lastmodified": "2025-12-04T23:10:31Z", - "mac": "ENC[AES256_GCM,data:gNsVWFrs92csjnRvhtXcKLuZUiHo9dxpFRLwjWz7VQSLeOBL4iv+Hq3SNyx4F69AC2nr9HL1QTLzX+444EhDYot0jLqOH6xz/FaQPf6OXKHg+Nr05MUe8X2QsLjodOW81Vv7HqIMypU5dyt0FBr74++9oEz6072AuFl5JAUWIvo=,iv:tGX+wUKvWYOnxVCTqhra7tg+r+TT8tyAr1tlRP2FkWA=,tag:WI5D0FTguiCJcrQh47qJow==,type:str]", + "lastmodified": "2026-01-19T14:14:55Z", + "mac": "ENC[AES256_GCM,data:tNJ4mSS9ulh3sQ1X5ccoswadbnQVm0+3bbyai486ljw59IBkGbf3mo35Dc1PHZJB+zXoiAj7d+hhY7YGJNz7CJjunI0o4+Aj38aEMUa/VpdO0LX+7xTz+r2wX3zaDYbAI16klElXJ30Z8PyVSoGosbz5DbPAKFED7silxVfiPbc=,iv:KOWA4/+jKqbrghw+LW91UQj5+IWSYx2RSi76ew7uNZ4=,tag:znrx6hMqFu+lykXu3DCHMQ==,type:str]", "pgp": [ { "created_at": "2025-06-13T20:12:55Z", diff --git a/hosts/nixos/aarch64-linux/moonside/secrets/secrets.yaml b/hosts/nixos/aarch64-linux/moonside/secrets/secrets.yaml index 08480fc..c78d1a6 100644 --- a/hosts/nixos/aarch64-linux/moonside/secrets/secrets.yaml +++ b/hosts/nixos/aarch64-linux/moonside/secrets/secrets.yaml @@ -16,9 +16,9 @@ microbin-uploader-password: ENC[AES256_GCM,data:20QOWTMLS7iTS/Q=,iv:EuUYcY1l4ykK #ENC[AES256_GCM,data:ZnMVMv6M,iv:z53BHIVvMUfYseftc6DTU9Mlb9ywEvNHv24TvIZiMFI=,tag:QdeWjrw0pmJsXYobADzA1A==,type:comment] shlink-api: ENC[AES256_GCM,data:XdfDJMjyhJyeqVB4RKgCdkWT2nYC/Pw21D8H/JzkGLuwGx8Q,iv:zucJGNLX8018gD34NL/BwTe0fPFucqpBtMCYXd3IGHs=,tag:/sN/ayEhUaCPmu6fS+mMHQ==,type:str] #ENC[AES256_GCM,data:R5mm4WAJww==,iv:6Uyb7Qtl6vt7nur/NLBlrVtKoPkF3ZjXdAhT24HW/ug=,tag:6X9b1zZbpHoEZmaYb9NQSw==,type:comment] -resticpw: ENC[AES256_GCM,data:PcrDphqR5Pin2hM=,iv:lnMlqwyCvbH75qbL2eJYblmuFOaVMmbPHjZ5l0n2Glw=,tag:YUxadLufJ2VPghLded851A==,type:str] -resticaccesskey: ENC[AES256_GCM,data:DOp2cFy1Y5HyXcsQ5O3nsrEOQBtlQQ3P8Q==,iv:0X6HF9kbPNDmhtENHgFeOSHln6xlCf5DNJfqavucDWI=,tag:+THGH00yBT9RhvJtENco2Q==,type:str] -resticsecretaccesskey: ENC[AES256_GCM,data:qpPTWx16Z92cup6ACh2KQPeIk8KPasQB4e/SwxUxfA==,iv:EqWTKXXA7wyArlF+D33tKF37tz8/ORsjsWjRPYBWPqg=,tag:F21+4cL/cozDIene7UQcyA==,type:str] +resticpw-SwarselMoonside: ENC[AES256_GCM,data:+kPee07ZmnAv4V0=,iv:gi7sdKO+WE8qTuYb3wbjgmVzRvmF8hd1h5vV9QDx+6Q=,tag:0/azZWAqeXcXCsmx2HkFmQ==,type:str] +resticaccesskey-SwarselMoonside: ENC[AES256_GCM,data:R9yj4NFFeZ/iU8Jwp5r3BwnZDy1eSWsebQ==,iv:8C05b7pxA7fJC1Mh5oAH1A5LtNYhZaZnQfAjZMURGtc=,tag:pSGpJrOy/i9Iq22OQPtU9g==,type:str] +resticsecretaccesskey-SwarselMoonside: ENC[AES256_GCM,data:8dp2FGgoJa5TBy2HFITO2to8Z4xoowzhLrCZVDLrAA==,iv:2t3CoVp/4+8xZvSjuMnq4d4nFugnL53HPv1r/odKGvM=,tag:I5zxggxsNHVovq8bcRs0Pw==,type:str] sops: age: - recipient: age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh @@ -30,8 +30,8 @@ sops: bURRem1aY203VW0ya0tZWUY3WTJLQ3MKonflaevgNP91G1cVgzoE6/K800kyG6BK Goe81HCYFfm86pzv5wV3/38j7fTZNeZnKwPFkMgEUueF1kA8J9V5CA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-11-28T17:44:47Z" - mac: ENC[AES256_GCM,data:h3skmRhVfBa/W6GB35O3sHdDLmo/4VQ3rgFbltdweDP+9qbQv+6tduRGknGiQjnyuaGGVyPlEOqfLKzYjP8Jsx+XnprblNfD75yiGckBFQaBKhd8l+hfcYVRNTrKCWkFUrYXIfCWgbrXNmq47SHn0+TBedXRw+9LoSyqsRdIJOk=,iv:Js2C7XfOD4d5fF+Otn7xJxBw0Nfh1cB7oLjyCrUA9es=,tag:4flxdWSlXyslNErlEFM2VA==,type:str] + lastmodified: "2026-01-19T14:13:20Z" + mac: ENC[AES256_GCM,data:XKsR8Gp6UHhAfoOdRozMxoGtdhfV7b6ogsqlqiAfTsuUayVVK6fRIgy5no5jcNnyyN8zveH/QZS1kGpNSY24N0l4gBA3u5ay5fsS0HjfW5b7mNpasOttqCrm6RpY2ZDdTUmsk3F25QEsdc28fajURJKOazZSs78dbdNq1LdJK1s=,iv:TgLuYGZtxx0ZPPeR1M/NgV1Wt7f5V89KEFOpKSjBxws=,tag:I/CGHZcT6n9X8R2EYRbOYw==,type:str] pgp: - created_at: "2025-06-13T21:18:31Z" enc: |- diff --git a/hosts/nixos/aarch64-linux/twothreetunnel/default.nix b/hosts/nixos/aarch64-linux/twothreetunnel/default.nix index 81c5676..34cb243 100644 --- a/hosts/nixos/aarch64-linux/twothreetunnel/default.nix +++ b/hosts/nixos/aarch64-linux/twothreetunnel/default.nix @@ -37,6 +37,24 @@ "moonside" "winters" "summers" + "summers-ankisync" + "summers-atuin" + "summers-audio" + "summers-firefly" + "summers-forgejo" + "summers-freshrss" + "summers-homebox" + "summers-immich" + "summers-jellyfin" + "summers-kanidm" + "summers-kavita" + "summers-koillection" + "summers-matrix" + "summers-monitoring" + "summers-nextcloud" + "summers-paperless" + "summers-radicale" + "summers-storage" "belchsfactory" "eagleland" "hintbooth-adguardhome" diff --git a/hosts/nixos/x86_64-linux/hintbooth/default.nix b/hosts/nixos/x86_64-linux/hintbooth/default.nix index 937ec67..6721ebf 100644 --- a/hosts/nixos/x86_64-linux/hintbooth/default.nix +++ b/hosts/nixos/x86_64-linux/hintbooth/default.nix @@ -27,7 +27,7 @@ info = "HUNSN RM02, 8GB RAM"; flakePath = "/root/.dotfiles"; isImpermanence = true; - isSecureBoot = false; + isSecureBoot = true; isCrypted = true; isBtrfs = true; isLinux = true; @@ -46,6 +46,25 @@ "hintbooth-adguardhome" "hintbooth-nginx" "summers" + "summers-ankisync" + "summers-atuin" + "summers-audio" + "summers-firefly" + "summers-forgejo" + "summers-freshrss" + "summers-homebox" + "summers-immich" + "summers-jellyfin" + "summers-kanidm" + "summers-kavita" + "summers-koillection" + "summers-matrix" + "summers-monitoring" + "summers-nextcloud" + "summers-paperless" + "summers-radicale" + "summers-storage" + "summers-transmission" "winters" ]; }; diff --git a/hosts/nixos/x86_64-linux/summers/default.nix b/hosts/nixos/x86_64-linux/summers/default.nix index ad093b0..8e08ce4 100644 --- a/hosts/nixos/x86_64-linux/summers/default.nix +++ b/hosts/nixos/x86_64-linux/summers/default.nix @@ -53,19 +53,19 @@ serverName = "hintbooth"; }; }; - restic = { - bucketName = "SwarselWinters"; - paths = [ - "/Vault/data/paperless" - "/Vault/data/koillection" - "/Vault/data/postgresql" - "/Vault/data/firefly-iii" - "/Vault/data/radicale" - "/Vault/data/matrix-synapse" - "/Vault/Eternor/Paperless" - "/Vault/Eternor/Bilder" - "/Vault/Eternor/Immich" - ]; + restic.targets = { + SwarselState = { + repository = config.repo.secrets.local.resticRepoState; + # nextcloud stores all data in state dir and has no data that needs backup + paths = lib.map (guest: "/Vault/guests/${guest}/state") (builtins.filter (name: name != "nextcloud") (builtins.attrNames config.guests)); + }; + SwarselStorage = { + repository = config.repo.secrets.local.resticRepoStorage; + paths = [ + "/Vault/Eternor/Pictures" + "/Vault/Eternor/Documents/paperless" + ]; + }; }; }; }; @@ -78,59 +78,31 @@ swarselmodules.server = { wireguard = true; - - nginx = true; # for php stuff - acme = false; # cert handled by proxy - - nfs = true; - # kavita = true; restic = true; - jellyfin = true; - navidrome = true; - spotifyd = true; - mpd = true; - postgresql = true; - matrix = true; - nextcloud = true; - immich = true; - paperless = true; - transmission = true; - syncthing = true; - grafana = true; - freshrss = true; - kanidm = true; - firefly-iii = true; - koillection = true; - radicale = true; - atuin = true; - forgejo = true; - ankisync = true; - homebox = true; opkssh = true; }; guests = lib.mkIf (!minimal && config.swarselsystems.withMicroVMs) ( { } - // confLib.mkMicrovm "kavita" { withZfs = true; } - // confLib.mkMicrovm "jellyfin" { withZfs = true; } - // confLib.mkMicrovm "audio" { withZfs = true; } - // confLib.mkMicrovm "postgresql" { withZfs = true; } - // confLib.mkMicrovm "matrix" { withZfs = true; } - // confLib.mkMicrovm "nextcloud" { withZfs = true; } - // confLib.mkMicrovm "immich" { withZfs = true; } - // confLib.mkMicrovm "paperless" { withZfs = true; } - // confLib.mkMicrovm "transmission" { withZfs = true; } - // confLib.mkMicrovm "storage" { withZfs = true; } - // confLib.mkMicrovm "monitoring" { withZfs = true; } - // confLib.mkMicrovm "freshrss" { withZfs = true; } - // confLib.mkMicrovm "kanidm" { withZfs = true; } - // confLib.mkMicrovm "firefly" { withZfs = true; } - // confLib.mkMicrovm "koillection" { withZfs = true; } - // confLib.mkMicrovm "radicale" { withZfs = true; } - // confLib.mkMicrovm "atuin" { withZfs = true; } - // confLib.mkMicrovm "forgejo" { withZfs = true; } // confLib.mkMicrovm "ankisync" { withZfs = true; } + // confLib.mkMicrovm "atuin" { withZfs = true; } + // confLib.mkMicrovm "audio" { withZfs = true; eternorPaths = [ "Music" ]; } + // confLib.mkMicrovm "firefly" { withZfs = true; } + // confLib.mkMicrovm "forgejo" { withZfs = true; } + // confLib.mkMicrovm "freshrss" { withZfs = true; } // confLib.mkMicrovm "homebox" { withZfs = true; } + // confLib.mkMicrovm "immich" { withZfs = true; eternorPaths = [ "Pictures" ]; } + // confLib.mkMicrovm "jellyfin" { withZfs = true; eternorPaths = [ "Videos" ]; } + // confLib.mkMicrovm "kanidm" { withZfs = true; } + // confLib.mkMicrovm "kavita" { withZfs = true; eternorPaths = [ "Books" ]; } + // confLib.mkMicrovm "koillection" { withZfs = true; } + // confLib.mkMicrovm "matrix" { withZfs = true; } + // confLib.mkMicrovm "monitoring" { withZfs = true; } + // confLib.mkMicrovm "nextcloud" { withZfs = true; } + // confLib.mkMicrovm "paperless" { withZfs = true; eternorPaths = [ "Documents" ]; } + // confLib.mkMicrovm "radicale" { withZfs = true; } + // confLib.mkMicrovm "storage" { withZfs = true; eternorPaths = [ "Books" "Videos" "Music" "Pictures" "Software" "Documents" ]; } + // confLib.mkMicrovm "transmission" { withZfs = true; eternorPaths = [ "Books" "Videos" "Music" "Software" ]; } ); networking.nftables.firewall.zones.untrusted.interfaces = [ "lan" "bmc" ]; diff --git a/hosts/nixos/x86_64-linux/summers/guests/ankisync/default.nix b/hosts/nixos/x86_64-linux/summers/guests/ankisync/default.nix index 84c16b1..1359ff4 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/ankisync/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/ankisync/default.nix @@ -36,7 +36,7 @@ }; swarselmodules.server = { - # ankisync = true; + ankisync = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/atuin/default.nix b/hosts/nixos/x86_64-linux/summers/guests/atuin/default.nix index 6a0e601..7d4eeea 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/atuin/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/atuin/default.nix @@ -36,7 +36,7 @@ }; swarselmodules.server = { - # atuin = true; + atuin = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/audio/default.nix b/hosts/nixos/x86_64-linux/summers/guests/audio/default.nix index 114e332..5f2ddd6 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/audio/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/audio/default.nix @@ -36,9 +36,9 @@ }; swarselmodules.server = { - # navidrome = true; - # spotifyd = true; - # mpd = true; + navidrome = true; + spotifyd = true; + mpd = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/firefly/default.nix b/hosts/nixos/x86_64-linux/summers/guests/firefly/default.nix index 461ebff..26ba724 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/firefly/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/firefly/default.nix @@ -36,9 +36,9 @@ }; swarselmodules.server = { - # firefly-iii = true; - # nginx = true; - # acme = true; + firefly-iii = true; + nginx = true; + acme = false; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/forgejo/default.nix b/hosts/nixos/x86_64-linux/summers/guests/forgejo/default.nix index f19dc48..5d1822a 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/forgejo/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/forgejo/default.nix @@ -36,7 +36,7 @@ }; swarselmodules.server = { - # forgejo = true; + forgejo = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/freshrss/default.nix b/hosts/nixos/x86_64-linux/summers/guests/freshrss/default.nix index bde8bbb..adf2eca 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/freshrss/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/freshrss/default.nix @@ -36,9 +36,9 @@ }; swarselmodules.server = { - # freshrss = true; - # nginx = true; - # acme = true; + freshrss = true; + nginx = true; + acme = false; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/homebox/default.nix b/hosts/nixos/x86_64-linux/summers/guests/homebox/default.nix index 062c0df..3f338f6 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/homebox/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/homebox/default.nix @@ -36,7 +36,7 @@ }; swarselmodules.server = { - # homebox = true; + homebox = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/immich/default.nix b/hosts/nixos/x86_64-linux/summers/guests/immich/default.nix index 86a4814..1a94a4f 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/immich/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/immich/default.nix @@ -27,8 +27,8 @@ } // lib.optionalAttrs (!minimal) { microvm = { - mem = 1024 * 8; - vcpu = 8; + mem = 1024 * 16; + vcpu = 14; }; swarselprofiles = { @@ -36,7 +36,7 @@ }; swarselmodules.server = { - # immich = true; + immich = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/jellyfin/default.nix b/hosts/nixos/x86_64-linux/summers/guests/jellyfin/default.nix index 3f80bef..85a3fb1 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/jellyfin/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/jellyfin/default.nix @@ -28,7 +28,7 @@ microvm = { mem = 1024 * 3; - vcpu = 1; + vcpu = 4; }; swarselprofiles = { @@ -36,7 +36,7 @@ }; swarselmodules.server = { - # jellyfin = true; + jellyfin = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/kanidm/default.nix b/hosts/nixos/x86_64-linux/summers/guests/kanidm/default.nix index c70f9df..776e2f2 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/kanidm/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/kanidm/default.nix @@ -28,7 +28,7 @@ microvm = { mem = 1024 * 4; - vcpu = 1; + vcpu = 2; }; swarselprofiles = { @@ -36,7 +36,7 @@ }; swarselmodules.server = { - # kanidm = true; + kanidm = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/kavita/default.nix b/hosts/nixos/x86_64-linux/summers/guests/kavita/default.nix index 4a3027b..91d20a3 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/kavita/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/kavita/default.nix @@ -28,7 +28,7 @@ microvm = { mem = 1024 * 1; - vcpu = 1; + vcpu = 2; }; @@ -37,7 +37,7 @@ }; swarselmodules.server = { - # kavita = true; + kavita = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/koillection/default.nix b/hosts/nixos/x86_64-linux/summers/guests/koillection/default.nix index cbd5f2a..b5e55c1 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/koillection/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/koillection/default.nix @@ -36,7 +36,7 @@ }; swarselmodules.server = { - # koillection = true; + koillection = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/matrix/default.nix b/hosts/nixos/x86_64-linux/summers/guests/matrix/default.nix index 1575ad4..024399b 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/matrix/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/matrix/default.nix @@ -27,7 +27,7 @@ } // lib.optionalAttrs (!minimal) { microvm = { - mem = 1024 * 3; + mem = 1024 * 6; vcpu = 2; }; @@ -36,7 +36,7 @@ }; swarselmodules.server = { - # matrix = true; + matrix = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/monitoring/default.nix b/hosts/nixos/x86_64-linux/summers/guests/monitoring/default.nix index d015cb2..b91ed1a 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/monitoring/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/monitoring/default.nix @@ -36,7 +36,7 @@ }; swarselmodules.server = { - # grafana = true; + grafana = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/nextcloud/default.nix b/hosts/nixos/x86_64-linux/summers/guests/nextcloud/default.nix index d8580b0..3fe0800 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/nextcloud/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/nextcloud/default.nix @@ -36,9 +36,9 @@ }; swarselmodules.server = { - # nextcloud = true; - # nginx = true; - # acme = true; + nextcloud = true; + nginx = true; + acme = false; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/paperless/default.nix b/hosts/nixos/x86_64-linux/summers/guests/paperless/default.nix index 74fe3a6..8381a04 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/paperless/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/paperless/default.nix @@ -27,7 +27,7 @@ } // lib.optionalAttrs (!minimal) { microvm = { - mem = 1024 * 4; + mem = 1024 * 8; vcpu = 4; }; @@ -36,7 +36,7 @@ }; swarselmodules.server = { - # paperless = true; + paperless = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/postgresql/default.nix b/hosts/nixos/x86_64-linux/summers/guests/postgresql/default.nix deleted file mode 100644 index f94f5f1..0000000 --- a/hosts/nixos/x86_64-linux/summers/guests/postgresql/default.nix +++ /dev/null @@ -1,42 +0,0 @@ -{ self, lib, minimal, ... }: -{ - imports = [ - "${self}/profiles/nixos/microvm" - "${self}/modules/nixos" - ]; - - swarselsystems = { - isMicroVM = true; - isImpermanence = true; - proxyHost = "twothreetunnel"; - server = { - wireguard.interfaces = { - wgHome = { - isClient = true; - serverName = "hintbooth"; - }; - wgProxy = { - isClient = true; - serverName = "twothreetunnel"; - }; - }; - }; - }; - - -} // lib.optionalAttrs (!minimal) { - - microvm = { - mem = 1024 * 1; - vcpu = 1; - }; - - swarselprofiles = { - microvm = true; - }; - - swarselmodules.server = { - # postgresql = true; - }; - -} diff --git a/hosts/nixos/x86_64-linux/summers/guests/radicale/default.nix b/hosts/nixos/x86_64-linux/summers/guests/radicale/default.nix index aa70516..74a6930 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/radicale/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/radicale/default.nix @@ -36,7 +36,7 @@ }; swarselmodules.server = { - # radicale = true; + radicale = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/storage/default.nix b/hosts/nixos/x86_64-linux/summers/guests/storage/default.nix index b6da313..3531298 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/storage/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/storage/default.nix @@ -36,8 +36,8 @@ }; swarselmodules.server = { - # nfs = true; - # syncthing = true; + nfs = true; + syncthing = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/transmission/default.nix b/hosts/nixos/x86_64-linux/summers/guests/transmission/default.nix index e4e7bd3..6afde67 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/transmission/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/transmission/default.nix @@ -8,17 +8,12 @@ swarselsystems = { isMicroVM = true; isImpermanence = true; - proxyHost = "twothreetunnel"; server = { wireguard.interfaces = { wgHome = { isClient = true; serverName = "hintbooth"; }; - wgProxy = { - isClient = true; - serverName = "twothreetunnel"; - }; }; }; }; @@ -36,7 +31,7 @@ }; swarselmodules.server = { - # transmission = true; + transmission = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/secrets/pii.nix.enc b/hosts/nixos/x86_64-linux/summers/secrets/pii.nix.enc index d911ed6..91992c6 100644 --- a/hosts/nixos/x86_64-linux/summers/secrets/pii.nix.enc +++ b/hosts/nixos/x86_64-linux/summers/secrets/pii.nix.enc @@ -1,5 +1,5 @@ { - "data": "ENC[AES256_GCM,data:l0LIC8IP4wVA8wI5Ef1yKYfvJw4b4izz7HemWgoKjx34GWLnVYKYqrsXuGD8QN0GzbK9ZAPsWXYa3VejnVXv8Qe1B9GPEJbPtP//ExZ9lDYoKICLpy/yLxSiG85xSQQ46UcipCpA5ZjJPnmYeimTlW+PH5BmuL3LD/OteGVcIwRVznBaQwQ/DnzxE7eBOyF3l0apIIzk4paMswF5OSh0+0EfIS0wKJ1zBLW3OfVc9N1npC7nn7x01X/fde9k4s0gt2XjPQ/Qo5HdBfEfqzzOTu1jiYuvuoiQ4KmlME75HWfLoGLjCYCespoEnH0v45vJALiKNk6wBbHwidY00HH8DSxRujYxl23IuW+r6x5B/rpXUanrHzfKmQyx3crYqDl3URHwycW49GXxWBy8PPE49SGmWMh25ceuLjIgqQaGppza1X/V3RV7tvA96/L/kAIvmoDaYJMncFv89Q+fi0obp1YqVNkxsdGuBawOnCzyL2RAhf9t1no2ak7zJnMqaiHY6BU0Sg2OSwWEJQEEBzmj4P5k9SXqVBF/MUL65sp76hq7Wk6mqtofHvzY0ugLw/b2G4+RlWNAyDQnb3dSmldSc/U7bLZ+2Z6IFlMrRGg0niZd8g2283CQACvNBSonZ9v1SMfgN6ChG2U8ry6McYwsrO0dDshiFyyyvy1GxPAzc8nf/n40i0ipnTydJ3vxlaPq3rKZPfsXQdfiqDDu5tGiF+7JpdBtoJQ2Pp8pRKkS6sVPIY2OsTdu/ZQ34aW9aBKLfGMB/YPm9vid1Nlp/5TSbmbXfC9Lwz5s3I50N/iLI9F8W+hhR4RpOQLufkS0+neFqK1N38s6P/lXAfIrDdq9+QNZvSE61bZqjx7oxl6QKJKvZCFmkTIZOP/xANrSe17f2MZ1ugh1MBMb/5/Zh9BznJBEjNMsaCdEEBe8Anbum0oO9CXlldFMqUf+LufI1VDWj/68oBjNmHgHFVzUofxD7q4EZ/8HTtfTWOivVLg0F2l4fR6JIdTqKEk/g1tVll2gWfH9H/xNrdZQ9PQI/XKiSa6LIWEdlPz3TuH2Fw6bo6UC1YfVMvoWPUQsUhqrCBv0eb7snvYBkUJg+/BWhWelL9W8FD0gce3WrJfAe12TXqgWb0zSHtPk9C9E0+UkXEM/SAciBJTSowR0edM8QyPzT8nP/9qrHz390V8EIbENWU9AYDuo6o5fh0E34FHNCuX/+toq9VrZZLVUR1pb+o4=,iv:o6qAis1FnoabxGMQDDXrubSFHIgP0XHkjO4Usx+eQoM=,tag:rC+nrChrFNfT/3C71szrfg==,type:str]", + "data": "ENC[AES256_GCM,data:F3RDXp9c69ZGzLlhWHDGDse6s3qYDbUjGQZi0iSS1J9Bb+K2SToOyxIg51UUp7K3TMQCiwj1OnwdP3FJlaA7CHpKYYEX+hL5/msA+ITs0dWNiuSaI7Hd0HE7kplU+jHVEOoFP36e6sdVlsUO1H2ICUTCIPU6zjQ9FqQkHBeKg9jPnOYkI1AV638F8261nqsfsmrN4yDS4bWgI7WsXBGAZJQ9nuvHIMUBXkLNOGI9o45vOZXW3LZmWLLJUddal8TNeitQ3tzJXnO+4pZbvlHhVxbkwB40Fc3mt/ZYqHfRK9W70dEDa63zYIVoyai8BlXmWl5mScxPerhvt05+NUeswV/yXf4UpsdAUttzNXuWenN7I9bIMrEODFocdPvELB/N/26smXaRFbtakSTeyDSuqwOefUashiZ+LyNB9lLpKyUXUiLxsOusucQIrL9kiMTvr2atPAXfEGJYC25uxNGOghffcwquitcMAKtGyLAMfnI606FkFE1MZxPc60OZo2y1yHhqV/QVFjoAwkFW5sSNUbe5DLoijuoNT+MZGxypwDUhgzCqWXzwz300jzpV3dla2tKeOjcJZk1JmlfXOrPsCNGkL1MtC5kRXFjA9HUV25fSHzrChDiyBek4fTCtZNphJz0yGBbNfX30vpY=,iv:w/D7rqHWsvBxUJaY4D2b3+aJRfoSfDwwU5L3facXFtY=,tag:3pwiviZYNiKe0FwteR7CxA==,type:str]", "sops": { "age": [ { @@ -7,8 +7,8 @@ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBKcWF5cDZnWlZBYko2UFV2\nNGRMNlNzejVGR3hJSXNjaFQrWk1FWU9WZDM4CjZBRW9PbG9XY0V2T0dZTVhGU1Nn\nOXpXSWdaeHRNbmd5S0xuUkVuLzlidTgKLS0tIGNXckVXK0d6R2dNKzFzYTNPZWVW\nT0QzY0kvNEJvSC9CWExaRjBsQjdVYU0KavAD19+DC502a44wxbtz8fbxwIgpgE2c\nU4LlkgvkrhtTTiu6d/LiAKfqM9PrSajBdO8YrTpFxkqYgfi1tMoC8w==\n-----END AGE ENCRYPTED FILE-----\n" } ], - "lastmodified": "2026-01-10T11:23:49Z", - "mac": "ENC[AES256_GCM,data:p/kSeOGsEFw1NxehT0UVNOrf20K+YEK/heZakNf+X4C4GabctvCTyGouoRDDq3ea/O7TeTT+uVRiveZ6TOE7S7rKwFX5yTuB1wKDqsFLjDgFidwzicHIBmfceB3XolU/l0cIkEH4UcYYOelfiHr5gtjLefnCUojttlUhRZz9CD4=,iv:2QDqwkwlaKZwtnuzfkmBDYmTTvt7FN2op6/O8JcHSBA=,tag:cOgrxorAFDwpBF2NfxxuVw==,type:str]", + "lastmodified": "2026-01-19T14:24:03Z", + "mac": "ENC[AES256_GCM,data:b87qyAxWtLycdtKTN2x+k9+CQB+JBUarfjDdrIiKBSaBwC0Gg05W5t2j1TRqi5NjA8GITYRRIHkzS0jx37zoLSmrJZqzSg4hTlbMDdjeGZiJt+zi7rDSv1HRSoOHz6CoG8XQYULNri1qcLzjBOCcdIFISh9EhXOTNbrwJ8uF/Eo=,iv:sFefD/bK514/SJ3PWJgL5a5Z4UHj6NKvJkLi0HhqpxI=,tag:v6CvJ1o8lKAAx1CApW6sdw==,type:str]", "pgp": [ { "created_at": "2026-01-10T00:38:26Z", diff --git a/hosts/nixos/x86_64-linux/summers/secrets/postgresql/secrets.yaml b/hosts/nixos/x86_64-linux/summers/secrets/postgresql/secrets.yaml deleted file mode 100644 index 802b0f6..0000000 --- a/hosts/nixos/x86_64-linux/summers/secrets/postgresql/secrets.yaml +++ /dev/null @@ -1,57 +0,0 @@ -wireguard-private-key: ENC[AES256_GCM,data:iSjQO7EUVOYgh3378FTGPOf7fUFLBoA7KhxroPv3iyWfbDI8r0yB/ewoMOI=,iv:Z9KlHucjpU44VvYWkq443njeSs0TREKTIeq65ieUXv4=,tag:6fjf3Ce/tuvK4vHvBaQn4A==,type:str] -sops: - age: - - recipient: age14sjyqch8tzqexk2gv0qgrrg09f0s6hvwhsgjac3vs6sc5rzgpcxsyqda6u - enc: | - -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2NlJITGlYcExUSStpOVA3 - b0t1ZklHciszOWlVNlJZN0d6a2dHWDlmb0JrClFpODdacW1nMDFySmUzd0pVSWNl - MGdSSTQ5ZFpGM1J0VjRIMmZVVjU3UVUKLS0tIGJPVWRPYzVPY2YvT2NrSU5BRDF0 - Nm1RY0dVUDJZbGY2TU9paHNWaVVsMHcKCPcHSSMjzPHBgj7LIFcGnQT/74nGgc78 - yfX67XYz1Ybdy23C9mddR8XtEy+g24MUEd4RoM9zziIG/Qt6+hl6rg== - -----END AGE ENCRYPTED FILE----- - - recipient: age12jh5836w3cmazec8ql652p9h3a3xn6quztztzqxg4n0kz7r96dnqqlhxxw - enc: | - -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2Y0Q0eU1lUDJZZENQYS85 - U1RzTU5XUEkxcnNwNGEwb3Z3UVA2YjkrcEUwCm1FNXM5czZxM2pDUk9pQkpOODFz - WW1ZWlJZeEJMNksvV0lGM2xvUW8vVUEKLS0tIGNidlRrSS9mb3VwWnJjRHFlZS9y - anoxVlpVcU1ZczBKQUZob1ZNNEcyYUEKrBDXe8EnozMy5nfGDV5Gcy10Q8q+CS+f - 9jOpiFBnK3wRpjS5n7aHtg8j+CHxDIV4ERH1XvuAsMPvaZpuY4TKMQ== - -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-01-07T13:36:49Z" - mac: ENC[AES256_GCM,data:FVo2l0qd8E0G4252lmbPqhBKBu1WRXdqD5iYNJ5VTcFwM2ErC1RXVFFzX5jnBdq8yPUozS5/Vjm5p4B+N1bxwDe8nmKUJcXFy5AdMMgrVmXySPqEF6+uMQM5Mfh5yLgLnxscpCo6SV0kESfD86TeHI/HJ73EL4L8tD5V0tiDcSg=,iv:igf9D+MLI0rhagUP6IZLe6sP2HL5UpT5Z0DtLbXVq50=,tag:c0CGV69zbtIUxZMRJHh8yg==,type:str] - pgp: - - created_at: "2026-01-12T22:05:38Z" - enc: |- - -----BEGIN PGP MESSAGE----- - - hQIMAwDh3VI7VctTAQ/8Cqj7NrbjiXvyZIeZJsxy3Tv+T8u7muMMCWGb0eUuiyCG - w037NfXNVc4j36DNIpzFaSa6Y0ZD6A8yoHZ794qNngxghe/M71UHgivTXayVhiqH - ViPFmET/LIBZhX32bf++3yS3FYthvs8Uyn+sRCtypSFH8IaRwSdZO0tRkJMJOybm - z2O6ktQYWfzsAzJtqXShhe4W2egl+rUfbIxM7/GcqImQPrCyUc7mHn9S4+tUPWgF - AhDRx12l3KmleixY/xtrRE9Z0TkQ3BezmZzacAmKfPjR/DcJ5zBEzHADh3AgxmBU - up6IvhqAkm7XsxgyHo+6iK8OkMF/ac0sA+Fk74lyvPfVBPW9lVwMvXo/BvFzbGPb - DL6rQP82vWX2WGhRM4g8FO0PIETNRs75yn4NmDWd1Kz1ENgKxhRaoDyrMBM8jw3n - MbHNPif66KrUWB5kbiRVGW367o8O7dCizRnwDdXHOFrjYjCM0tcXMFIeC7AcjQoX - LfC63ctDSJVrRqs2AT7xUVCGHpZWSHMlmukNAS4Nld5nrvzzL7CeizfDi/c/q9Ss - DEMVVzi6FL0u0psXvNcGIJ41pN2RhfcDRDpv4QmI5LIy3fUtDMCrIsY3s8B9rxWA - bSYZt7PQB+BFuA7tnXmnIFthj56rv24aUe8yC5uNmusMQ530WAoGHd0xEvY5f/WF - AgwDC9FRLmchgYQBD/9NYLTJOXjofuNQz21M5Akvap/5/TnQbQSN8/P/wdYZ1fBS - /JTxPsjgNRG8h6sa+RFyZla+iRISkRqIz91OG/Vm+UKqnkh8JB7hHsZ22+ZKgu0Y - 85QZyA1lXCmfXbPjQdBGwJhZN4t8u4y+GAwQydHL8AiTsFB+A+v1tsBodeOd6AZO - njj0LjMJflaFm37y50UTobVhuHi4FnKbnvdonc2k26ZgJRndyKiop/tV21mh49mQ - VwMETXOhFijw+OfVdsZWepP6Zz43WgUE2KFERXtI/mQuHFXm+R9SXWM2tpWpKbqh - TXCy4IW0VaYz4bHU4dvLTngtMvKZdw1DiCTkGjl3oS8LGEHObJmfaptd895QnKjW - UsSSZuU4QtXpPWkfDO/0q2HMLr8OgHuTegeeADnOrrw3DQQnaJgEzkr80tnAyZgD - Bjeg3SUnWilPY01sEs1LQ/BIvqMG8Kcc96wuuzw+8vRppuLovb4g7WpSlKwNq2G3 - oqPnuuZaKTtsKinv8PXm5o/BOxAlP7sWt98Z36pFaXhGWCX9pARK62JsLntoYYuz - +uWY2vmjrMGABxLioZmfdfYWlPmecu7Rd6K4u20PJiGSPkjakHUMjAYP9C08J4UM - 52RibILrAVQJVtlmspiigl2ia46P5J3sEN6ro6iKpMrhFrXC26b0YSM0rCh0RtJe - AbHXr5XqUZJcrdoaSQ/N2klHjqozYPwDE9ppivf4yMY9bv6dX1VgQg/pB1v8Z3ea - xgGWOZLo52h/WZEAr6D2+rEjeEVCNOswcBmqU7mPv4YcyrIwBLJ6vw/+5Hyo8Q== - =1Usp - -----END PGP MESSAGE----- - fp: 4BE7925262289B476DBBC17B76FD3810215AE097 - unencrypted_suffix: _unencrypted - version: 3.11.0 diff --git a/hosts/nixos/x86_64-linux/summers/secrets/secrets.yaml b/hosts/nixos/x86_64-linux/summers/secrets/secrets.yaml index f1ff4a4..18099db 100644 --- a/hosts/nixos/x86_64-linux/summers/secrets/secrets.yaml +++ b/hosts/nixos/x86_64-linux/summers/secrets/secrets.yaml @@ -1,62 +1,10 @@ -resticpw: ENC[AES256_GCM,data:duM1dMkCRdckaOg=,iv:mPRxC5KgBMHRUcgHJQTfLA9P5EfGwnbnfzCp8CNIr9o=,tag:VZlFcaVnm4eay+JM0Sd7cA==,type:str] -resticaccesskey: ENC[AES256_GCM,data:Jt4uKdD7WqjaRjnKLeJhYoFSTtpwqPuARw==,iv:s1Ff5h2uKVxZY0hIZObZLXDlxgoUIFTYSiO17JKPUWY=,tag:DenvTp2ny8i+XjgTF3MPNA==,type:str] -resticsecretaccesskey: ENC[AES256_GCM,data:ijvux8Uldkct48gqVIC+jtfJ8m2oQ8ZbIZUZbyY79A==,iv:BxC2CZ87hxZhf35xqLe4ArGO8EnsYCABmiN+OM7t6tk=,tag:I61Ne5ztK5CUDUu+yvBcig==,type:str] +resticpw-SwarselState: ENC[AES256_GCM,data:rJrpeiNxdGZ3NF0=,iv:NHf5tp9h9lHDzTNogFkzhyBXgJVSbawT45sSvlSn27c=,tag:D36aXm3Q09cFiaNuJjL9SQ==,type:str] +resticpw-SwarselStorage: ENC[AES256_GCM,data:uj8smcKXrOzm+Sc=,iv:ASXoj5ZDgW26ri4LpxtbyUbPoc1IvxIYxjMcM/waLus=,tag:sP1Q3561lMKXYzuDkPC3HQ==,type:str] +resticaccesskey-SwarselState: ENC[AES256_GCM,data:boY2ai1iHwjaEUXFrpQK3Jpi47GhhTF+5A==,iv:qcYJE2BidxvesBOBJU/KI0PqXCpb9Fa5fr9gRcE4ox8=,tag:XAArkrmA6n0hGxU4+3OSGA==,type:str] +resticaccesskey-SwarselStorage: ENC[AES256_GCM,data:b3pHjKJP8+pNwoR/0nj8kidtKZcqUHAkkQ==,iv:MKEV6AkkTgbZrc63DipIxPvm4pl5/elInY6N0ewl3ac=,tag:OZVUdGBq5HYCX/NL7RJgrA==,type:str] +resticsecretaccesskey-SwarselState: ENC[AES256_GCM,data:2tC7RKRQM55dekqc6DLsgZqIBQbmWJySIXCOyUjTMw==,iv:a0bjCwmFTUZcJlz9WMp2vorwm9dUxg/7ulKWtL14LiU=,tag:7jbl6AGx7dguM8GmTD6MHw==,type:str] +resticsecretaccesskey-SwarselStorage: ENC[AES256_GCM,data:yjhLY7AuW3m5tOqfiAt6IbVHTnGkzSGzjkoqWD3wvQ==,iv:+2/dSke3LlWQpWa8adNS65M2sbfNw7DbiFCruMHnBRU=,tag:XgV4J9/c5yg0X1eBN1myXQ==,type:str] wireguard-private-key: ENC[AES256_GCM,data:lP5wnI1YUSb2PJUo8LvCogz0gfwwnqgYtNEly2i8P4geQVGnsxCz2c0ZKgM=,iv:55gjJ2K15EB8i9iwNNsuKwzHZsX3RvsTKNAnr+Ac4to=,tag:GPscRLTJSj+TNJ/15pM1mw==,type:str] -#ENC[AES256_GCM,data:D3AMwX0rBg==,iv:4AaUSc9Swp4RJIqeNzTW7MvAi5cZ3c53alWY3P4wS5U=,tag:IUzpcX38+495WM3O7L0uGQ==,type:comment] -kavita-token: ENC[AES256_GCM,data:coBAnDN4tWB0b05z+SRv8tGau+KrvMbEBICpPPYrjAqS/jVIrsKfpiVp+jJ2ruKnrwFnE8aVzWMB423fFk/GzpLDJZHF7oPjlr5QQVsGQ+NP7Ls7lAu6/A==,iv:pk+sZqRcx+WgS0Nwa4z4I2RmTobL7QME8E77bYdlcsw=,tag:XJ46v//ploErgSNLlUfPBg==,type:str] -#ENC[AES256_GCM,data:KxuybG2VSA==,iv:5HnK8dQsTW+shG+EzGh9BomfoBGl5cdSQpZjD4OF8y4=,tag:S2EgHIoHyXpxpU48hWiiYQ==,type:comment] -matrix-shared-secret: ENC[AES256_GCM,data:wCDMXzV18aFk4h1tf60N61K8j+gRJxIfbQLvqbfoDWPH2gbuNsg3SfDyFgDZQUzAzfaYC+jcbUAFOPm7ZD6axQ==,iv:9Rpx5jHyxqoyLSD39zPopj7m5ZZcPIhiRTh9tZXIero=,tag:JQg1uOorQvN3m7Cm6fT0vA==,type:str] -mautrix-telegram-as-token: ENC[AES256_GCM,data:/34XoVkm/8o84PUDXGWzFphEu+0LyvfEo+HOEbEB5GfrHzJmPpWgdGmedAYLpupvOzWWjODXgNk0zC3l4a+4gQ==,iv:7AdLQ3/SCJM9VxEFOBZnmVWKeSDTKyFLq+dysahlErI=,tag:NP/iV6aVZLy4RFOK1OqOPA==,type:str] -mautrix-telegram-hs-token: ENC[AES256_GCM,data:6je3dFrFAoNCbUuZD7C+kMoQpNeqBxoUusEJBFM0IYcVAqsmclMktHWLFDerkfzgGmKverqnf+rINDVEX8Df5A==,iv:iDqeYSsw1OTxu4K+zAEU+eUz+TLnXSzXbr6J4cLp7KQ=,tag:PBHqaqJEVEN8nk5hmIVEpQ==,type:str] -mautrix-telegram-api-id: ENC[AES256_GCM,data:R6C4gFh+NQ==,iv:30LZQR0CRmtAxqXVu/GOihdvdsWqGqiLMQJAM1yaSg0=,tag:9QM9VlCqSFuDo2k0WJx7/w==,type:str] -mautrix-telegram-api-hash: ENC[AES256_GCM,data:m6RhyLX2wNtMG/rZtLtwPVYiF9rD6bqsulJTE4tNkeA=,iv:aGq8TGQCOVlf55XfM4A9V0eDF75E8Rg8Jg+Vc72NJ00=,tag:J2fJ+Q7KToQirY87t4mvzQ==,type:str] -#ENC[AES256_GCM,data:6lE2jJal,iv:n6GbM2CZy9KSVRPJvnYYhcN81P77TUoy9ZJwplbtPLg=,tag:UaI3x5tu9meuZc2Wj+s82w==,type:comment] -acme-dns-token: ENC[AES256_GCM,data:Q5rGOFLYvCQ0h8BZKC3JlcWHp2q3ucIoE1E3NujEGoBltdUj3RpY3Q==,iv:T38LtQ02/11zlJUUahIeDNXyd9fQ7MYAOYgAY5ioLMw=,tag:5G0emN3Oje+Otl4uBxe8Ow==,type:str] -#ENC[AES256_GCM,data:XTHlwp41c52pmg==,iv:P82FtV4f+KziNF5QNca/xx8ZvdeZu+4tQmtePvjhKGU=,tag:AdVhiRLboyDT3jaSBjD0Mw==,type:comment] -paperless-admin-pw: ENC[AES256_GCM,data:mfk+N/cxddgUiandSNIYvbt0X1nDLaWOzw==,iv:CbHsz5ldL4sdnMCghh5DFbIBeR7e7c8ftuB3cTRBXBQ=,tag:SGk6QsUO7+H30Mi8fFuaRQ==,type:str] -kanidm-paperless-client: ENC[AES256_GCM,data:9mqdKyyuPyezSiNIVBe4/ViHydfkfZmAiA==,iv:frksTnlKbIHG1XdXUTQwKHLtlpRdZeQOOCBFRQ9DY1o=,tag:DBUy4xV0drIxXL9IxV30/w==,type:str] -#ENC[AES256_GCM,data:4n9xtQ==,iv:Qa+X5jJ/PQLkEB/EdRoB6pic642twVkt8zTIkHLOGz8=,tag:cZP9TyLPNACeHRMqTsRnlw==,type:comment] -mpd-pw: ENC[AES256_GCM,data:umt4fAgqaLBIXLhLLGUAay/YbSKC2r4uZA==,iv:yBOe8MpJZGrko30+zmP6LYI7uPJvQUf9+KhZAsSKk90=,tag:JWpGwG5trY/kLyQo707jDQ==,type:str] -#ENC[AES256_GCM,data:mHqhDMd0XorN,iv:LFGTMK375H8QenyYVSSF0IfummbSa6XPSCrrQryy0/8=,tag:r7qqAYPVfVkgZXObQLYMGQ==,type:comment] -nextcloud-admin-pw: ENC[AES256_GCM,data:WIS+dK+6sNa8l9sfqILcVXpI,iv:pAOX6uUusKKOGrzHzij6tNOHJkacxyac/YFbU8ZmFhY=,tag:NQByvZhCu1qf1Qb/Eor0sA==,type:str] -kanidm-nextcloud-client: ENC[AES256_GCM,data:qEamdf1+i9Je6l2uswgDfrc/KkbLDDnZ/Q==,iv:T9g7V86o9sTIWZ6MwRg2Li2ntpR5B+DgvXbrM/pBHo0=,tag:OH4FKB6qgsdAEVb8wdkKCg==,type:str] -#ENC[AES256_GCM,data:mRjlEtwcsjs=,iv:l+6IJr+nyIUF45vhNAw84eVoypF+grcKvXa3Z4mDntI=,tag:A8guEoZcPnAzlvsbQGI1NQ==,type:comment] -grafana-admin-pw: ENC[AES256_GCM,data:OZRhYLC8mKGT1dLpYNA=,iv:JWLDUXsHEgISVX5qPOY/SyEyMbd1wBPRcX4aB9V1VY4=,tag:UnM7Ki9rqcv+QKEkbD5geQ==,type:str] -prometheus-admin-pw: ENC[AES256_GCM,data:zKtPGDIDN/pJxdRuQthIOkvVgjmx+FrEcA==,iv:M/gY7JGCcf3qOR3abTOhW4oK+cEZ+qrA7Ej1dXXWXnU=,tag:LD4faKNGJnJSPv0w2UtCqw==,type:str] -kanidm-grafana-client: ENC[AES256_GCM,data:wIPvYpMuT3cJKImJ/NrvfZg4u841DQNjow==,iv:BMIrNgd5p5kaQOqC7GyCz6tF76HOx7GHJ5TcWL/Qeaw=,tag:pfhys3Q1WBzv8lcaz4gSZA==,type:str] -#ENC[AES256_GCM,data:jWNwieXkgftTIg==,iv:3fYUvETktHqHxg1MR2ZK6Bkz4DGjILS7gIU7taGj534=,tag:cLIde4jkQUo2kZ1nxACQ2A==,type:comment] -freshrss-pw: ENC[AES256_GCM,data:+jKVUjkpNCjGSgE=,iv:SZu/AZxue9Y4xEdrAEHkwzuoL7THI6MS8YQFwcoRPMI=,tag:M/iBUKcKe1d6gW1cUpeBew==,type:str] -freshrss-oidc-crypto-key: ENC[AES256_GCM,data:bsnB53+pm+1AlPx6kvQ46GUtocDZJW2+MyJDC7tuSbgY3hnFOhmbbQ==,iv:9gF7OLOTxva4znYIEsdvrfI9JFPhuFucuH3oK9Rj3f8=,tag:TY7QfUpI1GmkNYXDNyl4zQ==,type:str] -kanidm-freshrss-client: ENC[AES256_GCM,data:7CO/LL3uKxQHFjfC3VR4JfL13hT7T/OG5w==,iv:Q5BZSrxMgUM5dXKKLeTXG/kWUgFb1RCmUQSg+B0H32w=,tag:gX2O/2l9XFk2r9HfGzWliA==,type:str] -#ENC[AES256_GCM,data:fs3hYmSnPA==,iv:AO/BtxZ//pNQESSDYSUZzSWc1daj6aa2vXteC04HivI=,tag:HfRZ2YUWO2XNtjN8IZMmvQ==,type:comment] -kanidm-admin-pw: ENC[AES256_GCM,data:OF7rhjmg0I7V5qc2nWfQzSAIMlowXapbvg==,iv:I3Ig16YFPP2BeoAdYmRLQe8fqdV/MC+GW3T61kNiftY=,tag:n/WcJsNejgoZIK4GmnaPlA==,type:str] -kanidm-idm-admin-pw: ENC[AES256_GCM,data:UdGmzkgeDVWzFR+jqmwzxB2U0yjbOMf5ZQ==,iv:dB1rS0d7/hgA4UGSu/P2OIu43PHZbif3UkNd9vZ962Y=,tag:6mYDZUcobB0Vi/sZ+nOt/g==,type:str] -kanidm-immich: ENC[AES256_GCM,data:9vIcSVknbeitmmj5SVWcfOkji+0tTyvEJA==,iv:cMorkTF7swSLShonZqkuPl2RfrGBOQVnR2XTFr8Rwy0=,tag:BK4QRnCsxNPpdqQk03ghMw==,type:str] -kanidm-paperless: ENC[AES256_GCM,data:IjB3ZySYVS3OZU3pq4dE4qzm4F3enTEwYw==,iv:UZyYN5zyyvsAwLf55mAw32/CdygYbtfZvQY6BBzlchE=,tag:Tz3TOqf7oIyw1j414bvHDw==,type:str] -kanidm-forgejo: ENC[AES256_GCM,data:hDPeC5CPg2yHvxtw5Z6uIwr9TtiJM+PjGg==,iv:+pEDpmePUbbH9H5edZ5IPPXY1g2Daw8lLgyDM+h/0Zc=,tag:tugJxGP2LTYrHnNKb4/wgg==,type:str] -kanidm-grafana: ENC[AES256_GCM,data:+tfJr1mrfD7Kza9R26av7G+QgzzQhjeUmw==,iv:StWa8qivQZFhA1V5pSskeXL2IF8QkZd/tdOdAmWJLL8=,tag:U5A137+ACOWl1LdmLwb+xA==,type:str] -kanidm-nextcloud: ENC[AES256_GCM,data:yTBSlSN7O+ywGB6j8dvORE8C3xabayg3NA==,iv:kprbm7NR/ukczINENzdLOgBl2fwSs1CWkW+XFmLYxTw=,tag:U1fwlVRwcJBMbxCPAqovBg==,type:str] -kanidm-oauth2-proxy: ENC[AES256_GCM,data:Wj+tqtfxI/JDZwM8dFKvWaq6P5xrdPeszw==,iv:9WNcoLs4zMzVgGAMIanS8IAJKZU/IV9AY4YXw8gsl4c=,tag:JTZMI7xmzlVbpoN7T35bJA==,type:str] -kanidm-freshrss: ENC[AES256_GCM,data:pO6j+ZAD8NXUiHMZ5jg1Dsu6OcFr8BUIfQ==,iv:2vxDhyGqafbOBLsmQFuiBVN/2H4h2ZIJfG7h4iV/dIE=,tag:cYO2ANzUMAwVBiq87SQ0wA==,type:str] -kanidm-firezone: ENC[AES256_GCM,data:5QcRJy1kn1bk8zBqPznyq6vHHukmIIQpiQ==,iv:GL0QkqhsgRIeE+1rIDqVuC+UyIKPJTu5AHALBMZq2Yg=,tag:+kF/HQexEgg6JJyv3LeGvw==,type:str] -#ENC[AES256_GCM,data:nkfK+2JT/zAFEN5r,iv:zhequNAlsknCC1ROXYm+tzaUy6mN6XmuqS13Q6HU0a0=,tag:FQw0dwMR/yitjGSFWW6/RQ==,type:comment] -firefly-iii-app-key: ENC[AES256_GCM,data:1jLFVD8tMVF9hYiNeUZn1ZpPcKuvpYEZxLJcylg415PXl7ngmDa6H3ruYKFk/rt0sjh7,iv:uFBKrNOa5NdHWsLW5knd16tF0HQH7j4nsoF2TGEcrl0=,tag:X61hLERJNS//sSkhtkBEwA==,type:str] -#ENC[AES256_GCM,data:ZeR7BLj26KJabuQx,iv:Fp8Etgu5tg9xmqT421n7vvQvL27evPslZmVgIiGCGDs=,tag:DjirUtjNCh09D2JGJXqaYQ==,type:comment] -koillection-env-file: ENC[AES256_GCM,data:G/Nwzw5wQAr7aUfM+JclpmXaVwLKr9DV4M0F69Sya1U=,iv:gAYrD2XFKl0gWyU0wQ2JU0Vrn9bXVLJf5p1HdunZxqw=,tag:y64flWvqJ2KGETBnnnSDOw==,type:str] -koillection-db-password: ENC[AES256_GCM,data:vKHnmcvSOKhHOt6Mdbw+uT7GdM8=,iv:/pHI4ficUG81gkAUTATUt1SLDxiWYZoONqXUrIuEjcM=,tag:2kRNBut9P8qSGvy1D5mJzA==,type:str] -#ENC[AES256_GCM,data:QgzAs3Xq1wgb10RNZzl0uJA=,iv:oCIr3yh3iiaskY1en7QPZvRGhC4wmzGI2MQ9qJ1FoW0=,tag:Fjcr+5Xz3gmEckizaUczgQ==,type:comment] -anki-pw: ENC[AES256_GCM,data:TGKLFfBD9UEZlvc=,iv:8GsOAxr7DI4uEsGREfsbRPA6p6/7Jl9oUXWpCmobBZ4=,tag:ZpmubPgfwmLw817sMpHRcg==,type:str] -#ENC[AES256_GCM,data:g1yoM9Q8wfA=,iv:Gj/srSIg6aI0lybHMQGu8wu2KfvzdKJ3XetoTaZwJpg=,tag:N1lqDLoqhiT7YNu4hyvwmw==,type:comment] -kanidm-forgejo-client: ENC[AES256_GCM,data:eQwwaqdWAHQ+1HgfKtx9v/5kT1rzbFfUhA==,iv:HKylHTkifgSIuq4tKPIsyOzDCn5ynl66/PLDyWW/pEQ=,tag:k3ZjA0BvdLvpbogq+e9JUQ==,type:str] -#ENC[AES256_GCM,data:7ZIGRjWPgI9l,iv:YXDxvRZ9SPO9cJBsGQ2T1i5DojjaghrlF5h53ECgukE=,tag:uXvmB3kINl4jg+18OoSpHA==,type:comment] -radicale-user: ENC[AES256_GCM,data:jsrSPQ9bk5IPSaw=,iv:4o4BYlQlWONCv5M51C1EhgbxGvg8Bir/rIdMjGO+yeo=,tag:oxrSuJS9LKRQurSM+0gfYg==,type:str] -#ENC[AES256_GCM,data:MiKHFUmTDvnrjhw=,iv:Y72pVFthqLq+LVj5bmy7dNDvXMxvTtFPEHSAfB1Dcoo=,tag:802/jEiC4zWXmvjXPwSYEw==,type:comment] -prometheus-admin-hash: ENC[AES256_GCM,data:Zp2yXBiFudvD75Yupi5mjQwL5wai+atnJ0ltzM+TnzFNzFgYv8hdilsxYSD0VDo6CZJWhEtp9ozfiETs,iv:jidoobYusa5RfAZfcdVSNj5yKBJvlRRCfcN7MYkN6Ko=,tag:2tYV/SFajv9VE+lIOuH/5w==,type:str] -snipe-it-appkey: ENC[AES256_GCM,data:6nsXRMr2Fr7e0b/0WJS7ntlg5HEedGMCGe/69kwfyb6llSp4Pn1H4eQc0Mk=,iv:ZtL9tTNZhUT+YL7Ps7ZyUBKd5W0i7ZZAeqyZbJB6ELs=,tag:nJnqHXg6OhQhRnRtraW3bA==,type:str] -snipe-it-db-password: ENC[AES256_GCM,data:Jpk3Ka4/Fk3CMdUZDf1SbaUbGbmkYl1L2YvEpGR/H4kq32Q=,iv:7t4bM8c2huTEYxUJDxu72dTueiGNOzwFjoedcQK5hdY=,tag:IHXqtICjjd4O/9MqqCyu2Q==,type:str] -#ENC[AES256_GCM,data:Z2MArzHJ5g==,iv:5IFG5SSmOOQU8hUiwLXG2UBRbPmgeq09/XU7UcPqoDc=,tag:93YLtbQgBMdDWCSl5BUVvw==,type:comment] -garage-admin-token: ENC[AES256_GCM,data:XZ4OVmqy4O2+NBqV+TlVCYb9Lk5bNoKFLcCNaNIRv0YEKcIgAlnL3bTuIaw=,iv:KvYTpvnmupx5DIVIh/EkKPkX3yr/3eLMzWB1vA5KM9k=,tag:L+kMrGSHXUsEqH0oFuBB2Q==,type:str] -garage-rpc-secret: ENC[AES256_GCM,data:uTLsZv1viatNX3f1qdDvFDKfVRgDDLv2+AUHCPo3lx/cUiB9HMcuUHJoNP8sLeuX77WXon29ZKMd5fKnydo77g==,iv:IJgDZZkA4QQfOWTWh7OLtWRZi0yE4dKE0BoJCqopWl8=,tag:wh9aWZhEehHx0nQ8UBBNKg==,type:str] sops: age: - recipient: age14sjyqch8tzqexk2gv0qgrrg09f0s6hvwhsgjac3vs6sc5rzgpcxsyqda6u @@ -68,8 +16,8 @@ sops: cUpZZzBOZHlZdzRoS0l4SkRER1JQeTQKBeYA2sVQab9moaYlT0jE7/zMJvOJoC7V QwHXwnkjZCavAC5HIn82PzJ0DNrMKSZ136AgA+F99X0ZFyFnEIFZCQ== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-01-10T11:56:45Z" - mac: ENC[AES256_GCM,data:3Y124JX/6MsyIeOv9t0DPSv6YUICgvQn688LpXvW2jSWYRuJCbSWG67cPQHCNYP3NjFWXuASlKhDRJQicwgamh3WrE7gC7QxtqCVtwL0FTfZeOQ+vRoIejWIldcKC3YK6vKYW/O//Uhd+5rG8ah2b7XqRvgv8bwIdUKFUQqG0EA=,iv:VfsIS6+QTbv4WhykReXOGkGul7dWj0Voux2vrkv6Ecw=,tag:h7zZqbe4NAZ0PlcWBq0r2w==,type:str] + lastmodified: "2026-01-19T14:12:00Z" + mac: ENC[AES256_GCM,data:VsZDoY88nMtY6S87Odi641VrenfVOraWDgfGuKVKKrcUJtTTF4hkwI5b8dZ4Qz/9g4IxW0Siht8qodqAEnA5bvDbMlabIgIRrbO4hAJjPYEtD3Q+J2n8PVvWLU94DusgN0A4rHXbEq1Am2bUjcXKWOg2FpkUGrkJyYfj6R4l6kk=,iv:ZPMPs71eoiEddKTDwIZbYUziKDVknXGMyw062i3X3oU=,tag:IiXOOiJzuN4M1jU6dZdTJg==,type:str] pgp: - created_at: "2026-01-10T00:38:27Z" enc: |- diff --git a/hosts/nixos/x86_64-linux/winters/default.nix b/hosts/nixos/x86_64-linux/winters/default.nix index a167da3..570ccfb 100644 --- a/hosts/nixos/x86_64-linux/winters/default.nix +++ b/hosts/nixos/x86_64-linux/winters/default.nix @@ -41,26 +41,6 @@ serverName = "hintbooth"; }; }; - restic = { - bucketName = "SwarselWinters"; - paths = [ - "/Vault/data/paperless" - "/Vault/data/koillection" - "/Vault/data/postgresql" - "/Vault/data/firefly-iii" - "/Vault/data/radicale" - "/Vault/data/matrix-synapse" - "/Vault/Eternor/Paperless" - "/Vault/Eternor/Bilder" - "/Vault/Eternor/Immich" - ]; - }; - garage = { - data_dir = { - capacity = "200G"; - path = "/Vault/data/garage/data"; - }; - }; }; }; @@ -72,35 +52,6 @@ swarselmodules.server = { diskEncryption = lib.mkForce false; - # nginx = true; # for php stuff - # acme = false; # cert handled by proxy - # wireguard = true; - - # nfs = true; - # kavita = true; - # restic = true; - # jellyfin = true; - # navidrome = true; - # spotifyd = true; - # mpd = true; - # postgresql = true; - # matrix = true; - # nextcloud = true; - # immich = true; - # paperless = true; - # transmission = true; - # syncthing = true; - # grafana = true; - # freshrss = true; - # kanidm = true; - # firefly-iii = true; - # koillection = true; - # radicale = true; - # atuin = true; - # forgejo = true; - # ankisync = true; - # homebox = true; - # opkssh = true; }; networking.nftables.firewall.zones.untrusted.interfaces = [ "lan" "enp3s0" ]; diff --git a/modules/nixos/client/uwsm.nix b/modules/nixos/client/uwsm.nix index 5c9d66e..2304d27 100644 --- a/modules/nixos/client/uwsm.nix +++ b/modules/nixos/client/uwsm.nix @@ -1,6 +1,7 @@ -{ lib, config, ... }: +{ lib, config, pkgs, ... }: let moduleName = "uwsm"; + cfg = config.programs.uwsm; in { options.swarselmodules.${moduleName} = lib.mkEnableOption "${moduleName} settings"; @@ -20,5 +21,39 @@ in }; }; }; + + services.displayManager.sessionPackages = + let + mk_uwsm_desktop_entry = + opts: + (pkgs.writeTextFile { + name = "${opts.name}-uwsm"; + text = '' + [Desktop Entry] + Name=${opts.prettyName} (UWSM) + Comment=${opts.comment} + Exec=${lib.getExe cfg.package} start -F -- ${opts.binPath} ${lib.strings.escapeShellArgs opts.extraArgs} + Type=Application + ''; + destination = "/share/wayland-sessions/${opts.name}-uwsm.desktop"; + derivationArgs = { + passthru.providedSessions = [ "${opts.name}-uwsm" ]; + }; + }); + in + lib.mkForce (lib.mapAttrsToList + ( + name: value: + mk_uwsm_desktop_entry { + inherit name; + inherit (value) + prettyName + comment + binPath + extraArgs + ; + } + ) + cfg.waylandCompositors); }; } diff --git a/modules/nixos/common/users.nix b/modules/nixos/common/users.nix index e6c11a4..be4d0b4 100644 --- a/modules/nixos/common/users.nix +++ b/modules/nixos/common/users.nix @@ -15,6 +15,18 @@ isNormalUser = true; uid = 1000; autoSubUidGidRange = false; + subUidRanges = [ + { + count = 65534; + startUid = 100001; + } + ]; + subGidRanges = [ + { + count = 999; + startGid = 1001; + } + ]; description = "Leon S"; password = lib.mkIf (minimal || config.swarselsystems.isPublic) "setup"; hashedPasswordFile = lib.mkIf (!minimal && !config.swarselsystems.isPublic) config.sops.secrets.main-user-hashed-pw.path; diff --git a/modules/nixos/optional/microvm-guest.nix b/modules/nixos/optional/microvm-guest.nix index 28c8c91..73e0794 100644 --- a/modules/nixos/optional/microvm-guest.nix +++ b/modules/nixos/optional/microvm-guest.nix @@ -32,8 +32,6 @@ # NOTE: this is needed, we dont import sevrer network module for microvms globals.hosts.${config.node.name}.isHome = true; - fileSystems."/persist".neededForBoot = lib.mkForce true; - systemd.network.networks."10-vlan-services" = { dhcpV6Config = { WithoutRA = "solicit"; diff --git a/modules/nixos/server/ankisync.nix b/modules/nixos/server/ankisync.nix index 65e928f..3585ec4 100644 --- a/modules/nixos/server/ankisync.nix +++ b/modules/nixos/server/ankisync.nix @@ -36,6 +36,10 @@ in }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/private/${serviceName}"; }]; + }; + services.anki-sync-server = { enable = true; port = servicePort; diff --git a/modules/nixos/server/atuin.nix b/modules/nixos/server/atuin.nix index 19b706c..351139f 100644 --- a/modules/nixos/server/atuin.nix +++ b/modules/nixos/server/atuin.nix @@ -7,6 +7,10 @@ in options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { + swarselmodules.server = { + postgresql = true; + }; + topology.self.services.${serviceName}.info = "https://${serviceDomain}"; globals = { diff --git a/modules/nixos/server/firefly-iii.nix b/modules/nixos/server/firefly-iii.nix index cf77b73..2f952c2 100644 --- a/modules/nixos/server/firefly-iii.nix +++ b/modules/nixos/server/firefly-iii.nix @@ -42,12 +42,16 @@ in homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + services = { ${serviceName} = { enable = true; user = serviceUser; group = if cfg.enableNginx then nginxGroup else serviceGroup; - dataDir = "/Vault/data/${serviceName}"; + dataDir = "/var/lib/${serviceName}"; settings = { TZ = config.repo.secrets.common.location.timezone; APP_URL = "https://${serviceDomain}"; diff --git a/modules/nixos/server/forgejo.nix b/modules/nixos/server/forgejo.nix index 5ae8125..146ac7c 100644 --- a/modules/nixos/server/forgejo.nix +++ b/modules/nixos/server/forgejo.nix @@ -44,9 +44,13 @@ in }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + services.${serviceName} = { enable = true; - stateDir = "/Vault/data/${serviceName}"; + stateDir = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; lfs.enable = lib.mkDefault true; diff --git a/modules/nixos/server/freshrss.nix b/modules/nixos/server/freshrss.nix index df0a809..bdae10f 100644 --- a/modules/nixos/server/freshrss.nix +++ b/modules/nixos/server/freshrss.nix @@ -61,6 +61,10 @@ in homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + services.${serviceName} = let inherit (config.repo.secrets.local.freshrss) defaultUser; @@ -71,7 +75,7 @@ in virtualHost = serviceDomain; baseUrl = "https://${serviceDomain}"; authType = "form"; - dataDir = "/Vault/data/tt-rss"; + dataDir = "/var/lib/freshrss"; passwordFile = config.sops.secrets.freshrss-pw.path; }; diff --git a/modules/nixos/server/homebox.nix b/modules/nixos/server/homebox.nix index 5325cce..b076405 100644 --- a/modules/nixos/server/homebox.nix +++ b/modules/nixos/server/homebox.nix @@ -1,6 +1,6 @@ { self, lib, pkgs, config, globals, dns, confLib, ... }: let - inherit (confLib.gen { name = "homebox"; port = 7745; }) servicePort serviceName serviceDomain serviceAddress proxyAddress4 proxyAddress6; + inherit (confLib.gen { name = "homebox"; port = 7745; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6; inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules; in { @@ -13,6 +13,10 @@ in icon = "${self}/files/topology-images/${serviceName}.png"; }; + swarselmodules.server = { + postgresql = true; + }; + users.persistentIds = { homebox = confLib.mkIds 981; }; @@ -33,14 +37,14 @@ in }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + systemd.services.homebox = { environment = { TMPDIR = "/var/lib/homebox/.tmp"; - }; - serviceConfig = { - # ReadWritePaths = "/var/lib/homebox"; - RuntimeDirectory = "homebox"; - BindPaths = "/run/homebox:/var/lib/homebox/.tmp"; + HOME = "/var/lib/homebox"; }; }; diff --git a/modules/nixos/server/id.nix b/modules/nixos/server/id.nix index f6db715..fa67280 100644 --- a/modules/nixos/server/id.nix +++ b/modules/nixos/server/id.nix @@ -15,59 +15,61 @@ in { options = { swarselmodules.server.ids = lib.mkEnableOption "enable persistent ids on server"; - users.persistentIds = mkOption { - default = { }; - description = '' - Maps a user or group name to its expected uid/gid values. If a user/group is - used on the system without specifying a uid/gid, this module will assign the - corresponding ids defined here, or show an error if the definition is missing. - ''; - type = types.attrsOf ( - types.submodule { - options = { - uid = mkOption { - type = types.nullOr types.int; - default = null; - description = "The uid to assign if it is missing in `users.users.`."; + users = { + persistentIds = mkOption { + default = { }; + description = '' + Maps a user or group name to its expected uid/gid values. If a user/group is + used on the system without specifying a uid/gid, this module will assign the + corresponding ids defined here, or show an error if the definition is missing. + ''; + type = types.attrsOf ( + types.submodule { + options = { + uid = mkOption { + type = types.nullOr types.int; + default = null; + description = "The uid to assign if it is missing in `users.users.`."; + }; + gid = mkOption { + type = types.nullOr types.int; + default = null; + description = "The gid to assign if it is missing in `users.groups.`."; + }; }; - gid = mkOption { - type = types.nullOr types.int; - default = null; - description = "The gid to assign if it is missing in `users.groups.`."; - }; - }; - } - ); - }; - - users.users = mkOption { - type = types.attrsOf ( - types.submodule ( - { name, ... }: - { - config.uid = - let - persistentUid = cfg.${name}.uid or null; - in - mkIf (persistentUid != null) (mkDefault persistentUid); } - ) - ); - }; + ); + }; - users.groups = mkOption { - type = types.attrsOf ( - types.submodule ( - { name, ... }: - { - config.gid = - let - persistentGid = cfg.${name}.gid or null; - in - mkIf (persistentGid != null) (mkDefault persistentGid); - } - ) - ); + users = mkOption { + type = types.attrsOf ( + types.submodule ( + { name, ... }: + { + config.uid = + let + persistentUid = cfg.${name}.uid or null; + in + mkIf (persistentUid != null) (mkDefault persistentUid); + } + ) + ); + }; + + groups = mkOption { + type = types.attrsOf ( + types.submodule ( + { name, ... }: + { + config.gid = + let + persistentGid = cfg.${name}.gid or null; + in + mkIf (persistentGid != null) (mkDefault persistentGid); + } + ) + ); + }; }; }; config = lib.mkIf config.swarselmodules.server.ids { diff --git a/modules/nixos/server/immich.nix b/modules/nixos/server/immich.nix index 568b516..3772b59 100644 --- a/modules/nixos/server/immich.nix +++ b/modules/nixos/server/immich.nix @@ -1,12 +1,16 @@ { lib, pkgs, config, globals, dns, confLib, ... }: let - inherit (confLib.gen { name = "immich"; port = 3001; }) servicePort serviceName serviceUser serviceDomain serviceAddress proxyAddress4 proxyAddress6; + inherit (confLib.gen { name = "immich"; port = 3001; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6; inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules; in { options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { + swarselmodules.server = { + postgresql = true; + }; + users = { persistentIds = { immich = confLib.mkIds 989; @@ -36,13 +40,21 @@ in }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; } + { directory = "/var/cache/${serviceName}"; user = serviceUser; group = serviceGroup; } + { directory = "/var/lib/redis-${serviceName}"; user = "redis-${serviceUser}"; group = "redis-${serviceGroup}"; } + ]; + }; + services.${serviceName} = { enable = true; package = pkgs.immich; host = "0.0.0.0"; port = servicePort; # openFirewall = true; - mediaLocation = "/Vault/Eternor/Immich"; # dataDir + mediaLocation = "/storage/Pictures/${serviceName}"; # dataDir environment = { IMMICH_MACHINE_LEARNING_URL = lib.mkForce "http://localhost:3003"; }; diff --git a/modules/nixos/server/jellyfin.nix b/modules/nixos/server/jellyfin.nix index fcd9910..6627a68 100644 --- a/modules/nixos/server/jellyfin.nix +++ b/modules/nixos/server/jellyfin.nix @@ -1,6 +1,6 @@ { pkgs, lib, config, globals, dns, confLib, ... }: let - inherit (confLib.gen { name = "jellyfin"; port = 8096; }) servicePort serviceName serviceUser serviceDomain serviceAddress proxyAddress4 proxyAddress6; + inherit (confLib.gen { name = "jellyfin"; port = 8096; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6; inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf nginxAccessRules homeServiceAddress; in { @@ -51,6 +51,13 @@ in # openFirewall = true; # this works only for the default ports }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; } + { directory = "/var/cache/${serviceName}"; user = serviceUser; group = serviceGroup; } + ]; + }; + nodes = { ${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; diff --git a/modules/nixos/server/jenkins.nix b/modules/nixos/server/jenkins.nix index e400172..cda5315 100644 --- a/modules/nixos/server/jenkins.nix +++ b/modules/nixos/server/jenkins.nix @@ -1,6 +1,6 @@ { pkgs, lib, config, globals, dns, confLib, ... }: let - inherit (confLib.gen { name = "jenkins"; port = 8088; }) servicePort serviceName serviceDomain serviceAddress proxyAddress4 proxyAddress6; + inherit (confLib.gen { name = "jenkins"; port = 8088; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6; inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules; in { @@ -23,13 +23,17 @@ in }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + services.jenkins = { enable = true; withCLI = true; port = servicePort; packages = [ pkgs.stdenv pkgs.git pkgs.jdk17 config.programs.ssh.package pkgs.nix ]; listenAddress = "0.0.0.0"; - home = "/Vault/apps/${serviceName}"; + home = "/var/lib/${serviceName}"; }; nodes = { diff --git a/modules/nixos/server/kanidm.nix b/modules/nixos/server/kanidm.nix index 17dd259..6de8284 100644 --- a/modules/nixos/server/kanidm.nix +++ b/modules/nixos/server/kanidm.nix @@ -80,12 +80,19 @@ in }; }; - environment.persistence."/persist" = lib.mkIf config.swarselsystems.isImpermanence { - files = [ - certPathBase - keyPathBase - ]; + environment.persistence = { + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + files = [ + certPathBase + keyPathBase + ]; + }; + + "/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; }; + systemd.services."generateSSLCert-${serviceName}" = let daysValid = 3650; diff --git a/modules/nixos/server/kavita.nix b/modules/nixos/server/kavita.nix index ce6bf10..2e59d4f 100644 --- a/modules/nixos/server/kavita.nix +++ b/modules/nixos/server/kavita.nix @@ -2,7 +2,7 @@ let inherit (config.swarselsystems) sopsFile; - inherit (confLib.gen { name = "kavita"; port = 8080; }) servicePort serviceName serviceUser serviceDomain serviceAddress proxyAddress4 proxyAddress6; + inherit (confLib.gen { name = "kavita"; port = 8080; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6; inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf nginxAccessRules homeServiceAddress; in { @@ -29,6 +29,10 @@ in icon = "${self}/files/topology-images/${serviceName}.png"; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + globals = { networks = { ${webProxyIf}.hosts = lib.mkIf isProxied { @@ -50,7 +54,7 @@ in user = serviceUser; settings.Port = servicePort; tokenKeyFile = config.sops.secrets.kavita-token.path; - dataDir = "/Vault/data/${serviceName}"; + dataDir = "/var/lib/${serviceName}"; }; nodes = { diff --git a/modules/nixos/server/koillection.nix b/modules/nixos/server/koillection.nix index d7ad07c..7adf1db 100644 --- a/modules/nixos/server/koillection.nix +++ b/modules/nixos/server/koillection.nix @@ -1,6 +1,6 @@ { self, lib, config, globals, dns, confLib, ... }: let - inherit (confLib.gen { name = "koillection"; port = 2282; dir = "/Vault/data/koillection"; }) servicePort serviceName serviceUser serviceDir serviceDomain serviceAddress proxyAddress4 proxyAddress6; + inherit (confLib.gen { name = "koillection"; port = 2282; dir = "/var/lib/koillection"; }) servicePort serviceName serviceUser serviceDir serviceDomain serviceAddress proxyAddress4 proxyAddress6; inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules; serviceDB = "koillection"; @@ -46,6 +46,10 @@ in }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; }]; + }; + virtualisation.oci-containers.containers = { koillection = { image = "koillection/koillection@${containerRev}"; diff --git a/modules/nixos/server/mailserver.nix b/modules/nixos/server/mailserver.nix index b2f910c..df187e3 100644 --- a/modules/nixos/server/mailserver.nix +++ b/modules/nixos/server/mailserver.nix @@ -1,7 +1,7 @@ { self, lib, config, globals, dns, confLib, ... }: let inherit (config.swarselsystems) sopsFile; - inherit (confLib.gen { name = "mailserver"; dir = "/var/lib/dovecot"; user = "virtualMail"; group = "virtualMail"; port = 443; }) serviceName serviceDir servicePort serviceUser serviceGroup serviceAddress serviceDomain proxyAddress4 proxyAddress6; + inherit (confLib.gen { name = "mailserver"; dir = "/var/lib/dovecot"; user = "virtualMail"; group = "virtualMail"; port = 80; }) serviceName serviceDir servicePort serviceUser serviceGroup serviceAddress serviceDomain proxyAddress4 proxyAddress6; inherit (confLib.static) isHome webProxy homeWebProxy dnsServer homeServiceAddress nginxAccessRules; inherit (config.repo.secrets.local.mailserver) user1 alias1_1 alias1_2 alias1_3 alias1_4 user2 alias2_1 alias2_2 alias2_3 user3; baseDomain = globals.domains.main; diff --git a/modules/nixos/server/matrix.nix b/modules/nixos/server/matrix.nix index c77caa7..9835376 100644 --- a/modules/nixos/server/matrix.nix +++ b/modules/nixos/server/matrix.nix @@ -1,7 +1,7 @@ { self, lib, config, pkgs, globals, dns, confLib, ... }: let inherit (config.swarselsystems) sopsFile; - inherit (confLib.gen { name = "matrix"; user = "matrix-synapse"; port = 8008; }) servicePort serviceName serviceUser serviceDomain serviceAddress proxyAddress4 proxyAddress6; + inherit (confLib.gen { name = "matrix"; user = "matrix-synapse"; port = 8008; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6; inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules; federationPort = 8448; @@ -21,6 +21,10 @@ in options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { + swarselmodules.server = { + postgresql = true; + }; + environment.systemPackages = with pkgs; [ matrix-synapse lottieconverter @@ -118,9 +122,18 @@ in }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/lib/matrix-synapse"; user = serviceUser; group = serviceGroup; } + { directory = "/var/lib/mautrix-whatsapp"; user = "mautrix-whatsapp"; group = "mautrix-whatsapp"; } + { directory = "/var/lib/mautrix-telegram"; user = "mautrix-telegram"; group = "mautrix-telegram"; } + { directory = "/var/lib/mautrix-signal"; user = "mautrix-signal"; group = "mautrix-signal"; } + ]; + }; + + services = { postgresql = { - enable = true; initialScript = pkgs.writeText "synapse-init.sql" '' CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse'; CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse" @@ -147,7 +160,7 @@ in matrix-synapse = { enable = true; - dataDir = "/Vault/data/matrix-synapse"; + dataDir = "/var/lib/matrix-synapse"; settings = { app_service_config_files = let diff --git a/modules/nixos/server/monitoring.nix b/modules/nixos/server/monitoring.nix index a74489e..95a634a 100644 --- a/modules/nixos/server/monitoring.nix +++ b/modules/nixos/server/monitoring.nix @@ -47,8 +47,10 @@ in node-exporter = confLib.mkIds 987; grafana = confLib.mkIds 974; }; + groups.nextcloud-exporter = { }; users = { nextcloud-exporter = { + group = "nextcloud-exporter"; extraGroups = [ "nextcloud" ]; }; @@ -78,10 +80,17 @@ in }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; } + { directory = "/var/lib/prometheus2"; user = prometheusUser; group = prometheusGroup; } + ]; + }; + services = { ${serviceName} = { enable = true; - dataDir = "/Vault/data/${serviceName}"; + dataDir = "/var/lib/${serviceName}"; provision = { enable = true; datasources.settings = { diff --git a/modules/nixos/server/mpd.nix b/modules/nixos/server/mpd.nix index e5734f5..807135d 100644 --- a/modules/nixos/server/mpd.nix +++ b/modules/nixos/server/mpd.nix @@ -36,9 +36,13 @@ in icon = "${self}/files/topology-images/${serviceName}.png"; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = "mpd"; group = "mpd"; }]; + }; + services.${serviceName} = { enable = true; - musicDirectory = "/media"; + musicDirectory = "/storage/Music"; user = serviceUser; group = serviceGroup; network = { diff --git a/modules/nixos/server/navidrome.nix b/modules/nixos/server/navidrome.nix index c202573..0374395 100644 --- a/modules/nixos/server/navidrome.nix +++ b/modules/nixos/server/navidrome.nix @@ -76,6 +76,10 @@ in }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + services.${serviceName} = { enable = true; # openFirewall = true; @@ -83,7 +87,7 @@ in LogLevel = "debug"; Address = "0.0.0.0"; Port = servicePort; - MusicFolder = "/Vault/Eternor/Music"; + MusicFolder = "/storage/Music"; PlaylistsPath = "./Playlists"; AutoImportPlaylists = false; EnableSharing = true; diff --git a/modules/nixos/server/nextcloud.nix b/modules/nixos/server/nextcloud.nix index c91e79a..0f84490 100644 --- a/modules/nixos/server/nextcloud.nix +++ b/modules/nixos/server/nextcloud.nix @@ -27,6 +27,13 @@ in homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; } + { directory = "/var/lib/redis-${serviceName}"; user = serviceUser; group = serviceGroup; } + ]; + }; + services = { ${serviceName} = { enable = true; @@ -36,8 +43,8 @@ in }; package = pkgs."nextcloud${nextcloudVersion}"; hostName = serviceDomain; - home = "/Vault/data/${serviceName}"; - datadir = "/Vault/data/${serviceName}"; + home = "/var/lib/${serviceName}"; + datadir = "/var/lib/${serviceName}"; https = true; configureRedis = true; maxUploadSize = "4G"; diff --git a/modules/nixos/server/nfs.nix b/modules/nixos/server/nfs.nix index fb6a776..cff9b09 100644 --- a/modules/nixos/server/nfs.nix +++ b/modules/nixos/server/nfs.nix @@ -10,6 +10,12 @@ in avahi = confLib.mkIds 978; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/cache/samba"; } + ]; + }; + services = { # add a user with sudo smbpasswd -a samba = { @@ -35,7 +41,7 @@ in browseable = "yes"; "read only" = "no"; "guest ok" = "no"; - path = "/Vault/Eternor"; + path = "/storage"; writable = "true"; comment = "Eternor"; "valid users" = nfsUser; diff --git a/modules/nixos/server/nginx.nix b/modules/nixos/server/nginx.nix index 4f57d92..918da3e 100644 --- a/modules/nixos/server/nginx.nix +++ b/modules/nixos/server/nginx.nix @@ -84,8 +84,15 @@ in networking.firewall.allowedTCPPorts = [ 80 443 ]; - environment.persistence."/persist" = lib.mkIf config.swarselsystems.isImpermanence { - files = [ dhParamsPathBase ]; + environment.persistence = { + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + files = [ dhParamsPathBase ]; + }; + "/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/cache/nginx"; user = "nginx"; group = "nginx"; } + ]; + }; }; services.nginx = { diff --git a/modules/nixos/server/oauth2-proxy.nix b/modules/nixos/server/oauth2-proxy.nix index f6c6a23..0650a88 100644 --- a/modules/nixos/server/oauth2-proxy.nix +++ b/modules/nixos/server/oauth2-proxy.nix @@ -139,6 +139,10 @@ in }; }; + users = { + persistentIds.oauth2-proxy = confLib.mkIds 966; + }; + # needed for homeWebProxy networking.firewall.allowedTCPPorts = [ servicePort ]; diff --git a/modules/nixos/server/opkssh.nix b/modules/nixos/server/opkssh.nix index 597240d..6f2a4de 100644 --- a/modules/nixos/server/opkssh.nix +++ b/modules/nixos/server/opkssh.nix @@ -5,7 +5,7 @@ let kanidmDomain = globals.services.kanidm.domain; inherit (config.swarselsystems) mainUser; - inherit (config.repo.secrets.local) persons; + mailAddress = config.repo.secrets.common.mail.address4; in { options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; @@ -29,7 +29,7 @@ in authorizations = [ { user = mainUser; - principal = builtins.head persons.${mainUser}.mailAddresses; + principal = mailAddress; inherit (config.services.opkssh.providers.kanidm) issuer; } ]; diff --git a/modules/nixos/server/paperless.nix b/modules/nixos/server/paperless.nix index 0d119a5..ad1efa6 100644 --- a/modules/nixos/server/paperless.nix +++ b/modules/nixos/server/paperless.nix @@ -44,11 +44,21 @@ in }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; } + { directory = "/var/lib/redis-${serviceName}"; user = "redis-${serviceUser}"; group = "redis-${serviceGroup}"; } + { directory = "/var/lib/private/tika"; } + { directory = "/var/cache/${serviceName}"; user = serviceUser; group = serviceGroup; } + { directory = "/var/cache/private/tika"; } + ]; + }; + services = { ${serviceName} = { enable = true; - mediaDir = "/Vault/Eternor/Paperless"; - dataDir = "/Vault/data/${serviceName}"; + mediaDir = "/storage/Documents/${serviceName}"; + dataDir = "/var/lib/${serviceName}"; user = serviceUser; port = servicePort; passwordFile = config.sops.secrets.paperless-admin-pw.path; diff --git a/modules/nixos/server/pipewire.nix b/modules/nixos/server/pipewire.nix index 41a602d..d6549f2 100644 --- a/modules/nixos/server/pipewire.nix +++ b/modules/nixos/server/pipewire.nix @@ -6,6 +6,10 @@ users.persistentIds.rtkit = confLib.mkIds 996; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/pipewire"; user = "pipewire"; group = "pipewire"; }]; + }; + services.pipewire = { enable = true; pulse.enable = true; diff --git a/modules/nixos/server/podman.nix b/modules/nixos/server/podman.nix index 0a27be5..f1f397b 100644 --- a/modules/nixos/server/podman.nix +++ b/modules/nixos/server/podman.nix @@ -15,6 +15,12 @@ in oci-containers.backend = "podman"; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/lib/containers"; } + ]; + }; + networking.nftables.firewall = lib.mkIf config.networking.nftables.enable { zones.podman = { diff --git a/modules/nixos/server/postgresql.nix b/modules/nixos/server/postgresql.nix index 97850c1..4cf3554 100644 --- a/modules/nixos/server/postgresql.nix +++ b/modules/nixos/server/postgresql.nix @@ -2,7 +2,7 @@ let inherit (confLib.gen { name = "postgresql"; port = 3254; }) serviceName; postgresVersion = 14; - postgresDirPrefix = if config.swarselsystems.isCloud then "/var/lib" else "/Vault/data"; + postgresDirPrefix = "/var/lib"; in { options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; @@ -22,9 +22,14 @@ in dataDir = "${postgresDirPrefix}/${serviceName}/${builtins.toString postgresVersion}"; }; }; - environment.persistence."/persist".directories = lib.mkIf (config.swarselsystems.isImpermanence && config.swarselsystems.isCloud) [ - { directory = "/var/lib/postgresql"; user = "postgres"; group = "postgres"; mode = "0750"; } - ]; + environment.persistence = { + "/persist".directories = lib.mkIf (config.swarselsystems.isImpermanence && config.swarselsystems.isCloud) [ + { directory = "/var/lib/postgresql"; user = "postgres"; group = "postgres"; mode = "0750"; } + ]; + "/state".directories = lib.mkIf config.swarselsystems.isMicroVM [ + { directory = "/var/lib/postgresql"; user = "postgres"; group = "postgres"; mode = "0750"; } + ]; + }; }; } diff --git a/modules/nixos/server/radicale.nix b/modules/nixos/server/radicale.nix index 5953bdc..25ba047 100644 --- a/modules/nixos/server/radicale.nix +++ b/modules/nixos/server/radicale.nix @@ -35,6 +35,10 @@ in topology.self.services.${serviceName}.info = "https://${serviceDomain}"; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + globals = { networks = { ${webProxyIf}.hosts = lib.mkIf isProxied { @@ -67,7 +71,7 @@ in htpasswd_encryption = "autodetect"; }; storage = { - filesystem_folder = "/Vault/data/radicale/collections"; + filesystem_folder = "/var/lib/radicale/collections"; }; }; rights = { diff --git a/modules/nixos/server/restic.nix b/modules/nixos/server/restic.nix index 2b0bd01..e56cd59 100644 --- a/modules/nixos/server/restic.nix +++ b/modules/nixos/server/restic.nix @@ -1,65 +1,88 @@ { lib, pkgs, config, ... }: let inherit (config.swarselsystems) sopsFile; + + targets = config.swarselsystems.server.restic.targets; in { options.swarselmodules.server.restic = lib.mkEnableOption "enable restic backups on server"; options.swarselsystems.server.restic = { - bucketName = lib.mkOption { - type = lib.types.str; - }; - paths = lib.mkOption { - type = lib.types.listOf lib.types.str; - }; - withPostgres = lib.mkOption { - type = lib.types.bool; - default = false; + targets = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: { + options = { + bucketName = lib.mkOption { + type = lib.types.str; + default = name; + }; + repository = lib.mkOption { + type = lib.types.str; + }; + paths = lib.mkOption { + type = lib.types.listOf lib.types.str; + }; + withPostgres = lib.mkOption { + type = lib.types.bool; + default = false; + }; + }; + })); + default = { }; }; }; + config = lib.mkIf config.swarselmodules.server.restic { sops = { - secrets = { - resticpw = { inherit sopsFile; }; - resticaccesskey = { inherit sopsFile; }; - resticsecretaccesskey = { inherit sopsFile; }; - }; - templates = { - "restic-env".content = '' - AWS_ACCESS_KEY_ID=${config.sops.placeholder.resticaccesskey} - AWS_SECRET_ACCESS_KEY=${config.sops.placeholder.resticsecretaccesskey} - ''; - }; + secrets = + lib.mkMerge (lib.mapAttrsToList + (name: _: { + "resticpw-${name}" = { inherit sopsFile; }; + "resticaccesskey-${name}" = { inherit sopsFile; }; + "resticsecretaccesskey-${name}" = { inherit sopsFile; }; + }) + targets); + + templates = + lib.mkMerge (lib.mapAttrsToList + (name: _: { + "restic-env-${name}".content = '' + AWS_ACCESS_KEY_ID=${config.sops.placeholder."resticaccesskey-${name}"} + AWS_SECRET_ACCESS_KEY=${config.sops.placeholder."resticsecretaccesskey-${name}"} + ''; + }) + targets); }; - services.restic = - let - inherit (config.repo.secrets.local) resticRepo; - in - { - backups = { - "${config.swarselsystems.server.restic.bucketName}" = { - environmentFile = config.sops.templates."restic-env".path; - passwordFile = config.sops.secrets.resticpw.path; - inherit (config.swarselsystems.server.restic) paths; + services.restic.backups = + lib.mapAttrs' + (name: target: + lib.nameValuePair target.bucketName { + environmentFile = + config.sops.templates."restic-env-${name}".path; + + passwordFile = + config.sops.secrets."resticpw-${name}".path; + + inherit (target) paths repository; + pruneOpts = [ "--keep-daily 3" "--keep-weekly 2" "--keep-monthly 3" "--keep-yearly 100" ]; + backupPrepareCommand = '' ${pkgs.restic}/bin/restic prune ''; - repository = "${resticRepo}"; + initialize = true; + timerConfig = { OnCalendar = "03:00"; }; - }; - - }; - }; - + } + ) + targets; }; } diff --git a/modules/nixos/server/router.nix b/modules/nixos/server/router.nix index 6e69770..5e9f40f 100644 --- a/modules/nixos/server/router.nix +++ b/modules/nixos/server/router.nix @@ -7,6 +7,8 @@ let }) globals.networks.home-lan.vlans; selectVLANs = vlans: map (vlan: { VLAN = globals.networks.home-lan.vlans.${vlan}.id; }) vlans; + lan1VLANs = selectVLANs [ "home" "devices" "guests" ]; + lan2VLANs = selectVLANs [ "home" "devices" "services" ]; lan3VLANs = selectVLANs [ "home" "devices" "services" ]; lan4VLANs = lan3VLANs; lan5VLANs = selectVLANs [ "home" "devices" "guests" ]; @@ -186,9 +188,9 @@ in Bridge = "br"; ConfigureWithoutCarrier = true; }; - inherit bridgeVLANs; + bridgeVLANs = lan1VLANs; }; - # wifi + # winters "30-lan2" = { matchConfig.MACAddress = config.repo.secrets.local.networking.networks.lan2.mac; linkConfig.RequiredForOnline = "enslaved"; @@ -196,7 +198,7 @@ in Bridge = "br"; ConfigureWithoutCarrier = true; }; - inherit bridgeVLANs; + bridgeVLANs = lan2VLANs; }; # summers "30-lan3" = { diff --git a/modules/nixos/server/snipe-it.nix b/modules/nixos/server/snipe-it.nix index a9c105b..3ebb784 100644 --- a/modules/nixos/server/snipe-it.nix +++ b/modules/nixos/server/snipe-it.nix @@ -44,7 +44,7 @@ in hostName = serviceDomain; user = serviceUser; group = serviceGroup; - dataDir = "/Vault/data/snipeit"; + dataDir = "/var/lib/snipeit"; database = { user = serviceUser; port = mysqlPort; diff --git a/modules/nixos/server/spotifyd.nix b/modules/nixos/server/spotifyd.nix index e5dc58d..a392313 100644 --- a/modules/nixos/server/spotifyd.nix +++ b/modules/nixos/server/spotifyd.nix @@ -27,6 +27,12 @@ in # when another user connects, the service will crash and the new user will login systemd.services.spotifyd.serviceConfig.RestartSec = lib.mkForce 1; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/cache/private/spotifyd"; } + ]; + }; + services.spotifyd = { enable = true; settings = { diff --git a/modules/nixos/server/syncthing.nix b/modules/nixos/server/syncthing.nix index 8a1945e..6998326 100644 --- a/modules/nixos/server/syncthing.nix +++ b/modules/nixos/server/syncthing.nix @@ -75,12 +75,16 @@ in }; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + services.${serviceName} = rec { enable = true; user = serviceUser; group = serviceGroup; - dataDir = lib.mkDefault "/Vault/data/${serviceName}"; - configDir = "${cfg.dataDir}/.config/${serviceName}"; + dataDir = if config.swarselsystems.isMicroVM then "/storage/Documents/syncthing" else (lib.mkDefault "/var/lib/${serviceName}"); + configDir = if config.swarselsystems.isMicroVM then "/var/lib/syncthing/.config/syncthing" else "${cfg.dataDir}/.config/${serviceName}"; guiAddress = "0.0.0.0:${builtins.toString servicePort}"; openDefaultPorts = lib.mkIf (!isProxied) true; # opens ports TCP/UDP 22000 and UDP 21027 for discovery relay.enable = false; diff --git a/modules/nixos/server/transmission.nix b/modules/nixos/server/transmission.nix index c3f8e4c..d737e38 100644 --- a/modules/nixos/server/transmission.nix +++ b/modules/nixos/server/transmission.nix @@ -1,7 +1,7 @@ { self, pkgs, lib, config, confLib, ... }: let - inherit (confLib.gen { name = "transmission"; }) serviceName serviceDomain; - inherit (confLib.static) isHome; + inherit (confLib.gen { name = "transmission"; port = 9091; }) serviceName servicePort serviceDomain; + inherit (confLib.static) isHome homeServiceAddress homeWebProxy nginxAccessRules; lidarrUser = "lidarr"; lidarrGroup = lidarrUser; @@ -96,6 +96,16 @@ in inherit isHome; }; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/lib/radarr"; user = radarrUser; group = radarrGroup; } + { directory = "/var/lib/readarr"; user = readarrUser; group = readarrGroup; } + { directory = "/var/lib/sonarr"; user = sonarrUser; group = sonarrGroup; } + { directory = "/var/lib/lidarr"; user = lidarrUser; group = lidarrGroup; } + { directory = "/var/lib/private/prowlarr"; user = prowlarrUser; group = prowlarrGroup; } + ]; + }; + services = { radarr = { enable = true; @@ -103,7 +113,7 @@ in group = radarrGroup; settings.server.port = radarrPort; openFirewall = true; - dataDir = "/Vault/data/radarr"; + dataDir = "/var/lib/radarr"; }; readarr = { enable = true; @@ -111,7 +121,7 @@ in group = readarrGroup; settings.server.port = readarrPort; openFirewall = true; - dataDir = "/Vault/data/readarr"; + dataDir = "/var/lib/readarr"; }; sonarr = { enable = true; @@ -119,7 +129,7 @@ in group = sonarrGroup; settings.server.port = sonarrPort; openFirewall = true; - dataDir = "/Vault/data/sonarr"; + dataDir = "/var/lib/sonarr"; }; lidarr = { enable = true; @@ -127,53 +137,88 @@ in group = lidarrGroup; settings.server.port = lidarrPort; openFirewall = true; - dataDir = "/Vault/data/lidarr"; + dataDir = "/var/lib/lidarr"; }; prowlarr = { enable = true; settings.server.port = prowlarrPort; openFirewall = true; }; + }; - nginx = { + nodes = { + ${homeWebProxy}.services.nginx = { + upstreams = { + transmission = { + servers = { + "${homeServiceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + radarr = { + servers = { + "${homeServiceAddress}:${builtins.toString radarrPort}" = { }; + }; + }; + readarr = { + servers = { + "${homeServiceAddress}:${builtins.toString readarrPort}" = { }; + }; + }; + sonarr = { + servers = { + "${homeServiceAddress}:${builtins.toString sonarrPort}" = { }; + }; + }; + lidarr = { + servers = { + "${homeServiceAddress}:${builtins.toString lidarrPort}" = { }; + }; + }; + prowlarr = { + servers = { + "${homeServiceAddress}:${builtins.toString prowlarrPort}" = { }; + }; + }; + }; virtualHosts = { "${serviceDomain}" = { enableACME = false; forceSSL = false; acmeRoot = null; + extraConfig = nginxAccessRules; locations = { "/" = { - proxyPass = "http://localhost:9091"; + proxyPass = "http://transmission"; extraConfig = '' client_max_body_size 0; ''; }; "/radarr" = { - proxyPass = "http://localhost:${builtins.toString radarrPort}"; + proxyPass = "http://radarr"; extraConfig = '' client_max_body_size 0; ''; }; "/readarr" = { - proxyPass = "http://localhost:${builtins.toString readarrPort}"; + proxyPass = "http://readarr"; extraConfig = '' client_max_body_size 0; ''; }; "/sonarr" = { - proxyPass = "http://localhost:${builtins.toString sonarrPort}"; + proxyPass = "http://sonarr"; extraConfig = '' client_max_body_size 0; ''; }; "/lidarr" = { - proxyPass = "http://localhost:${builtins.toString lidarrPort}"; + proxyPass = "http://lidarr"; extraConfig = '' client_max_body_size 0; ''; }; "/prowlarr" = { - proxyPass = "http://localhost:${builtins.toString prowlarrPort}"; + proxyPass = "http://prowlarr"; extraConfig = '' client_max_body_size 0; ''; diff --git a/modules/shared/config-lib.nix b/modules/shared/config-lib.nix index 4439036..bf21184 100644 --- a/modules/shared/config-lib.nix +++ b/modules/shared/config-lib.nix @@ -21,7 +21,7 @@ in confLib = rec { getConfig = if nixosConfig == null then config else nixosConfig; - gen = { name ? "n/a", user ? name, group ? name, dir ? null, port ? null, domain ? (domainDefault name), address ? addressDefault, proxy ? proxyDefault }: rec { + gen = { name ? "n/a", user ? name, group ? user, dir ? null, port ? null, domain ? (domainDefault name), address ? addressDefault, proxy ? proxyDefault }: rec { servicePort = port; serviceName = name; specificServiceName = "${name}-${config.node.name}"; @@ -88,65 +88,76 @@ in mkMicrovm = if config.swarselsystems.withMicroVMs then (guestName: - { enableStorage ? false + { eternorPaths ? [ ] , withZfs ? false , ... }: { - ${guestName} = { - backend = "microvm"; - autostart = true; - zfs = lib.mkIf withZfs { - # stateful config that should be backed up - "/state" = { - pool = "Vault"; - dataset = "guests/${guestName}/state"; - }; - # data that should be backed up - "/storage" = lib.mkIf enableStorage { - pool = "Vault"; - dataset = "guests/${guestName}/storage"; - }; - # other stuff that should only reside on disk, not backed up - "/persist" = { - pool = "Vault"; - dataset = "guests/${guestName}/persist"; - }; - }; - modules = [ - (config.node.configDir + /guests/${guestName}/default.nix) - { - node.secretsDir = config.node.configDir + /secrets/${guestName}; - node.configDir = config.node.configDir + /guests/${guestName}; - networking.nftables.firewall = { - zones.untrusted.interfaces = lib.mkIf - ( - lib.length config.guests.${guestName}.networking.links == 1 - ) - config.guests.${guestName}.networking.links; - }; - } - "${self}/modules/nixos/optional/microvm-guest.nix" - "${self}/modules/nixos/optional/systemd-networkd-base.nix" - ]; - microvm = { - system = config.node.arch; - baseMac = config.repo.secrets.local.networking.networks.lan.mac; - interfaces.vlan-services = { - mac = lib.mkForce "02:${lib.substring 3 5 config.guests.${guestName}.microvm.baseMac}:${mkDeviceMac globals.networks.home-lan.vlans.services.hosts."${config.node.name}-${guestName}".id}"; + ${guestName} = + { + backend = "microvm"; + autostart = true; + zfs = lib.mkIf withZfs + ({ + # stateful config usually bind-mounted to /var/lib/ that should be backed up remotely + "/state" = { + pool = "Vault"; + dataset = "guests/${guestName}/state"; + }; + # other stuff that should only reside on zfs, not backed up remotely + "/persist" = { + pool = "Vault"; + dataset = "guests/${guestName}/persist"; + }; + } // lib.optionalAttrs (eternorPaths != [ ]) + (lib.listToAttrs (map + # data that is pulled in externally by services, some of which is backed up externally + (eternorPath: + lib.nameValuePair "/storage/${eternorPath}" { + pool = "Vault"; + dataset = "Eternor/${eternorPath}"; + }) + eternorPaths))); + modules = [ + (config.node.configDir + /guests/${guestName}/default.nix) + { + node.secretsDir = config.node.configDir + /secrets/${guestName}; + node.configDir = config.node.configDir + /guests/${guestName}; + networking.nftables.firewall = { + zones.untrusted.interfaces = lib.mkIf + ( + lib.length config.guests.${guestName}.networking.links == 1 + ) + config.guests.${guestName}.networking.links; + }; + fileSystems = { + "/persist".neededForBoot = true; + } // lib.optionalAttrs withZfs { + "/state".neededForBoot = true; + }; + } + "${self}/modules/nixos/optional/microvm-guest.nix" + "${self}/modules/nixos/optional/systemd-networkd-base.nix" + ]; + microvm = { + system = config.node.arch; + baseMac = config.repo.secrets.local.networking.networks.lan.mac; + interfaces.vlan-services = { + mac = lib.mkForce "02:${lib.substring 3 5 config.guests.${guestName}.microvm.baseMac}:${mkDeviceMac globals.networks.home-lan.vlans.services.hosts."${config.node.name}-${guestName}".id}"; + + }; + }; + extraSpecialArgs = { + inherit (inputs.self) nodes; + inherit (inputs.self.pkgs.${config.node.arch}) lib; + inherit inputs outputs minimal; + inherit (inputs) self; + withHomeManager = false; + microVMParent = config.node.name; + globals = inputs.self.globals.${config.node.arch}; }; }; - extraSpecialArgs = { - inherit (inputs.self) nodes; - inherit (inputs.self.pkgs.${config.node.arch}) lib; - inherit inputs outputs minimal; - inherit (inputs) self; - withHomeManager = false; - microVMParent = config.node.name; - globals = inputs.self.globals.${config.node.arch}; - }; - }; }) else (_: { _ = { }; diff --git a/nix/hosts.nix b/nix/hosts.nix index 29de26e..31f7406 100644 --- a/nix/hosts.nix +++ b/nix/hosts.nix @@ -176,7 +176,7 @@ configurationsPerArch = type: minimal: mkConfigurationsPerArch type minimal; in - { + rec { nixosConfigurations = configurationsPerArch "nixos" false; nixosConfigurationsMinimal = configurationsPerArch "nixos" true; darwinConfigurations = configurationsPerArch "darwin" false; @@ -198,6 +198,17 @@ // config.darwinConfigurations // config.guestConfigurations; + guestResources = lib.mapAttrs + (name: _: + let + f = arg: lib.foldr (base: acc: base + acc) 0 (map (node: nodes."${name}-${node}".config.microvm.${arg}) (builtins.attrNames nodes.${name}.config.guests)); + in + { + mem = f "mem"; + vcpu = f "vcpu"; + }) + nodes; + "@" = lib.mapAttrs (_: v: v.config.system.build.toplevel) config.nodes; }; } diff --git a/nix/packages.nix b/nix/packages.nix index 2f2f525..3707fb6 100644 --- a/nix/packages.nix +++ b/nix/packages.nix @@ -25,7 +25,21 @@ # see https://flake.parts/module-arguments.html?highlight=modulewith#persystem-module-parameters _module.args.pkgs = import inputs.nixpkgs { inherit system; - config.allowUnfree = true; + config = { + allowUnfree = true; + + permittedInsecurePackages = [ + # matrix + "olm-3.2.16" + # sonarr + "aspnetcore-runtime-wrapped-6.0.36" + "aspnetcore-runtime-6.0.36" + "dotnet-sdk-wrapped-6.0.428" + "dotnet-sdk-6.0.428" + # + "SDL_ttf-2.0.11" + ]; + }; overlays = [ self.overlays.default ]; diff --git a/profiles/nixos/microvm/default.nix b/profiles/nixos/microvm/default.nix index 226edc7..2b88350 100644 --- a/profiles/nixos/microvm/default.nix +++ b/profiles/nixos/microvm/default.nix @@ -23,6 +23,7 @@ ssh = lib.mkDefault true; wireguard = lib.mkDefault true; dns-home = lib.mkDefault true; + opkssh = true; }; }; }; diff --git a/secrets/public/wg/ankisync.pub b/secrets/public/wg/summers-ankisync.pub similarity index 100% rename from secrets/public/wg/ankisync.pub rename to secrets/public/wg/summers-ankisync.pub diff --git a/secrets/public/wg/atuin.pub b/secrets/public/wg/summers-atuin.pub similarity index 100% rename from secrets/public/wg/atuin.pub rename to secrets/public/wg/summers-atuin.pub diff --git a/secrets/public/wg/audio.pub b/secrets/public/wg/summers-audio.pub similarity index 100% rename from secrets/public/wg/audio.pub rename to secrets/public/wg/summers-audio.pub diff --git a/secrets/public/wg/firefly.pub b/secrets/public/wg/summers-firefly.pub similarity index 100% rename from secrets/public/wg/firefly.pub rename to secrets/public/wg/summers-firefly.pub diff --git a/secrets/public/wg/forgejo.pub b/secrets/public/wg/summers-forgejo.pub similarity index 100% rename from secrets/public/wg/forgejo.pub rename to secrets/public/wg/summers-forgejo.pub diff --git a/secrets/public/wg/freshrss.pub b/secrets/public/wg/summers-freshrss.pub similarity index 100% rename from secrets/public/wg/freshrss.pub rename to secrets/public/wg/summers-freshrss.pub diff --git a/secrets/public/wg/homebox.pub b/secrets/public/wg/summers-homebox.pub similarity index 100% rename from secrets/public/wg/homebox.pub rename to secrets/public/wg/summers-homebox.pub diff --git a/secrets/public/wg/immich.pub b/secrets/public/wg/summers-immich.pub similarity index 100% rename from secrets/public/wg/immich.pub rename to secrets/public/wg/summers-immich.pub diff --git a/secrets/public/wg/jellyfin.pub b/secrets/public/wg/summers-jellyfin.pub similarity index 100% rename from secrets/public/wg/jellyfin.pub rename to secrets/public/wg/summers-jellyfin.pub diff --git a/secrets/public/wg/kanidm.pub b/secrets/public/wg/summers-kanidm.pub similarity index 100% rename from secrets/public/wg/kanidm.pub rename to secrets/public/wg/summers-kanidm.pub diff --git a/secrets/public/wg/kavita.pub b/secrets/public/wg/summers-kavita.pub similarity index 100% rename from secrets/public/wg/kavita.pub rename to secrets/public/wg/summers-kavita.pub diff --git a/secrets/public/wg/koillection.pub b/secrets/public/wg/summers-koillection.pub similarity index 100% rename from secrets/public/wg/koillection.pub rename to secrets/public/wg/summers-koillection.pub diff --git a/secrets/public/wg/matrix.pub b/secrets/public/wg/summers-matrix.pub similarity index 100% rename from secrets/public/wg/matrix.pub rename to secrets/public/wg/summers-matrix.pub diff --git a/secrets/public/wg/monitoring.pub b/secrets/public/wg/summers-monitoring.pub similarity index 100% rename from secrets/public/wg/monitoring.pub rename to secrets/public/wg/summers-monitoring.pub diff --git a/secrets/public/wg/nextcloud.pub b/secrets/public/wg/summers-nextcloud.pub similarity index 100% rename from secrets/public/wg/nextcloud.pub rename to secrets/public/wg/summers-nextcloud.pub diff --git a/secrets/public/wg/paperless.pub b/secrets/public/wg/summers-paperless.pub similarity index 100% rename from secrets/public/wg/paperless.pub rename to secrets/public/wg/summers-paperless.pub diff --git a/secrets/public/wg/postgresql.pub b/secrets/public/wg/summers-postgresql.pub similarity index 100% rename from secrets/public/wg/postgresql.pub rename to secrets/public/wg/summers-postgresql.pub diff --git a/secrets/public/wg/radicale.pub b/secrets/public/wg/summers-radicale.pub similarity index 100% rename from secrets/public/wg/radicale.pub rename to secrets/public/wg/summers-radicale.pub diff --git a/secrets/public/wg/storage.pub b/secrets/public/wg/summers-storage.pub similarity index 100% rename from secrets/public/wg/storage.pub rename to secrets/public/wg/summers-storage.pub diff --git a/secrets/public/wg/transmission.pub b/secrets/public/wg/summers-transmission.pub similarity index 100% rename from secrets/public/wg/transmission.pub rename to secrets/public/wg/summers-transmission.pub diff --git a/secrets/repo/globals.nix.enc b/secrets/repo/globals.nix.enc index 6b7aa23..2de962c 100644 --- a/secrets/repo/globals.nix.enc +++ b/secrets/repo/globals.nix.enc @@ -1,5 +1,5 @@ { - "data": "ENC[AES256_GCM,data:H426SsDhgoKaBUGAekwU+DeE00rOuaQvRWT1HukJQksnYU6FoPIC4AhV2oGZall5JwhhqnKM8IZ2QTlW/gKEBLsRwQAU0AqFKRo2ULj73TpW8HwpWyXrCTrrod499+An3NT613Xux+CZLm6nSlPAEm4xz79FwoIJs5vUThF2hhu/fKZvxdV4QWcXqoJ44cPyHRrGEPZiM+JNjPKgIehmbdqXSZrA63K9vlH7oS3lkg4jKDYSLpiLg+jzf5WQe5PTKdCO/De89vq2qwAW3hFoUTYLxFTr/41+6vpO+76MytAbOjiZDF3YG2NruuNoiq2qZyCyRQ3THbiymmL4DqmHpWa2SafxiK7uvKXf2B5XWyveH/8U4vVxFBqsboq1Ot8Tf8hxV+ZO5sRYxL1RczOZ68CjFqfKHH4+fnvfIZRoVIsJ7J4M1r22rzZ5d4YnAFgC4z8dmRMmMXFwXv2xkKBC+Wpew5EEccEDVJ824ZcPTk7gXU1O7ZwKFkca9M9Nj1EwTfGN0x4XVv5zQAPrVUajtyJspzilIS7gDqpOTIxk56psV8EaK7cIAkuGa1XOIgH+wjJkxzXTFazG/NRuTDtwrs8y+aFDSlq1j+6hIK6+x7dQILdNTEgKSg4ItB6FlN3ZhBFZWcvF7aeKogyWLa9+uyQ3o+4V2n65MAytwg8nthAHPOK6xk3mbrIhY0AmRXgtOOKWydUGOR7ggInlGC/aeIjD831LTyjHG/rNepqQjfc4sKtkivNNNy6zp9LH++VPklzAL+T+SHoyS7X1luDyXpKD6Suyef87cfPdVNnHKRo1MKPVGIsD241994CsQ9repMS7XpTCbtiM4TpKDX2fW6W9PnR59vi3v/NjvOsVmRPsPTKqtyjDTJxcHrc2tLg4E+z2mBgdRFxGs8DsrhpNMhhhDrRSw2YrZjfejMZcKEz0W5hxTNrdLnf21ORDXC4Pj35xdWXoSbPnYCnE+2odLHJtNtPbrKsdw9QqUO5BARM7erj4ZbiVVAX3E89/Jh00xct4itofokHgDQwOGusgC7Y4PLbBbP0ZMzFFTCFd85rIagkYNx/SwEX7+wnfSAIDSunlB59Wk+sP6kDYQ+/Y66zSLejqlglskCJE2IbgXIETK24/w20doH2CHj6Bhx/wmixOd2IKBytkOvB392Bu8GLJx3BdSicPCgRrt9II6ifgHy4dbJrLIGeUnpz2/kWPotr9DSfjwNkNsW1tHQ2WOQQhBZ8BDn6E6xVteU8svqTCYKT+/NUmKH838WL4hAk6XkBbZJRpk4C18SBM0k0YaydjCkQ2+5Aryj7K3ohiqcjrDygEmnMWSKQ16Az8MI4S4KPQhUk8zhBKAerekBIsCEEZaNKC6p4JkKIaz0qVejy5DuZzQPL/j6oRXCBhgks3DwfiTvW9qPuyYlAFVMJGoY74sAajSWViJR+1ygiE6ttgOdzqtEsFXuHcO5VIvjsajf8Z0+V2XfDuYvwajHPcu+3JXFqwePK5KgwzhF5JzlcXh9czmPFNbTMGnTfMvG+hDoivDXj0lf/HEoQIy6XTt4zL5jaLo0+o1H1CrsRQrvkge4lwwVGf2rc2FPYbdrpd/PFygTX5VvmspQZfRwGsFILWR7SEz14cHe/aBBv+EZ6qtqPhAiugvwUZiM+m2DRnAXxgKAni1F0pQTC0Qpa9lEseR7nhJbGR1KzogkxPmmPcrjDK3jn05oHiZE8L3mJTG6S4hUTguYjBcP08c4mealYQti8MRuBVtg6j+ebXwlwPjOjwhEjOWpQG5aDhUrbca60tfJlwIjYzAwzzcmsVZmqOdIYcEpXQcKi2daE6rnSR0wO9gkMvon7VcqVHDHnrkAhdCQtieds9vGy6i91WZKLzsvuhpHM0iUMSG0sWP4bVUq/X/M65WuHQqQy+09EM+EijOCBIDglL63DkW8Od0t9WvZ6il7NkslOwsU2r8LbOdWnzTRPxCrICj7rGaF6fTnQoX3tl4EpcspvAYzSHiMuzaKx9ohfSylC48psKjDDBC38ZhhK1UxRYxrmEyIfkwKakFGt+zhAT0u0OwPl7BzLzT/TFrmisOp0xKnsfGKOS1qq3I8mcE+tJ/1dugkfKui3a9FrpTBrNNUYMOHo9XFT3vm0D+5feulhm/f2iByUWXJ2HuqZSLwfRQuSnO9HdyYdcPxMmGPbxUnNf05gwprpdoL1RHpdVCBBsVYpKgxQrWwFuANDVBQn3FAfVRDTIQNVNt5/ezc62N51rxWJbIu0ccsaIdsxrZOKcK58HEEvA9P++k4sbNY2w0zSRuC7gNGnlli5I3Ll6/avIqGfnc21uzWX0ua46n0SbNQ1frODLW7RzoalgaxIG88aeWBKvqEG8n0O/IhEkrnUkx7ZJRpfhgXI+0m7LMiteh8qD3yYR9dvI9PNIm+iYsWa5NvZFRSrigz98ZdVu/6Z8c9E3OdtcLQq4hVlRhM1eXOReAhtZ6076cDEAHEKtoIoNo3kcZlsexLUBHE4XIPkJ6G4bbCW1iLBaXeGgoylY0Lwf7gNNGHZu1g/3RNuK+jzLSly+Uhx/8f45/qcQegMDfvCayfYB37ez/uiUNVuGZOIilJC9eQFVAq9XE2C+cxk8kcESIoBzkwdbUV7N56ZJ9TT2x4ND62qxxuPgh+7MOyBHsRJWlUoYPRU+64fkkRsZdxl10R1EeZpheUyywWSRE5kW62N+P/UUPmK0GeWf8JYPzXyB0bXP+d+h99FsxBXAcUMR2wV5Hbau3h8acgystLTj23AXWZumtzNmR7lmLdyHZ8SwdAoDgO7cylGI3Z6UH/ret2TdI6HUwUtEgOxgk+7bgs3S94gpqGwVr4FtIQSF7vD7LoXF3/Qouad4TqdBF1apcL00dvocSIMFOVZsB83VtcpFwHWIOLLW3FvQXt/M7uXFPwvGIPkDXIIbtQX3QcNWYUYARwDmlHv6lTVc7CC+Gk32k7bYd/kcUIBv5fE+sRk1Ivng6BlduTnXfTftMleHF9hQ+CHqZ+8JaQMP8xl4pJCBjvQ0hi6yTr9t9aWXltseh4HnFKssOWrQZyBbrLMqCde9s3bFjcF2ZZhimsN4NqB8/7zQsZZYyUY5mC5OZaVY0d93h3PmnPIaLqp3+wN8x0bmYoTgsPpqexvaMxaA+NSKb5Cec1f+KOU8DWHNHJYi7zc4h8yEB6Pwp5pfcrcuK4tS6CWzDp0lqwCDAsALdI0cgfqJHKnvgwrt/BdPE+fzYTOgb5RWrs0bfTqPOq9cJAey+YG4cvQITNresOyJtW9ohlUc0z6EJnbUoRO3ycGQhYSAsur5E7/XdbZIHzfWGjdc1ySwA7GFEN066Bwp8yNFXBCqdqz4reif0hwImiZPyJEadCE4KTNDH3OFaT94BQyifHuUiAIwklpuQFT+ryiQgnmIR5rWi/RBFVxbJyFW78KJGdSBeIVUBqXdkSxhaBRgIVfN7k2lghfue/VFAnUAUp+lmbf6SALbIKH+RQyqxgTV1tZky2795E5AotTkGJ1wxJbyrHzSO1fNUcOKQ7Q35wnV3hHDVZ6pG4XZezehacVSLAgSmpyYL/6M1yJGQJZzZ6H0MvTWoMuvcOA+IF+qP5pcVbuxM2IsWHw0/hyel9AiPery56A8GDZfHidYnWfg00ePewJKLmusxoEsAps33iVYHJSApdvqxdrj3Ba04ez45p1DfFO5/ZlqviJ8dg0wKIbRNoIOxLjUNQy8l7rEGfphe9l0VvnNPGVbHXlxkt7yq1zrq4yMfd4oRCcW7PMChcSicjhwXhS2F0U3ybYnKnK9YS/dIhNm4l/K0REF2E+QvgT2ur5dLYsr0O+FVzBS18tldJV9dofyzUsDknBJ4MGnhEOrbmPonbQlfm3adqj7vUK9/J2cbFR5JH0cClxkGqlc9tkBxSOGkNVi6qmMHsoJWfz3VwkdW7RaSc+IKkeJSoP2wMfrJLdrY2WUMxf6NcVKwrFYee6lOSWnhM3Xx78i/wMiHJcVmXjHkj+7NeaM8ZeKz1S2yDsiMMrvSQk7WPYl5SqUihkUTLIOWkbRp9yt872OAWrNCtbon1spWMFG5J8BvS0cpEBVJiPARNwT9keWCddPoTOx/MWMRyJ5G7fwFvJg0KLO7i4XuuO9ZF756npM5lyG5oIuJDl0QRBTtGWk/C55puIsL5xSXuWUHpbgsaeaP7r+HYLWOdlkgcZJ/U5HGRnoKMOpa/mavzQSRU4mQABOGck1wsecTi+1kUdvJS0zGxk8VXlqgFq2thUKKp0i5894+iSuiy6X5/dWgxHRMPQGAigE7AnPeWq80kTREakm1BuSmFyvpHqWHrYAmlGT8dunuqIerpei10REPDhxNzPROFDolrTji6qARBhCUBYffnxg4xGHQwLV7aN/u3cAngg/jay12uLm6AhdkAuhpEdIcQUYNJ3STEon7rzP6vlXNrifuxOPmq9Ru+57pkbU5eZJ+yIGisUyOj9JqXZbrh7niRCZjQhI6B0q/F99q5yeFhI7dYIT+UxXRiw3gOjShuDDsEvb7s3WuOu8cDZ6mFKkpLE7IruTbTPWZnqiq8aDf/2x96PSiCxXFYKhf3T7YmC3SgwST9i+vddetQ7NK4I8Emjn1Nqnbqg13knKlnh/cjJ6q4KGj99eKxKV98MdLqVF6aLtsNzzCRqhuuFR8kmM4kBo32waQGP54ceaHtbMNcML4417UIHyU/yjFOONHfE0zu8D90hxfs4UjuHqxL5MC854PbITweFCtZ85M++JFTRpiihfDtsdi/zyoEU2x83V8G/lCBB/14taHcVcbTBqpYFurPYsU75lNGr5NtWPwxNnJFZlIBde38cBBma5C84CLFaQgN96J+oMRZngCOdqXtxKxaWUb4O+Ek6InmtJIb/pFckq6GGQComCJ1x5YwUsAQgp2AuBo5q8/amIBw+Yke5BEy8PYKc5/RM46CQYz8w0J3rsZzjEmSgUSNY2MWVwfxNWMIYw5UB7JXyE10OBmxfu7OF9Ay40qvwSfKyDycwcQwSzqTaO+iu03gtLCCX3FLd7N8QHRCtP4wftVwLap6Ukbg9le5/W3olrJrBiKk4BSIvZK438L2+ptxdOLM+6SwREv0x1tbf0N7YPjgO9QQvOfNsv4sVs+KsxrrqLi0ao87JTn/mJDMHhPi2ZJW0Oxty8Ym1EOyzT3BhsORkcU72E/tYqLTYd3BToDeYLrk4TlT9QE5Xaaq2vhqI2JS/fH+1z0HWDhjz3tG4DV9aoVPdsPwJsRabicEbpCeqJlBQB/6FFQOHwiSDzlHfb4r7agkyJWfB2wReuzRyxOOOcWhrg4WluoouvJAQHxY7PKiUqBS56ZQ6XKVhZBdDnPfd+NWut7zhZ7F96cQ3fz8cuQ67e3LIACqnXEgc9ox5BjAvi/PXyQvuknlZXParlsdlgOzkv2nWBxocP5uSEE51RkjNGYrgnaxvKxsx9TDg1H7ofO68ioHhqZnbQwzHn8zMauz00dAgXqeQgNMAdCASpkMQ1COvcO8DUQOWHCXiq16/xRo850gV68QdR0PorXhOs8dxsk+oc4JsDAE+JwiaYU7yWecQ+jyJK0HuQIjaA3eE2MQlEOTDs3JfyXOmFRCEh640Uy5AM+4//v8z+r2v+OBPyw3MnIl+ldqpKK7Y/E6deXbx1Lix6Vq25MDoZCejhivokwJtZVyMjpLQVcBasveZ7GjJac7wR3dQyLXWBhxOvL9lARu40/Xo7itgran+YtRSFhQ2D35U4NdW/PmGqETC00qxInkCvVdO5whYxRjN7su7OChaETjzC58tqD8qN/f0uy2XkR1m/zkFD66bQ3/UohooW2YV1D3gway1Kri3cR2ueZY2beeIZPj/ODBEOpn7fva6hbwxsSdrSqFR3bWdxAM419ASa791J7nGlVEkEmGyL2vAhm6/0JBCPq8oAPrcfzw5n91dlvBRTJ+U1hhUn8vZDBL/F3kCb1WHBjGzQuJ4iVUwIcQ8vlF+T28+CV4zRA2U8OlSHDLuHtAoY0LqR8Yaz+snVJDH2wV3jMAryRf9/IS+1BYHpsJVylz4Ms+6FN/Ok5fLhVfTfHIqW7Mic0h/feaeBQ9I/6tvEeYEX4HHN8yRNYmElQUEmHT/Y4Y/Zzu1Uxh5qVvxwEIsH7obr8+awSWjhxDljhLBvcC9rfnj1lYaAv3cwtSWYyyjhGgAcDoJhLXTY2mQ9YucywHdXF/CtSlHGxD3wjTNE15xnRLcKD6MCPRZ4+dUWaOcAqAPDUzTwy9KHvKH0MRjaB+CccsXMJxvL44lqRzQUbK0iEt2Hq0p0O2IdXDdvEea1CFGzA88QHG1x+tVYZMkMhKFIZq9p2dlBUfYwgiCSCqxgeTlp3x0kQ/12hQdVkWVw4xyv+5LCuRqo3dVD31wLRkYg6WKYahaobDzuK0p+3+H2MsFhr/ZNiKtpzS3mGBgybZrQBUy0eEF/sggYXQzsolU71gCMTyBPFBpl0n72MsuEINNlRo6EaLPwWcdZGWcjYFYDVltUBLt68I9V2DRVN1F31VfT3HjqxhNkh7khj28AQlzOsA/PcTaEzK5580HW7kS6TZHy0gGox3b3Vj2lg/uXQeLry2x0+UBUtZVoeNoWH3A3UeyaYw8mUMcc2TopEt0oAUxHO3SAYL+M1/D7MN1axmcdCoKtmD1SEo6SeLmXIvBAzYNEDC1gIBjKEylyHqmbmWYqUODuV64R/MQaXYjcLUg6R4xnrodJCUiLfZf6142WUMGvg5nAehimnVl+O3j+XXCYl7lgmpxkGWuOinZXpq29yBgLVogCJkq404sjpUtIEyXHWmQR449FGg07iU6P1Tl4TUGEnpXw+asKQqoZvLyqPwNjs1cTZkdkAK3e0GBCNA3uohkI7z2f8nIRssgK86b0RM1/XF9GCs+6POqo0VC50115AKEsOj+diOfhvIOEwi1CuI8A1rv5/800UR15ajZS4xnap+pmkz4d3/+HsrK6wWLtx5obBX4j54SpUzurCSUiVdO7ye/x/wWQcME2Oz/4FaaG9OI5QGe5WxUp2VZWhX2nAS8Vb6AiJVFEVgZS47OlcxAFqBLkLVNgh0LjfJzhHX1mk7PW6ose+mzGajlUfT6bDdI5PwDBPHPGphSwuBXOxePwZfaIcHFU4B0PjcoA/1m8CDn/bFE631JeLvigOhNtH63HEZmRxwYpSbmFYZU5IplKjHYMGEN1uY3NSrO7SOu7NrT+UKyqJKPSzw+cEBNs4naUdb5OYujn0JvRz8H49n4R6Aul8NSWLOcbqMHcymI+k1j5MJ2jntg+6IgRAp4EZCSfrat7QyLKadpE3GmZ+mphMLacfSBDYrCe7GWpQwCzMQKKzliG/qcfIZmyfCZv54jlEa7lpeABefx1zyyXkTPuji+KEw3q7brVlaBJ9dSNNCWj0AdhO+JDC8x4HYqW4WLo4BPWZTEpPifLRZ6FrG/uxPxka76atVyCjMbLgmbhTokBctRECYXDrf+mHLnjicfVVt76SdxDUx9FgUuyuHZalIO/hTh7gWF1YY3C1KBk8wEBXdrrJ3I/FFVOdvMVcrhuRtRKEkRaFRBBOOCmBAKqzVvzm5LesseSDwZY0npHuwFtATrfucbxo4ht+uwNUwBstZtawi/F0YbTCXoIPI5iqd03u8r87NOBM7S5T4tix8ifwqLohp7YSQecMsSOWZpHoRxe3YOWYxIHYXbZACmDCMDFgUbgBjgUdEqHovIWYPPgiF600N6ge5l/Ny6ZHllA0+fY6Z0LS+b2+R//RBbZPqZaSfOS+hPyL7ixzCE6/O7XmkwUsgj7qsuJHQsG34fUQmwSZ5pj8VqbMejxTed1z1SWz5m8ddOZ2lQchfGm7gkU1tR+L2tM6C9olrEMVWj94gR2eD1E1CXS7DhD4hKS77WaeuCHQtOAT/gyko5Vb4T3II+K3/1CIh5Rnd+GRBt+fkN7zqYPJyObtMmiE7nz5onurO5rXj4DPSaMT8s4RJ50TrQvwpNJDC0CuMLsjTUfNyUQM6ht44gfmkmxOPLyNdxJBENZPda2dAG6ZfxabGyfyvj42zGJgVERFAOc1q5RTq7Xt21KyJirTs0D0/l3UinTRp4PUIaEtPZIOn9xfV0ccd1u0hT+pYVDJc2wZI0uxMpdiGdBQHuLYGfm9Q7gxqD8kiPQZqFOHSueqEGi1/LoiNNMihncx/tJP9msMhm/oe7EGQF/g06f2s/2bIFmjKhO03iSM8Sj9Zwrir7ZfjuBmK3EnaIJ9OAxXmvG0gL15AbVXv7JY/bXitvxaxSAOK2057i0pl/dFoA8ZIfSbEWJB8+wla03EjwKPHh4ZkAfr/VF0iC4h62uJB/JokDSzlVtb3gkYLeV9LYhwge4D5wmgbjKwhqaz0sa3kCvOsHHln0y/IVaciCxFiaQ1du0eq0aaOQU2oiiD1tTz+gWhGb9qTqgs/jFXOlc6LC1oCHqK3mzG4UMu9qRavLiyyOJGwKLzI5tKfzvZDy2dzXCEujGmpjCrFDsm3VtXmMQ6hMnTrU0fRQftQJz7RlRY9bKuhYhokBG72eKfREI7ipwitqsBdE/sR+4GafI6OmDPDPDjOMVRpLtPQsRaNmoOp6fzCQwH0h19FBnk49NqO10Pi1j+KevGITHTTsBqg3M9tRXR0Tv+8KrNMR4dHt1Jjri1Ut/fC3oWeBoGjI4AxTaRZuAHZWnQ91azKoZJ18OCbA1mKd9sxhHIS+Yxxp4jLiLfgDJvpO0IjCQWmeNwjzqw5Z1HVHBwZlULkPbtSvFdWzNfzQMRKVHntDMQwrvMJuiLXvD3vDngfYA+Ya7qmpvlkqu8+KRaTfw6juKXnyyYJqfHegndYuLPVKq+zF7X6kQzcAyjvMEDml1FLC7GOfD7CEMPf85V/pWk2efSVI4cNvuoe7brZVfuoEtmEollHXewHStEH9U2XDRH37n19+WiYekajjojjBnMa2uIhy7kkyEQb5eF/Ks3+3DEjA8NXeZoosFJYMPf8dziXJflwhI1i2IHUN34RHf42cS1XvnUoHZyMaqZGNo5a4j7HrDw/2DXAeqOwinYOwPG/Pw8je0HrXMmLZUOjyS8hoAp/3w/9Esl1P5dCxdKmu8Eh40gxN4xx82sCl1PRp3S29MyP+QMS8V6gfdQgsEHZY14jHWhCG6PQARJPsZy+14SndYl0qPNGhmEzDuezbWB2R7XP53K7AIsAXarQd7W4fKJo/BpUoe9nF237WmvTTU4kRRpTfux8yvyjmD8VZH0kbjvNkfHYMwbUEXyWzr/Z38+CxpRDzTKA/F4Tfv/OAhh+8ALRyKGc6sfxoIoQdBRTvI4YntKbtvtpUqTR41E+9TIPw/JdI0R8F8DT/otxoXl0vBPx1EYdqxGkjWJ7VIO5fgq7MT3sK2KddVTNmNOW224buqFS0ZIFKEyXu2/EqpyhYxld+WP4i3xdIx5rLbXLcHyO18+DV+/86fKMV2n+4sFNPqVyoORyuEb5R3lm3iEvsebYpn25js8p5QLRidW0Uw3ei1xehN8W97H9MDOPU9eAibNcVgr7qdQwhkrC1Bc+7su2HPLkLvunMASGiaUbafS+YQeorODQ1LFlfQGuXfa7IEBTuhwymj6bREBqjRjl3cC8rzMmgSC65tDl4rEGs870CuE0YQVcC15s6kuHwIphtR54Qemm+WjnV4Xp12Sg28GvhbBsRsGmPqKpMRUKnzRqZHXXdjTpPDhx3CdJTRZXgP2wuTRMIPd4KwlWktaqe+DlSU32u1Ybrjhf3SrWvc6qKDqAYRG0EDOHyMoWcyEXBSc6E7uSzk7zfM1EPr6fVDGx9IsqQhibIOetTqF3TyBaO8sKrTU0BULn6CDbLrOceGewqm1mwMp4oah+ZYwt1B0LT64aAQfahc96fCUxhc76MjYRk8TcwQTsLFL7RFiOe4NimgbOb5/GO8lojWk9GluSSD+S9Lwl16D77hbYxAqhWciePR58SBBeDasd8xI6//CaX1jT+MSfPT+20heNg40mBTq2XVODuHFw5XBRrMKsxJCWTaVZzCJJipQgm7MJNikhlPZH88VzBGzFvLbbz7SkypGxns58tFSQy2CXaOCVQeJv8dZ5yRxOzKSwU1Vyb/tZxZIpinweP8Skfo1k89KviI4gBWmSud1IRYYCWAxNWy6d4m5vmezC1Cw9Y23pu8Puv+5YltWGqkgxRjvK7qeBjzrTcqEQvGHuRemrDeehuO3Np/BKbCu2USWzhr+s3Kghkuby3I5sJRB8kGIIIekc/JS6ynSksQkatoprySrnmIuei1Q6QbzGJg3OjgXNj7/tJvcO5vMJqaSIxCm8ZZhm6LmCnuMWrNqdo+bB/BX2XJNn24Gqy9OapaQHgifcc0QSLyQajHlTBbn5aL1QvDfe8is9nfyqDvibo5lj0+raj7kjaMY7RmthFqd6HeTXW6EpugHPzSuvn+roAa/Zfp0SNEc+MeQtADn3bueuCNGRbPbgzzG5gaFV4UpWdAYzCLGbwXFN1s2aPBy3rVtl4TGKxG1fXlA3I0NZ/KEg/leMnvwy2+WLkZxQFNBW0XXMJsYIlCUEwheSaPD6ST7HkNWQzXClLzKd0UBIUc91wIa526Vfr4hT7ARAIAKaSRGmyBaZHDEuX2GjNm/09YfF49CMOQQzV4MGBvFlqIIhJBGYjy5oz7Gk20xSKlDJd0p7k1cgbyke9gf3u4dQ49zueYUeJv0Iti6VR5/mHnlM85a29mz6tir2ewr+5v2dwZoDnTfRES3HUgzcWlu3pE3wKHg32Q++4cz2IaSyUge21Ikyh5wNyfkmdtp5XmA+HVkXoZvYJzciEj4H8dKTmpCo6LPokpXtzxR0614ap+wuEoq/K+XDq8bm1t1DEwTaRrFnvFFklcJaTlFTVEskEMGndDRPI4/AU0w6hVO6grURyw6G7bPj03adft/ImOwotqeqfeR4SWJBrGFkgrja1zhjYYshrjTcJnNKHxYCPap5e6ZouFfNwbNxP0ABN/tobDsA8Fg4CTfl98lriP/EKnjSpP3M6RRxGCc2daD57b3K+G01ov/Xby0qpQThdCL752nPvA3irCmuyNlXkzNIMMw0ZQhZ+/yM+5SQ0TsLqoQFFVGdmQFlPB4IdB1OoKwlCsaJxSMN2QGn+XfBykWgrt5TuEsyH6+H/yfd5fTB9X/KQQigkwhmb0vXFct24jAtjxM8T8XYbR9kHnmn1vyQZeO3yvOspBNMZei4GPOi7LeGSDzZO/rP749PvnXKXk8CBjIWJGnQHV1m1nZRRA6igxxmkIuKEsSzAspm1cPXuLUYM43soLpY+ummQusqcuzS45lBU7qzbzfzoUMIqEh/CkMsohd+taUdmRQbU7zUAB6UkDKylldOLkJljJ8ierOhCkCPKKxOHB85G5W6ffWFV8GBX96AR/De1lLJGi1vbtXuaC5FpmvadxwZOsjAcsiF5hh3miAI4x/2TGS48YIPGH0O8IdUjanbA01oAI61p//2N2n7m5o3vis8GDZBVhmVdgdxO4ts9T4ra7wz1Po8/qbnknkyInNP2G+Pu2Lc2kxR3IMHnMvZbvG21vP+SfAe0t2fG0lDmvG6/tzEUd0H0EGUYgokEWmGN6xYBfA2Zgzn6oZGIvWrMi/vGQDilhs5uGT3PCQX3iDmpVc6UoyUpcZ8BYTj1JTYBacmpr1j6lSVNBYnluH4CCxoSVIoXjDjoYdJ/tLeYBDeeBrzY60wR5UpKAGSM2s2wBuuMMrVgjTncWi4rP6qPsDrABPDAMusaxuJX1b1PBV+XtDIEqAJXLQOY9mT5/m4Wr04zHmoWQvW3lDS630svp7GPbvr9f/KjglqP26WV927W8vJ1EgB/8g1r7cvzxfVuqr4ewywCyQXa6f7CWjePO5Dcw7l40dsY7dn81RIhEHyt6n/ifc9MpHPgOu5P0G1LTr1Mt8JI0FyhDqEkZkyApUgnFxMSfhVIePlM9qK0oliXSD0YZv6EMQk0nQrSne+lla+wvJJUVAPQR6H7gTDz6vy0hTfsIHNgzHJ5MsQiR4S+0e2ta7p38bbHMHSeSHk0DBDYv9zNh8NTuRPeQS41dLGr/54XpKGX5AmT3bTJnb3D6j+Itiqn5KqsLpCENbypbmFH10QbVAavGo0O2aog5w9CyjxrztxjpI4k3z1rW+C1O6W53MpceLV5Nd30qAcPf2pBstXSjpFnapHXg+wdgtP8I8IJmzE0Sw7JXyel42qXr7Z/esgeLjZXtp9F7Wl7d5H5g7yOExQUegaijT6eR0GBzcbnRDATNnHiyx8u75TabwV6aCPMyD6QGVl8ioDA2NVARMiBPaGpw7BvqCQ9OM+5zOf4VhQ3hODW35usDUqEuV1WTl447i0HW12y6dZwZfdHMU69xtJwFCM3hf7VmFHi+JN+9qwdim0ZX9+DQsPflkoQXUrvlCdIhCxd8Dr9f5b1sQyL//PvzOkawXfNUtOWIUxoLkiU2xc3O4X32CIsJdTVg95G9HOTlRSNDpL2jbkAfObKW3OlcLors8dNVRSPoHhajY4evLMYO2Xq/2lFkaxzXU58I4xCk+IkgtXUJ6mUZTEINdi6yEMbOPQ7KNF4YCHLv4/m142mGkvyOTuOo0G6Bv9wPnEHerhKeC4AKkR7qNU0aJNY9OjNUnQB7lBe3ZHy1jbITl78cPQezuChOQkDb17zkrNjRzFmQ1hG9FzRFLoZ1AX/wp+IBI/98CHNM6knVR6V9WoHfpD5fkTunPOwM+605Gj10RGwq4sZR9rc9On55kBXaiPMCaXNrfhnLo0t1TAMDNldL/b9VL6qfJEQh40vw+J+HbT0dWK4JZClKaHehrvJCXhYm2om23aXAC4P4nG89FPKS4lYYK+9tBX4W5c114l7p8DQbvQhHR2HZCBic291D7b04eOt3sK/bO3PUB32fLhaxzt4dUipxhBCg0/EHKnWNT6UmEAo6W0RW00n84Mh5Abq5P4ZUSOcBJPnwaDWRE4TjD5W1aSuN1j+SSJNHOD9uLLQnH5t30JVYFnm/pz9tsM5vrd+qk40mLkw5nFOB/miDBA1KAHMQWRn7Z8iJyAGvXbXT8izHmEfVl9ubpy58XeM8voCoMc2YvV+9I2JUtYRr7uzuZAHkt6/tGGl72R+X5vP/GdhQHO5oB7rdqLnrocWFOXJ3T1jHecdgJU6sz6SfmkchEhhe7lwzc86LuM51tjt7r0mWY93O6uX+vEVNpuKKstwbIn+hyK8SRZ9nsWonuVqWLeIndE09U5bnaw9kPZxdyFMtoJQ1sTa47zs9tg+9aXN9hxcT8bQb4g494aWpIgZ36WfSkhFoQR0IPJDMKbC7wMALjrsnVqY8esxUNULysS4II98vyXft3VzC/I7nj7KBxbI3eKfBccYo7kdDXDcH9N4WS/0QHU9xMsiRl/XBrN0PiHDuBumulN8+PfELQhdhG4uJ1pE0i6GM1eaK16BugFcho9gnNRlUUP55YuothPEO2gRF1szVSpYhMvGfHmcSBkdt5cRuV0wy6onIqgnYr90vCOUIG8J9nwzxG+w+qG1quDkcyH5a15BQvkl4QGbs4AvcpWbxppniglLUDfhNTNAV97VFP6bxmOGjyWNoaC00jQFlxM0/ipguX6bjoPq8WgeB4yghfkv4gs1EJtwA49cPRDP9j02/HScECOoZ7JQyAZ6Kc/wjJ8cvnHxceQmV48/2K1TxcKl23eBJYIN4hivjcRTVPg5YwZ6eRnhNs/8K2uyxzOvFZpph+hNnwcJiv1LY+U8iv5QHk67a/HIUXRzuje4nMnLVgSGHeeQUSzPV6KEumm9FKmS000Fkb6qBgC6Qq+7q15oiFtctYN8GvtTv5kG4utTr2e/HrSL59E29VHhbZaTJUJSS3GrTMDoOZxpm7cESHop0XgTjb9dpCwPfIl96Fa6wEWYzvI9bwNv+/CCr03IRhFuAmePQ3E/rCQutnxyqJit46anudJ8NMzPHeK+z5/Dj9MN2S4m5LHBD6+YGRV9zkQsmGJLtmFarQiPEGhVFsdFRk1GxUs+Jkfmt3XpUHlSvw378pY3U0WdVXCB156BakXVR2cYDf/DRq5lSrgcTUmzhsNrfJArMHY7077+1+Ka96IKs/j3Tsu6ZumcanmGlyMLG+J+1NIytksQ/ehhHIam5NrwgzpiIQeUji17KuUe8qbmdTnEDRFhp/il+tSgAbO4EV3F4p+HcO1YxbpwxGH9f27xtqYFBvW2xyEJP4VYH8eExSM9pIbem715yN2NNOy5U4HOFkw7/89QESgtwhY2Ndev9Dy0GAGmziA257m3Vk+awubQeJM18YO9kHezA69n/tbKgIv+OqOdGpnycXFbhIyBnevEYxLpyT72VhaUiqf5dXBux3SmY3zvLpFqNYD0FVRdSAYM+teDEWPF8YzwfS+s/TBI4vSQAJrJe5LDF9yLd4bP0HEjPRLLwpdqw41VCCZQmYP2Npcqm9v4e0JUfBfiX7+RCIH87gBW3lrm3lxuNZvtPpMbBJhok6L7mMZaZQR1WIE7gmig/ivnGMr/KzOmrGbMQWdYQ6HIVUE5MZyEXZaB1C2wkx3s24GUenDxIRneZPt0O1dbUu4ikRUOQYQFwCGGMjwvrDG5irL9o9jtaon1fVzjh3Mn+jDVw3dq8KTwc6M06nKuQz0VfdrPqQ+Xv9EbEYx+Y7fs65Yk7xysVVAhMQd3ebKbEbAj7++4iKb3lrsumMGgKqAxBU7Htjqbe7pbmB8FHy4U2nbqptVONHkyPBYWS9+MaZOLPRQ9kcuzG/7fJ7ZydXLcALqPVqzxj,iv:zBTf+IXwjEJa+x64pNqfRoaUHiiEvjwSUUB4q8EkkQU=,tag:L/7ZvprEBuLywT44Nf7geA==,type:str]", + "data": "ENC[AES256_GCM,data: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,iv:tiOrqnqaXb0jd6e7nwCe714Q43iqm9hljyuOfsVsDEs=,tag:nvr2pu/r9O8GwHRqGX0M3g==,type:str]", "sops": { "age": [ { @@ -143,8 +143,8 @@ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBmZHkzbHVZcmpwdzZHMVkv\nRXJZeXRTNmhUOTZHTGxlVDBqMkg5Z0pPNHlVCmI0TnFobDZuSGx0cDUxQ08yd0tj\na0h0cU13aFZNcFh4VE1xZ3FtcWZSN0kKLS0tIEhwbmdkaDZpSGo2WjdIRU41d3Ra\nczJhWFFyOVF0dG9FenVFcFhIUnVFSmcKjUsUDUe7bSM6k0Sw2Ygh8Ivk6UC1PTFh\nRvLsDcxOS4QK8OiJPZLCFH6iHsVuzvHHcpra4Q5ZD0EVeXXZkjPXzg==\n-----END AGE ENCRYPTED FILE-----\n" } ], - "lastmodified": "2026-01-10T12:50:53Z", - "mac": "ENC[AES256_GCM,data:/WKrvjiwGbsl1DDzDqZekZFRCVB6u6xyZ4x2P/ZEmQXxRzvXMr85DYeO2xjt+kyPGq5TFsQYgeot1z/WSMbM8xHw8vxNRuP1cocrxxHIw1VEA9yBsA0Oy2+hs89aKsrrT6K6xl4PQAgHCZJh777z3QOpqReSiKnIXg8EZU5jEgk=,iv:oLCxZ9GEFFfaU3C/NqvXZrZtQk5uI4AtGZdSO0SK6K8=,tag:t5XF4iNqC+g7o2FAsffaXg==,type:str]", + "lastmodified": "2026-01-19T13:22:10Z", + "mac": "ENC[AES256_GCM,data:bA+aPggCsNoTx0MCD/bRRbWbchyUL3wcpKF64j2sbtL0ID44IcN8hKO7739Lg1omoxk31id1j3/PsFlFArbLF8tR7yxYpb4nSjgrOYPvhvO6kXGoS74iKndTu5BpNzufrOJIJlXCrKs43m0iFy7KPpM2jTm9tSTWMsloA5xyfb0=,iv:XCPlxgunWqb8bcYbeFmGFtJSlYugqYH7CSB/83hVmgg=,tag:YUKItD5hFQk/lJUdFP9nCg==,type:str]", "pgp": [ { "created_at": "2026-01-12T22:05:06Z",