From 80c08a6d193e0faf866ed708d7325c91fcd9b9bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20Schwarz=C3=A4ugl?= Date: Thu, 5 Mar 2026 23:36:19 +0100 Subject: [PATCH] style: fix formatting --- SwarselSystems.org | 2334 ++++++++--------- .../nixos/optional/microvm-guest-shares.nix | 2 +- modules/nixos/server/disk-encrypt.nix | 8 +- modules/nixos/server/postgresql.nix | 2 +- 4 files changed, 1169 insertions(+), 1177 deletions(-) diff --git a/SwarselSystems.org b/SwarselSystems.org index f51ce25..adfea44 100644 --- a/SwarselSystems.org +++ b/SwarselSystems.org @@ -2487,12 +2487,15 @@ The rest of the functions are used to build full NixOS systems as well as halfCo // 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; + (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; }; @@ -2854,30 +2857,31 @@ Aside from the =default= devShell which is the one that should usually be called deploy = let nix-version = "2_28"; - in { - packages = [ - (builtins.trace "alarm: pinned nix_${nix-version}" pkgs.stable25_05.nixVersions."nix_${nix-version}") - pkgs.git - pkgs.just - pkgs.age - pkgs.ssh-to-age - pkgs.sops - ]; - - env = - [ - { - name = "NIX_CONFIG"; - value = '' - plugin-files = ${pkgs.stable25_05.nix-plugins.overrideAttrs (o: { - buildInputs = [pkgs.stable25_05.nixVersions."nix_${nix-version}" pkgs.stable25_05.boost]; - patches = (o.patches or []) ++ [./nix-plugins.patch]; - })}/lib/nix/plugins - extra-builtins-file = ${self + /nix/extra-builtins.nix} - ''; - } + in + { + packages = [ + (builtins.trace "alarm: pinned nix_${nix-version}" pkgs.stable25_05.nixVersions."nix_${nix-version}") + pkgs.git + pkgs.just + pkgs.age + pkgs.ssh-to-age + pkgs.sops ]; - }; + + env = + [ + { + name = "NIX_CONFIG"; + value = '' + plugin-files = ${pkgs.stable25_05.nix-plugins.overrideAttrs (o: { + buildInputs = [pkgs.stable25_05.nixVersions."nix_${nix-version}" pkgs.stable25_05.boost]; + patches = (o.patches or []) ++ [./nix-plugins.patch]; + })}/lib/nix/plugins + extra-builtins-file = ${self + /nix/extra-builtins.nix} + ''; + } + ]; + }; default = let nix-version = "2_30"; @@ -3196,164 +3200,168 @@ On the structure of overlays: as you notice, all of the attributes within overla inherit (self) outputs; inherit (outputs) lib; in - { - flake = _: + { + flake = _: { - overlays = let - nixpkgs-stable-versions = final: _: + overlays = let - nixpkgsInputs = - lib.filterAttrs - (name: _v: builtins.match "^nixpkgs-.*" name != null) - inputs; + nixpkgs-stable-versions = final: _: + let + nixpkgsInputs = + lib.filterAttrs + (name: _v: builtins.match "^nixpkgs-.*" name != null) + inputs; - rename = name: builtins.replaceStrings [ "nixpkgs-" ] [ "" ] name; + rename = name: builtins.replaceStrings [ "nixpkgs-" ] [ "" ] name; + + mkPkgs = src: + import src { + inherit (final.stdenv.hostPlatform) system; + config.allowUnfree = true; + }; + in + builtins.listToAttrs (map + (name: { + name = rename name; + value = mkPkgs nixpkgsInputs.${name}; + }) + (builtins.attrNames nixpkgsInputs)); - mkPkgs = src: - import src { - inherit (final.stdenv.hostPlatform) system; - config.allowUnfree = true; - }; in - builtins.listToAttrs (map - (name: { - name = rename name; - value = mkPkgs nixpkgsInputs.${name}; - }) - (builtins.attrNames nixpkgsInputs)); - - in rec { - default = additions; - additions = final: prev: - let - additions = final: _: import "${self}/pkgs/flake" { pkgs = final; inherit self lib; } - // { + rec { + default = additions; + additions = final: prev: + let + additions = final: _: import "${self}/pkgs/flake" { pkgs = final; inherit self lib; } + // { swarsel-nix = import inputs.swarsel-nix { pkgs = prev; }; zjstatus = inputs.zjstatus.packages.${prev.stdenv.hostPlatform.system}.default; }; - in - (additions final prev) - // (nixpkgs-stable-versions final prev) - // (inputs.niri-flake.overlays.niri final prev) - // (inputs.noctalia.overlays.default final prev) - // (inputs.vbc-nix.overlays.default final prev) - // (inputs.nur.overlays.default final prev) - // (inputs.emacs-overlay.overlay final prev) - // (inputs.nix-topology.overlays.default final prev) - // (inputs.nix-index-database.overlays.nix-index final prev) - // (inputs.nixgl.overlay final prev) - // (inputs.nix-minecraft.overlay final prev) - // (inputs.nixos-extra-modules.overlays.default final prev); + in + (additions final prev) + // (nixpkgs-stable-versions final prev) + // (inputs.niri-flake.overlays.niri final prev) + // (inputs.noctalia.overlays.default final prev) + // (inputs.vbc-nix.overlays.default final prev) + // (inputs.nur.overlays.default final prev) + // (inputs.emacs-overlay.overlay final prev) + // (inputs.nix-topology.overlays.default final prev) + // (inputs.nix-index-database.overlays.nix-index final prev) + // (inputs.nixgl.overlay final prev) + // (inputs.nix-minecraft.overlay final prev) + // (inputs.nixos-extra-modules.overlays.default final prev); - stables = final: prev: - let - mkUsePkgsFrom = pkgsFrom: names: - builtins.listToAttrs (map - (name: { - inherit name; - value = pkgsFrom.${name}; - }) - names); + stables = final: prev: + let + mkUsePkgsFrom = pkgsFrom: names: + builtins.listToAttrs (map + (name: { + inherit name; + value = pkgsFrom.${name}; + }) + names); - from = let - stablePackages = nixpkgs-stable-versions final prev; - in key: - stablePackages.${key} or (throw "Missing nixpkgs input nixpkgs-${key}"); + from = + let + stablePackages = nixpkgs-stable-versions final prev; + in + key: + stablePackages.${key} or (throw "Missing nixpkgs input nixpkgs-${key}"); - in - (mkUsePkgsFrom (from "dev") [ - # "swayosd" - "firezone-relay" - "firezone-server-web" - "firezone-server-api" - "firezone-server-domain" - ]) - // (mkUsePkgsFrom (from "stable24_05") [ - "awscli2" - ]) - // (mkUsePkgsFrom (from "stable24_11") [ - "python39" - "spotify" - "vieb" - ]) - // (mkUsePkgsFrom (from "stable25_05") [ - "steam-fhsenv-without-steam" - "transmission_3" - ]) - // (mkUsePkgsFrom (from "stable") [ - # "anki" - "azure-cli" - # "bat-extras.batgrep" - # "bluez" - "calibre" - # "chromium" - "dwarfs" - "gotenberg" - "khal" - "libreoffice" - "libreoffice-qt" - "nerd-fonts-symbols-only" - "noto-fonts" - "noto-fonts-cjk-sans" - "noto-fonts-color-emoji" - # "pipewire" - "podman" - "teams-for-linux" - # "vesktop" - "virtualbox" - ]); - - modifications = final: prev: - let - modifications = final: prev: { - # vesktop = prev.vesktop.override { - # withSystemVencord = true; - # }; - - lib = prev.lib // { - swarselsystems = self.outputs.swarselsystemsLib; - hm = self.outputs.homeLib; - }; - - firefox = prev.firefox.override { - nativeMessagingHosts = [ - prev.tridactyl-native - prev.browserpass - # prev.plasma5Packages.plasma-browser-integration - ]; - }; - - isync = prev.isync.override { - withCyrusSaslXoauth2 = true; - }; - - mgba = final.swarsel-mgba; - - noctalia-shell = prev.noctalia-shell.override { - calendarSupport = true; - }; - - retroarch = prev.retroarch.withCores (cores: with cores; [ - snes9x # snes - nestopia # nes - dosbox # dos - scummvm # scumm - vba-m # gb/a - mgba # gb/a - melonds # ds - dolphin # gc/wii + in + (mkUsePkgsFrom (from "dev") [ + # "swayosd" + "firezone-relay" + "firezone-server-web" + "firezone-server-api" + "firezone-server-domain" + ]) + // (mkUsePkgsFrom (from "stable24_05") [ + "awscli2" + ]) + // (mkUsePkgsFrom (from "stable24_11") [ + "python39" + "spotify" + "vieb" + ]) + // (mkUsePkgsFrom (from "stable25_05") [ + "steam-fhsenv-without-steam" + "transmission_3" + ]) + // (mkUsePkgsFrom (from "stable") [ + # "anki" + "azure-cli" + # "bat-extras.batgrep" + # "bluez" + "calibre" + # "chromium" + "dwarfs" + "gotenberg" + "khal" + "libreoffice" + "libreoffice-qt" + "nerd-fonts-symbols-only" + "noto-fonts" + "noto-fonts-cjk-sans" + "noto-fonts-color-emoji" + # "pipewire" + "podman" + "teams-for-linux" + # "vesktop" + "virtualbox" ]); - }; - in - modifications final prev; - }; + modifications = final: prev: + let + modifications = final: prev: { + # vesktop = prev.vesktop.override { + # withSystemVencord = true; + # }; + + lib = prev.lib // { + swarselsystems = self.outputs.swarselsystemsLib; + hm = self.outputs.homeLib; + }; + + firefox = prev.firefox.override { + nativeMessagingHosts = [ + prev.tridactyl-native + prev.browserpass + # prev.plasma5Packages.plasma-browser-integration + ]; + }; + + isync = prev.isync.override { + withCyrusSaslXoauth2 = true; + }; + + mgba = final.swarsel-mgba; + + noctalia-shell = prev.noctalia-shell.override { + calendarSupport = true; + }; + + retroarch = prev.retroarch.withCores (cores: with cores; [ + snes9x # snes + nestopia # nes + dosbox # dos + scummvm # scumm + vba-m # gb/a + mgba # gb/a + melonds # ds + dolphin # gc/wii + ]); + + }; + in + modifications final prev; + }; }; - } + } #+end_src ** Installer images (iso, kexec) :PROPERTIES: @@ -6143,7 +6151,6 @@ A Mac notebook that I have received from work. I use this machine for getting ac My phone. I use only a minimal config for remote debugging here. #+begin_src nix-ts :tangle hosts/android/aarch64-linux/magicant/default.nix - { pkgs, ... }: { environment = { packages = with pkgs; [ @@ -6188,8 +6195,6 @@ My phone. I use only a minimal config for remote debugging here. experimental-features = nix-command flakes ''; } - - #+end_src **** Treehouse (DGX Spark) @@ -12012,7 +12017,7 @@ Restricts access to the system by the nix build user as per https://discourse.ni "nix-store --serve --write") exec env NIX_SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt ${config.nix.package}/bin/nix-store --serve --write ;; - ,*) + *) echo "Access only allowed for using the nix remote builder" 1>&2 exit esac @@ -12154,14 +12159,8 @@ systemd-initrd provides a lightweight SSH server in form of dropbear - in order I also take some precautions in how I get networking information during stage 1. For the most part, I just use [[#h:12370671-7892-4a74-a804-84f871acde06][systemd-networkd (server)]], however, for hosts in my local network, I take another step to define the network in the =kernelParams=, to make extra sure I can reach it. #+begin_src nix-ts :tangle modules/nixos/server/disk-encrypt.nix - { self, pkgs, lib, config, globals, minimal, ... }: + { self, pkgs, lib, config, minimal, ... }: let - localIp = globals.networks.${config.swarselsystems.server.netConfigName}.hosts.${config.node.name}.ipv4; - subnetMask = globals.networks.${config.swarselsystems.server.netConfigName}.subnetMask4; - gatewayIp = globals.hosts.${config.node.name}.defaultGateway4; - - inherit (globals.general) routerServer; - isRouter = config.node.name == routerServer; hostKeyPathBase = "/etc/secrets/initrd/ssh_host_ed25519_key"; hostKeyPath = @@ -12172,7 +12171,7 @@ I also take some precautions in how I get networking information during stage 1. # this key is only used only for ssh to stage 1 in initial provisioning (in nix store) generatedHostKey = pkgs.runCommand "initrd-hostkey" { } '' - ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -N "" -f $out + ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -N "" -f $out ''; in { @@ -12275,18 +12274,20 @@ By default, attic only provides a cli client to authenticate to caches. I want a config.sops.templates.attic-env.path ]; }; - script = let - attic = lib.getExe pkgs.attic-client; - in '' - set -eu - if ${attic} cache info ${config.swarselsystems.mainUser} >/dev/null 2>&1; then - echo "cache already authenticated" - exit 0 - fi - echo "cache not authenticated, attempting login..." - ${attic} login ${config.swarselsystems.mainUser} "$DOMAIN" "$TOKEN" --set-default - ${attic} use ${config.swarselsystems.mainUser} - ''; + script = + let + attic = lib.getExe pkgs.attic-client; + in + '' + set -eu + if ${attic} cache info ${config.swarselsystems.mainUser} >/dev/null 2>&1; then + echo "cache already authenticated" + exit 0 + fi + echo "cache not authenticated, attempting login..." + ${attic} login ${config.swarselsystems.mainUser} "$DOMAIN" "$TOKEN" --set-default + ${attic} use ${config.swarselsystems.mainUser} + ''; }; @@ -12331,15 +12332,17 @@ In order to define a new wireguard interface, I have to: inherit (cfg) interfaces; ifaceList = builtins.attrValues interfaces; in - { - options = { - swarselmodules.server.${serviceName} = - lib.mkEnableOption "enable ${serviceName} settings"; + { + options = { + swarselmodules.server.${serviceName} = + lib.mkEnableOption "enable ${serviceName} settings"; - swarselsystems.server.wireguard = { - interfaces = let + swarselsystems.server.wireguard = { + interfaces = + let topConfig = config; - in lib.mkOption { + in + lib.mkOption { type = lib.types.attrsOf (lib.types.submodule ({ config, name, ... }: { options = { isServer = lib.mkEnableOption "set this interface as a wireguard server"; @@ -12357,9 +12360,9 @@ In order to define a new wireguard interface, I have to: let serverCfg = nodes.${config.serverName}.config; in - if serverCfg.swarselsystems.isCloud - then serverCfg.node.name - else "home"; + if serverCfg.swarselsystems.isCloud + then serverCfg.node.name + else "home"; readOnly = true; description = "Prefix used to look up the server network in globals.networks.\"-wg\"."; }; @@ -12386,55 +12389,55 @@ In order to define a new wireguard interface, I have to: default = { }; description = "WireGuard interfaces defined on this host."; }; - }; }; + }; - config = lib.mkIf config.swarselmodules.server.${serviceName} { + config = lib.mkIf config.swarselmodules.server.${serviceName} { - assertions = lib.concatLists ( - lib.flip lib.mapAttrsToList interfaces ( - ifName: ifCfg: + assertions = lib.concatLists ( + lib.flip lib.mapAttrsToList interfaces ( + ifName: ifCfg: let assertionPrefix = "While evaluating the wireguard network ${ifName}:"; in - [ - { - assertion = ifCfg.isServer || (ifCfg.isClient && ifCfg.serverName != ""); - message = "${assertionPrefix}: This node must either be a server for the wireguard network or a client with serverName set."; - } - { - assertion = lib.stringLength ifName < 16; - message = "${assertionPrefix}: The specified linkName '${ifName}' is too long (must be max 15 characters)."; - } - ] - ) - ); - - topology.self.interfaces = lib.mapAttrs' - (wgName: _: - lib.nameValuePair "${wgName}" { - network = wgName; - } - ) - config.swarselsystems.server.wireguard.interfaces; - - environment.systemPackages = with pkgs; [ - wireguard-tools - ]; - - sops.secrets = - lib.mkMerge ( [ { - wireguard-private-key = { - inherit sopsFile; - owner = serviceUser; - group = serviceGroup; - mode = "0600"; - }; + assertion = ifCfg.isServer || (ifCfg.isClient && ifCfg.serverName != ""); + message = "${assertionPrefix}: This node must either be a server for the wireguard network or a client with serverName set."; } - ] ++ (map - (i: + { + assertion = lib.stringLength ifName < 16; + message = "${assertionPrefix}: The specified linkName '${ifName}' is too long (must be max 15 characters)."; + } + ] + ) + ); + + topology.self.interfaces = lib.mapAttrs' + (wgName: _: + lib.nameValuePair "${wgName}" { + network = wgName; + } + ) + config.swarselsystems.server.wireguard.interfaces; + + environment.systemPackages = with pkgs; [ + wireguard-tools + ]; + + sops.secrets = + lib.mkMerge ( + [ + { + wireguard-private-key = { + inherit sopsFile; + owner = serviceUser; + group = serviceGroup; + mode = "0600"; + }; + } + ] ++ (map + (i: let clientSecrets = lib.optionalAttrs i.isClient { @@ -12459,26 +12462,26 @@ In order to define a new wireguard interface, I have to: }) i.peers)); in - clientSecrets // serverSecrets - ) - ifaceList) - ); - - networking.firewall = { - checkReversePath = lib.mkIf (lib.any (i: i.isClient) ifaceList) "loose"; - allowedUDPPorts = lib.mkMerge ( - lib.flip lib.mapAttrsToList interfaces ( - _: ifCfg: - lib.optional ifCfg.isServer ifCfg.port + clientSecrets // serverSecrets ) - ); - }; + ifaceList) + ); - networking.nftables.firewall = { - zones = lib.mkMerge - ( - lib.flip lib.mapAttrsToList interfaces ( - ifName: ifCfg: + networking.firewall = { + checkReversePath = lib.mkIf (lib.any (i: i.isClient) ifaceList) "loose"; + allowedUDPPorts = lib.mkMerge ( + lib.flip lib.mapAttrsToList interfaces ( + _: ifCfg: + lib.optional ifCfg.isServer ifCfg.port + ) + ); + }; + + networking.nftables.firewall = { + zones = lib.mkMerge + ( + lib.flip lib.mapAttrsToList interfaces ( + ifName: ifCfg: { ${ifName}.interfaces = [ ifName ]; } @@ -12487,30 +12490,30 @@ In order to define a new wireguard interface, I have to: let peerNet = globals.networks."${ifCfg.serverNetConfigPrefix}-${ifName}".hosts.${peer}; in - lib.nameValuePair "${ifName}-node-${peer}" { - parent = ifName; - ipv4Addresses = lib.optional (peerNet.ipv4 != null) peerNet.ipv4; - ipv6Addresses = lib.optional (peerNet.ipv6 != null) peerNet.ipv6; - } + lib.nameValuePair "${ifName}-node-${peer}" { + parent = ifName; + ipv4Addresses = lib.optional (peerNet.ipv4 != null) peerNet.ipv4; + ipv6Addresses = lib.optional (peerNet.ipv6 != null) peerNet.ipv6; + } ) ifCfg.peers) - ) - ); - rules = lib.mkMerge ( - lib.flip lib.mapAttrsToList interfaces ( - ifName: ifCfg: + ) + ); + rules = lib.mkMerge ( + lib.flip lib.mapAttrsToList interfaces ( + ifName: ifCfg: let inherit (config.networking.nftables.firewall) localZoneName; netCfg = globals.networks."${ifCfg.serverNetConfigPrefix}-${ifName}"; in - { - "${ifName}-to-${localZoneName}" = { - inherit (netCfg.firewallRuleForAll) allowedTCPPorts allowedUDPPorts allowedTCPPortRanges allowedUDPPortRanges; - from = [ ifName ]; - to = [ localZoneName ]; - ignoreEmptyRule = true; - }; - } + { + "${ifName}-to-${localZoneName}" = { + inherit (netCfg.firewallRuleForAll) allowedTCPPorts allowedUDPPorts allowedTCPPortRanges allowedUDPPortRanges; + from = [ ifName ]; + to = [ localZoneName ]; + ignoreEmptyRule = true; + }; + } // lib.listToAttrs (map (peer: lib.nameValuePair "${ifName}-node-${peer}-to-${localZoneName}" ( @@ -12523,75 +12526,75 @@ In order to define a new wireguard interface, I have to: ) ) ifCfg.peers) - ) - ); - }; + ) + ); + }; - systemd.network = { - enable = true; + systemd.network = { + enable = true; - networks = lib.mkMerge (map - (i: + networks = lib.mkMerge (map + (i: let inherit (i) ifName; in - { - "50-${ifName}" = { - matchConfig.Name = ifName; - linkConfig = { - MTUBytes = 1408; # TODO: figure out where we lose those 12 bits (8 from pppoe maybe + ???) - }; - - address = [ - globals.networks."${i.serverNetConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv4 - globals.networks."${i.serverNetConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv6 - ]; + { + "50-${ifName}" = { + matchConfig.Name = ifName; + linkConfig = { + MTUBytes = 1408; # TODO: figure out where we lose those 12 bits (8 from pppoe maybe + ???) }; - }) - ifaceList); - netdevs = lib.mkMerge (map - (i: + address = [ + globals.networks."${i.serverNetConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv4 + globals.networks."${i.serverNetConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv6 + ]; + }; + }) + ifaceList); + + netdevs = lib.mkMerge (map + (i: let inherit (i) ifName; in - { - "50-${ifName}" = { - netdevConfig = { - Kind = "wireguard"; - Name = ifName; - }; + { + "50-${ifName}" = { + netdevConfig = { + Kind = "wireguard"; + Name = ifName; + }; - wireguardConfig = { - ListenPort = lib.mkIf i.isServer servicePort; + wireguardConfig = { + ListenPort = lib.mkIf i.isServer servicePort; - PrivateKeyFile = config.sops.secrets.wireguard-private-key.path; + PrivateKeyFile = config.sops.secrets.wireguard-private-key.path; - RouteTable = lib.mkIf i.isClient "main"; - }; + RouteTable = lib.mkIf i.isClient "main"; + }; - wireguardPeers = - lib.optionals i.isClient [ - { - PublicKey = - builtins.readFile "${self}/secrets/public/wg/${i.serverName}.pub"; + wireguardPeers = + lib.optionals i.isClient [ + { + PublicKey = + builtins.readFile "${self}/secrets/public/wg/${i.serverName}.pub"; - PresharedKeyFile = - config.sops.secrets."wireguard-${i.serverName}-${config.node.name}-${i.ifName}-presharedKey".path; + PresharedKeyFile = + config.sops.secrets."wireguard-${i.serverName}-${config.node.name}-${i.ifName}-presharedKey".path; - Endpoint = - "server.${i.serverName}.${globals.domains.main}:${toString servicePort}"; + Endpoint = + "server.${i.serverName}.${globals.domains.main}:${toString servicePort}"; - PersistentKeepalive = 25; + PersistentKeepalive = 25; - AllowedIPs = - let - wgNetwork = globals.networks."${i.serverNetConfigPrefix}-${i.ifName}"; - in - (lib.optional (wgNetwork.cidrv4 != null) wgNetwork.cidrv4) + AllowedIPs = + let + wgNetwork = globals.networks."${i.serverNetConfigPrefix}-${i.ifName}"; + in + (lib.optional (wgNetwork.cidrv4 != null) wgNetwork.cidrv4) ++ (lib.optional (wgNetwork.cidrv6 != null) wgNetwork.cidrv6); - } - ] + } + ] ++ lib.optionals i.isServer (map (clientName: { PublicKey = @@ -12605,18 +12608,18 @@ In order to define a new wireguard interface, I have to: clientInWgNetwork = globals.networks."${i.serverNetConfigPrefix}-${i.ifName}".hosts.${clientName}; in - (lib.optional (clientInWgNetwork.ipv4 != null) - (lib.net.cidr.make 32 clientInWgNetwork.ipv4)) + (lib.optional (clientInWgNetwork.ipv4 != null) + (lib.net.cidr.make 32 clientInWgNetwork.ipv4)) ++ (lib.optional (clientInWgNetwork.ipv6 != null) (lib.net.cidr.make 128 clientInWgNetwork.ipv6)); }) i.peers); - }; - }) - ifaceList); - }; + }; + }) + ifaceList); }; - } + }; + } #+end_src **** BTRFS @@ -13470,7 +13473,7 @@ Needed for audio and stuff. Many services require a databasee, and I like to go with full postgres when giving the chance. Each host will usually run its own instance instead of maintaining a centralised one. #+begin_src nix-ts :tangle modules/nixos/server/postgresql.nix - { self, config, lib, pkgs, confLib, ... }: + { config, lib, pkgs, confLib, ... }: let inherit (confLib.gen { name = "postgresql"; port = 3254; }) serviceName; postgresVersion = 14; @@ -13546,7 +13549,7 @@ Allows me to spin up containers for services that do not provide NixOS options. }; local-to-podman = { - from = [ "local" "wgProxy" "wgHome"]; + from = [ "local" "wgProxy" "wgHome" ]; to = [ "podman" ]; before = [ "drop" ]; verdict = "accept"; @@ -13992,7 +13995,7 @@ My file server. I aim to decomission this as soon as I can, however, I need a re globals.services.${serviceName} = { domain = serviceDomain; inherit proxyAddress4 proxyAddress6 isHome serviceAddress; - homeServiceAddress = lib.mkIf isHome homeServiceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { @@ -14155,140 +14158,140 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= gotenbergPort = 3002; kanidmDomain = globals.services.kanidm.domain; 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} { - users = { - persistentIds = { - redis-paperless = confLib.mkIds 975; + users = { + persistentIds = { + redis-paperless = confLib.mkIds 975; + }; + users.${serviceUser} = { + extraGroups = [ "users" ]; + }; + }; + + sops.secrets = { + paperless-admin-pw = { inherit sopsFile; owner = serviceUser; }; + kanidm-paperless-client = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + }; + + # networking.firewall.allowedTCPPorts = [ servicePort ]; + + globals = { + networks = { + ${webProxyIf}.hosts = lib.mkIf isProxied { + ${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ]; }; - users.${serviceUser} = { - extraGroups = [ "users" ]; + ${homeProxyIf}.hosts = lib.mkIf isHome { + ${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ]; }; }; - - sops.secrets = { - paperless-admin-pw = { inherit sopsFile; owner = serviceUser; }; - kanidm-paperless-client = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6 isHome serviceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; + }; - # networking.firewall.allowedTCPPorts = [ servicePort ]; + 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"; } + ]; + }; - globals = { - networks = { - ${webProxyIf}.hosts = lib.mkIf isProxied { - ${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ]; + services = { + ${serviceName} = { + enable = true; + mediaDir = "/storage/Documents/${serviceName}"; + dataDir = "/var/lib/${serviceName}"; + user = serviceUser; + port = servicePort; + passwordFile = config.sops.secrets.paperless-admin-pw.path; + address = "0.0.0.0"; + settings = { + PAPERLESS_OCR_LANGUAGE = "deu+eng"; + PAPERLESS_URL = "https://${serviceDomain}"; + PAPERLESS_OCR_USER_ARGS = builtins.toJSON { + optimize = 1; + invalidate_digital_signatures = true; + pdfa_image_compression = "lossless"; }; - ${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/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 = "/storage/Documents/${serviceName}"; - dataDir = "/var/lib/${serviceName}"; - user = serviceUser; - port = servicePort; - passwordFile = config.sops.secrets.paperless-admin-pw.path; - address = "0.0.0.0"; - settings = { - PAPERLESS_OCR_LANGUAGE = "deu+eng"; - PAPERLESS_URL = "https://${serviceDomain}"; - PAPERLESS_OCR_USER_ARGS = builtins.toJSON { - optimize = 1; - invalidate_digital_signatures = true; - pdfa_image_compression = "lossless"; - }; - PAPERLESS_TIKA_ENABLED = "true"; - PAPERLESS_TIKA_ENDPOINT = "http://localhost:${builtins.toString tikaPort}"; - PAPERLESS_TIKA_GOTENBERG_ENDPOINT = "http://localhost:${builtins.toString gotenbergPort}"; - PAPERLESS_APPS = "allauth.socialaccount.providers.openid_connect"; - PAPERLESS_SOCIALACCOUNT_PROVIDERS = builtins.toJSON { - openid_connect = { - OAUTH_PKCE_ENABLED = "True"; - APPS = [ - rec { - provider_id = "kanidm"; - name = "Kanidm"; - client_id = "paperless"; - # secret will be added by paperless-web.service (see below) - #secret = ""; - settings.server_url = "https://${kanidmDomain}/oauth2/openid/${client_id}/.well-known/openid-configuration"; - } - ]; - }; + PAPERLESS_TIKA_ENABLED = "true"; + PAPERLESS_TIKA_ENDPOINT = "http://localhost:${builtins.toString tikaPort}"; + PAPERLESS_TIKA_GOTENBERG_ENDPOINT = "http://localhost:${builtins.toString gotenbergPort}"; + PAPERLESS_APPS = "allauth.socialaccount.providers.openid_connect"; + PAPERLESS_SOCIALACCOUNT_PROVIDERS = builtins.toJSON { + openid_connect = { + OAUTH_PKCE_ENABLED = "True"; + APPS = [ + rec { + provider_id = "kanidm"; + name = "Kanidm"; + client_id = "paperless"; + # secret will be added by paperless-web.service (see below) + #secret = ""; + settings.server_url = "https://${kanidmDomain}/oauth2/openid/${client_id}/.well-known/openid-configuration"; + } + ]; }; }; }; - - tika = { - enable = true; - port = tikaPort; - openFirewall = false; - listenAddress = "127.0.0.1"; - enableOcr = true; - }; - - gotenberg = { - enable = true; - package = pkgs.gotenberg; - libreoffice.package = pkgs.libreoffice; - port = gotenbergPort; - bindIP = "127.0.0.1"; - timeout = "600s"; - chromium.package = pkgs.chromium; - }; }; + tika = { + enable = true; + port = tikaPort; + openFirewall = false; + listenAddress = "127.0.0.1"; + enableOcr = true; + }; - # Add secret to PAPERLESS_SOCIALACCOUNT_PROVIDERS - systemd.services.paperless-web.script = lib.mkBefore '' + gotenberg = { + enable = true; + package = pkgs.gotenberg; + libreoffice.package = pkgs.libreoffice; + port = gotenbergPort; + bindIP = "127.0.0.1"; + timeout = "600s"; + chromium.package = pkgs.chromium; + }; + }; + + + # Add secret to PAPERLESS_SOCIALACCOUNT_PROVIDERS + systemd.services.paperless-web.script = lib.mkBefore '' oidcSecret=$(< ${config.sops.secrets.kanidm-paperless-client.path}) export PAPERLESS_SOCIALACCOUNT_PROVIDERS=$( ${pkgs.jq}/bin/jq <<< "$PAPERLESS_SOCIALACCOUNT_PROVIDERS" \ --compact-output \ --arg oidcSecret "$oidcSecret" '.openid_connect.APPS.[0].secret = $oidcSecret' ) - ''; + ''; - nodes = - let - extraConfigLoc = '' + nodes = + let + extraConfigLoc = '' proxy_connect_timeout 300; proxy_send_timeout 300; proxy_read_timeout 300; send_timeout 300; - ''; - 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; }); - }; + ''; + 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 **** transmission @@ -14321,233 +14324,232 @@ I use this configuration for sailing. prowlarrGroup = prowlarrUser; prowlarrPort = 9696; in - { - options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} and friends on server"; - config = lib.mkIf config.swarselmodules.server.${serviceName} { + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} and friends on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { - sops.secrets = { - pia = { inherit sopsFile; }; + sops.secrets = { + pia = { inherit sopsFile; }; + }; + + # this user/group section is probably unneeded + users = { + persistentIds = { + prowlarr = confLib.mkIds 971; + readarr = confLib.mkIds 970; + }; + groups = { + dockeruser = { + gid = 1155; + }; + "${radarrGroup}" = { }; + "${readarrGroup}" = { }; + "${sonarrGroup}" = { }; + "${lidarrGroup}" = { }; + "${prowlarrGroup}" = { }; }; - - # this user/group section is probably unneeded users = { - persistentIds = { - prowlarr = confLib.mkIds 971; - readarr = confLib.mkIds 970; + dockeruser = { + isSystemUser = true; + uid = 1155; + group = "docker"; + extraGroups = [ "users" ]; }; - groups = { - dockeruser = { - gid = 1155; - }; - "${radarrGroup}" = { }; - "${readarrGroup}" = { }; - "${sonarrGroup}" = { }; - "${lidarrGroup}" = { }; - "${prowlarrGroup}" = { }; - }; - users = { - dockeruser = { - isSystemUser = true; - uid = 1155; - group = "docker"; - extraGroups = [ "users" ]; - }; - "${radarrUser}" = { - isSystemUser = true; - group = radarrGroup; - extraGroups = [ "users" ]; - }; - "${readarrGroup}" = { - isSystemUser = true; - group = readarrGroup; - extraGroups = [ "users" ]; - }; - "${sonarrGroup}" = { - isSystemUser = true; - group = sonarrGroup; - extraGroups = [ "users" ]; - }; - "${lidarrUser}" = { - isSystemUser = true; - group = lidarrGroup; - extraGroups = [ "users" ]; - }; - "${prowlarrGroup}" = { - isSystemUser = true; - group = prowlarrGroup; - extraGroups = [ "users" ]; - }; - }; - }; - - virtualisation.docker.enable = true; - environment.systemPackages = with pkgs; [ - docker - ]; - - topology.self.services = { - radarr.info = "https://${serviceDomain}/radarr"; - readarr = { - name = "Readarr"; - info = "https://${serviceDomain}/readarr"; - icon = "${self}/files/topology-images/readarr.png"; - }; - sonarr.info = "https://${serviceDomain}/sonarr"; - lidarr.info = "https://${serviceDomain}/lidarr"; - prowlarr.info = "https://${serviceDomain}/prowlarr"; - }; - - globals.services.transmission = { - domain = serviceDomain; - 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 = { - pia = { - enable = true; - credentials.credentialsFile = config.sops.secrets.pia.path; - protocol = "wireguard"; - autoConnect = { - enable = true; - region = "sweden"; - }; - portForwarding.enable = true; - dns.enable = true; - }; - radarr = { - enable = true; - user = radarrUser; + "${radarrUser}" = { + isSystemUser = true; group = radarrGroup; - settings.server.port = radarrPort; - openFirewall = true; - dataDir = "/var/lib/radarr"; + extraGroups = [ "users" ]; }; - readarr = { - enable = true; - user = readarrUser; + "${readarrGroup}" = { + isSystemUser = true; group = readarrGroup; - settings.server.port = readarrPort; - openFirewall = true; - dataDir = "/var/lib/readarr"; + extraGroups = [ "users" ]; }; - sonarr = { - enable = true; - user = sonarrUser; + "${sonarrGroup}" = { + isSystemUser = true; group = sonarrGroup; - settings.server.port = sonarrPort; - openFirewall = true; - dataDir = "/var/lib/sonarr"; + extraGroups = [ "users" ]; }; - lidarr = { - enable = true; - user = lidarrUser; + "${lidarrUser}" = { + isSystemUser = true; group = lidarrGroup; - settings.server.port = lidarrPort; - openFirewall = true; - dataDir = "/var/lib/lidarr"; + extraGroups = [ "users" ]; }; - prowlarr = { - enable = true; - settings.server.port = prowlarrPort; - openFirewall = true; + "${prowlarrGroup}" = { + isSystemUser = true; + group = prowlarrGroup; + extraGroups = [ "users" ]; }; }; + }; - 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}" = { }; - }; + virtualisation.docker.enable = true; + environment.systemPackages = with pkgs; [ + docker + ]; + + topology.self.services = { + radarr.info = "https://${serviceDomain}/radarr"; + readarr = { + name = "Readarr"; + info = "https://${serviceDomain}/readarr"; + icon = "${self}/files/topology-images/readarr.png"; + }; + sonarr.info = "https://${serviceDomain}/sonarr"; + lidarr.info = "https://${serviceDomain}/lidarr"; + prowlarr.info = "https://${serviceDomain}/prowlarr"; + }; + + globals.services.transmission = { + domain = serviceDomain; + 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 = { + pia = { + enable = true; + credentials.credentialsFile = config.sops.secrets.pia.path; + protocol = "wireguard"; + autoConnect = { + enable = true; + region = "sweden"; + }; + portForwarding.enable = true; + dns.enable = true; + }; + radarr = { + enable = true; + user = radarrUser; + group = radarrGroup; + settings.server.port = radarrPort; + openFirewall = true; + dataDir = "/var/lib/radarr"; + }; + readarr = { + enable = true; + user = readarrUser; + group = readarrGroup; + settings.server.port = readarrPort; + openFirewall = true; + dataDir = "/var/lib/readarr"; + }; + sonarr = { + enable = true; + user = sonarrUser; + group = sonarrGroup; + settings.server.port = sonarrPort; + openFirewall = true; + dataDir = "/var/lib/sonarr"; + }; + lidarr = { + enable = true; + user = lidarrUser; + group = lidarrGroup; + settings.server.port = lidarrPort; + openFirewall = true; + dataDir = "/var/lib/lidarr"; + }; + prowlarr = { + enable = true; + settings.server.port = prowlarrPort; + openFirewall = true; + }; + }; + + nodes = { + ${homeWebProxy}.services.nginx = { + upstreams = { + transmission = { + servers = { + "${homeServiceAddress}:${builtins.toString servicePort}" = { }; }; }; - virtualHosts = { - "${serviceDomain}" = { - enableACME = false; - forceSSL = false; - acmeRoot = null; - extraConfig = nginxAccessRules; - locations = { - "/" = { - proxyPass = "http://transmission"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "/radarr" = { - proxyPass = "http://radarr"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "/readarr" = { - proxyPass = "http://readarr"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "/sonarr" = { - proxyPass = "http://sonarr"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "/lidarr" = { - proxyPass = "http://lidarr"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "/prowlarr" = { - proxyPass = "http://prowlarr"; - extraConfig = '' - client_max_body_size 0; - ''; - }; + 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://transmission"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "/radarr" = { + proxyPass = "http://radarr"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "/readarr" = { + proxyPass = "http://readarr"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "/sonarr" = { + proxyPass = "http://sonarr"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "/lidarr" = { + proxyPass = "http://lidarr"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "/prowlarr" = { + proxyPass = "http://prowlarr"; + extraConfig = '' + client_max_body_size 0; + ''; }; }; }; }; }; }; - } - + }; + } #+end_src **** syncthing @@ -14861,7 +14863,7 @@ 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 = {}; + groups.nextcloud-exporter = { }; users = { nextcloud-exporter = { group = "nextcloud-exporter"; @@ -15269,7 +15271,7 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with globals.services.${serviceName} = { domain = serviceDomain; inherit proxyAddress4 proxyAddress6 isHome serviceAddress; - homeServiceAddress = lib.mkIf isHome homeServiceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { @@ -15632,386 +15634,385 @@ kanidm person credential create-reset-token else "${keyPathBase}"; 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} { - users = { - persistentIds = { - kanidm = confLib.mkIds 984; - }; - users.${serviceUser} = { - group = serviceGroup; - isSystemUser = true; - }; - - groups.${serviceGroup} = { }; + users = { + persistentIds = { + kanidm = confLib.mkIds 984; + }; + users.${serviceUser} = { + group = serviceGroup; + isSystemUser = true; }; - sops = { - secrets = { - "kanidm-self-signed-crt" = { sopsFile = certsSopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-self-signed-key" = { sopsFile = certsSopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-admin-pw" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-idm-admin-pw" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-immich" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-paperless" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-forgejo" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-grafana" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-nextcloud" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-freshrss" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-oauth2-proxy" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + groups.${serviceGroup} = { }; + }; + + sops = { + secrets = { + "kanidm-self-signed-crt" = { sopsFile = certsSopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-self-signed-key" = { sopsFile = certsSopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-admin-pw" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-idm-admin-pw" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-immich" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-paperless" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-forgejo" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-grafana" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-nextcloud" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-freshrss" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-oauth2-proxy" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + }; + }; + + # networking.firewall.allowedTCPPorts = [ servicePort ]; + + globals = { + general.idmServer = config.node.name; + 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; + }; + }; - # networking.firewall.allowedTCPPorts = [ servicePort ]; + environment.persistence = { + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + files = [ + certPathBase + keyPathBase + ]; + }; - globals = { - general.idmServer = config.node.name; - networks = { - ${webProxyIf}.hosts = lib.mkIf isProxied { - ${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ]; + "/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + }; + + systemd.services = { + "generateSSLCert-${serviceName}" = + let + daysValid = 3650; + renewBeforeDays = 365; + in + { + before = [ "${serviceName}.service" ]; + requiredBy = [ "${serviceName}.service" ]; + after = [ "local-fs.target" ]; + requires = [ "local-fs.target" ]; + + serviceConfig = { + Type = "oneshot"; }; - ${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 = { - "/persist" = lib.mkIf config.swarselsystems.isImpermanence { - files = [ - certPathBase - keyPathBase - ]; - }; + script = '' + set -eu - "/state" = lib.mkIf config.swarselsystems.isMicroVM { - directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; - }; - }; + ${pkgs.coreutils}/bin/install -d -m 0755 ${certsDir} + ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0755 /persist${certsDir}" else ""} + ${pkgs.coreutils}/bin/install -d -m 0750 ${privateDir} + ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0750 /persist${privateDir}" else ""} - systemd.services = { - "generateSSLCert-${serviceName}" = - let - daysValid = 3650; - renewBeforeDays = 365; - in - { - before = [ "${serviceName}.service" ]; - requiredBy = [ "${serviceName}.service" ]; - after = [ "local-fs.target" ]; - requires = [ "local-fs.target" ]; - - serviceConfig = { - Type = "oneshot"; - }; - - script = '' - set -eu - - ${pkgs.coreutils}/bin/install -d -m 0755 ${certsDir} - ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0755 /persist${certsDir}" else ""} - ${pkgs.coreutils}/bin/install -d -m 0750 ${privateDir} - ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0750 /persist${privateDir}" else ""} - - need_gen=0 - if [ ! -f "${certPath}" ] || [ ! -f "${keyPath}" ]; then - need_gen=1 - else - enddate="$(${pkgs.openssl}/bin/openssl x509 -noout -enddate -in "${certPath}" | cut -d= -f2)" - end_epoch="$(${pkgs.coreutils}/bin/date -d "$enddate" +%s)" - now_epoch="$(${pkgs.coreutils}/bin/date +%s)" - seconds_left=$(( end_epoch - now_epoch )) - days_left=$(( seconds_left / 86400 )) - if [ "$days_left" -lt ${toString renewBeforeDays} ]; then + need_gen=0 + if [ ! -f "${certPath}" ] || [ ! -f "${keyPath}" ]; then need_gen=1 else - echo 'Certificate exists and is still valid' + enddate="$(${pkgs.openssl}/bin/openssl x509 -noout -enddate -in "${certPath}" | cut -d= -f2)" + end_epoch="$(${pkgs.coreutils}/bin/date -d "$enddate" +%s)" + now_epoch="$(${pkgs.coreutils}/bin/date +%s)" + seconds_left=$(( end_epoch - now_epoch )) + days_left=$(( seconds_left / 86400 )) + if [ "$days_left" -lt ${toString renewBeforeDays} ]; then + need_gen=1 + else + echo 'Certificate exists and is still valid' + fi fi - fi - if [ "$need_gen" -eq 1 ]; then - ${pkgs.openssl}/bin/openssl req -x509 -nodes -days ${toString daysValid} -newkey rsa:4096 -sha256 \ - -keyout "${keyPath}" \ - -out "${certPath}" \ - -subj "/CN=${serviceDomain}" \ - -addext "subjectAltName=DNS:${serviceDomain}" + if [ "$need_gen" -eq 1 ]; then + ${pkgs.openssl}/bin/openssl req -x509 -nodes -days ${toString daysValid} -newkey rsa:4096 -sha256 \ + -keyout "${keyPath}" \ + -out "${certPath}" \ + -subj "/CN=${serviceDomain}" \ + -addext "subjectAltName=DNS:${serviceDomain}" - chmod 0644 "${certPath}" - chmod 0600 "${keyPath}" - chown ${serviceUser}:${serviceGroup} "${certPath}" "${keyPath}" - fi - ''; - }; - kanidm = { - environment.KANIDM_TRUST_X_FORWARD_FOR = "true"; - serviceConfig.RestartSec = "30"; + chmod 0644 "${certPath}" + chmod 0600 "${keyPath}" + chown ${serviceUser}:${serviceGroup} "${certPath}" "${keyPath}" + fi + ''; }; + kanidm = { + environment.KANIDM_TRUST_X_FORWARD_FOR = "true"; + serviceConfig.RestartSec = "30"; }; + }; - # system.activationScripts."createPersistentStorageDirs" = lib.mkIf config.swarselsystems.isImpermanence { - # deps = [ "generateSSLCert-${serviceName}" "users" "groups" ]; - # }; - # system.activationScripts."generateSSLCert-${serviceName}" = - # let - # daysValid = 3650; - # renewBeforeDays = 365; - # in - # { - # text = '' - # set -eu + # system.activationScripts."createPersistentStorageDirs" = lib.mkIf config.swarselsystems.isImpermanence { + # deps = [ "generateSSLCert-${serviceName}" "users" "groups" ]; + # }; + # system.activationScripts."generateSSLCert-${serviceName}" = + # let + # daysValid = 3650; + # renewBeforeDays = 365; + # in + # { + # text = '' + # set -eu - # ${pkgs.coreutils}/bin/install -d -m 0755 ${certsDir} - # ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0755 /persist${certsDir}" else ""} - # ${pkgs.coreutils}/bin/install -d -m 0750 ${privateDir} - # ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0750 /persist${privateDir}" else ""} + # ${pkgs.coreutils}/bin/install -d -m 0755 ${certsDir} + # ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0755 /persist${certsDir}" else ""} + # ${pkgs.coreutils}/bin/install -d -m 0750 ${privateDir} + # ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0750 /persist${privateDir}" else ""} - # need_gen=0 - # if [ ! -f "${certPathBase}" ] || [ ! -f "${keyPathBase}" ]; then - # need_gen=1 - # else - # enddate="$(${pkgs.openssl}/bin/openssl x509 -noout -enddate -in "${certPathBase}" | cut -d= -f2)" - # end_epoch="$(${pkgs.coreutils}/bin/date -d "$enddate" +%s)" - # now_epoch="$(${pkgs.coreutils}/bin/date +%s)" - # seconds_left=$(( end_epoch - now_epoch )) - # days_left=$(( seconds_left / 86400 )) - # if [ "$days_left" -lt ${toString renewBeforeDays} ]; then - # need_gen=1 - # fi - # fi + # need_gen=0 + # if [ ! -f "${certPathBase}" ] || [ ! -f "${keyPathBase}" ]; then + # need_gen=1 + # else + # enddate="$(${pkgs.openssl}/bin/openssl x509 -noout -enddate -in "${certPathBase}" | cut -d= -f2)" + # end_epoch="$(${pkgs.coreutils}/bin/date -d "$enddate" +%s)" + # now_epoch="$(${pkgs.coreutils}/bin/date +%s)" + # seconds_left=$(( end_epoch - now_epoch )) + # days_left=$(( seconds_left / 86400 )) + # if [ "$days_left" -lt ${toString renewBeforeDays} ]; then + # need_gen=1 + # fi + # fi - # if [ "$need_gen" -eq 1 ]; then - # ${pkgs.openssl}/bin/openssl req -x509 -nodes -days ${toString daysValid} -newkey rsa:4096 -sha256 \ - # -keyout "${keyPath}" \ - # -out "${certPath}" \ - # -subj "/CN=${serviceDomain}" \ - # -addext "subjectAltName=DNS:${serviceDomain}" + # if [ "$need_gen" -eq 1 ]; then + # ${pkgs.openssl}/bin/openssl req -x509 -nodes -days ${toString daysValid} -newkey rsa:4096 -sha256 \ + # -keyout "${keyPath}" \ + # -out "${certPath}" \ + # -subj "/CN=${serviceDomain}" \ + # -addext "subjectAltName=DNS:${serviceDomain}" - # chmod 0644 "${certPath}" - # chmod 0600 "${keyPath}" - # chown ${serviceUser}:${serviceGroup} "${certPath}" "${keyPath}" - # fi - # ''; - # deps = [ - # "etc" - # (lib.mkIf config.swarselsystems.isImpermanence "specialfs") - # ]; - # }; + # chmod 0644 "${certPath}" + # chmod 0600 "${keyPath}" + # chown ${serviceUser}:${serviceGroup} "${certPath}" "${keyPath}" + # fi + # ''; + # deps = [ + # "etc" + # (lib.mkIf config.swarselsystems.isImpermanence "specialfs") + # ]; + # }; - services = { - ${serviceName} = { - package = pkgs.kanidmWithSecretProvisioning_1_9; - server = { - enable = true; - settings = { - domain = serviceDomain; - origin = "https://${serviceDomain}"; - # tls_chain = config.sops.secrets.kanidm-self-signed-crt.path; - tls_chain = certPathBase; - # tls_key = config.sops.secrets.kanidm-self-signed-key.path; - tls_key = keyPathBase; - bindaddress = "0.0.0.0:${toString servicePort}"; - # trust_x_forward_for = true; - }; + services = { + ${serviceName} = { + package = pkgs.kanidmWithSecretProvisioning_1_9; + server = { + enable = true; + settings = { + domain = serviceDomain; + origin = "https://${serviceDomain}"; + # tls_chain = config.sops.secrets.kanidm-self-signed-crt.path; + tls_chain = certPathBase; + # tls_key = config.sops.secrets.kanidm-self-signed-key.path; + tls_key = keyPathBase; + bindaddress = "0.0.0.0:${toString servicePort}"; + # trust_x_forward_for = true; }; - client = { - enable = true; - settings = { - uri = config.services.kanidm.server.settings.origin; - verify_ca = true; - verify_hostnames = true; - }; + }; + client = { + enable = true; + settings = { + uri = config.services.kanidm.server.settings.origin; + verify_ca = true; + verify_hostnames = true; + }; + }; + provision = { + enable = true; + adminPasswordFile = config.sops.secrets.kanidm-admin-pw.path; + idmAdminPasswordFile = config.sops.secrets.kanidm-idm-admin-pw.path; + groups = { + "immich.access" = { }; + "paperless.access" = { }; + "forgejo.access" = { }; + "forgejo.admins" = { }; + "grafana.access" = { }; + "grafana.editors" = { }; + "grafana.admins" = { }; + "grafana.server-admins" = { }; + "nextcloud.access" = { }; + "nextcloud.admins" = { }; + "navidrome.access" = { }; + "freshrss.access" = { }; + "firefly.access" = { }; + "radicale.access" = { }; + "slink.access" = { }; + "opkssh.access" = { }; + "adguardhome.access" = { }; }; - provision = { - enable = true; - adminPasswordFile = config.sops.secrets.kanidm-admin-pw.path; - idmAdminPasswordFile = config.sops.secrets.kanidm-idm-admin-pw.path; - groups = { - "immich.access" = { }; - "paperless.access" = { }; - "forgejo.access" = { }; - "forgejo.admins" = { }; - "grafana.access" = { }; - "grafana.editors" = { }; - "grafana.admins" = { }; - "grafana.server-admins" = { }; - "nextcloud.access" = { }; - "nextcloud.admins" = { }; - "navidrome.access" = { }; - "freshrss.access" = { }; - "firefly.access" = { }; - "radicale.access" = { }; - "slink.access" = { }; - "opkssh.access" = { }; - "adguardhome.access" = { }; - }; - inherit (config.repo.secrets.local) persons; + inherit (config.repo.secrets.local) persons; - systems = { - oauth2 = { - immich = { - displayName = "Immich"; - originUrl = [ - "https://${immichDomain}/auth/login" - "https://${immichDomain}/user-settings" - "app.immich:///oauth-callback" - "https://${immichDomain}/api/oauth/mobile-redirect" - ]; - originLanding = "https://${immichDomain}/"; - basicSecretFile = config.sops.secrets.kanidm-immich.path; - preferShortUsername = true; - enableLegacyCrypto = true; # can use RS256 / HS256, not ES256 - scopeMaps."immich.access" = [ - "openid" - "email" - "profile" - ]; + systems = { + oauth2 = { + immich = { + displayName = "Immich"; + originUrl = [ + "https://${immichDomain}/auth/login" + "https://${immichDomain}/user-settings" + "app.immich:///oauth-callback" + "https://${immichDomain}/api/oauth/mobile-redirect" + ]; + originLanding = "https://${immichDomain}/"; + basicSecretFile = config.sops.secrets.kanidm-immich.path; + preferShortUsername = true; + enableLegacyCrypto = true; # can use RS256 / HS256, not ES256 + scopeMaps."immich.access" = [ + "openid" + "email" + "profile" + ]; + }; + paperless = { + displayName = "Paperless"; + originUrl = "https://${paperlessDomain}/accounts/oidc/kanidm/login/callback/"; + originLanding = "https://${paperlessDomain}/"; + basicSecretFile = config.sops.secrets.kanidm-paperless.path; + preferShortUsername = true; + scopeMaps."paperless.access" = [ + "openid" + "email" + "profile" + ]; + }; + forgejo = { + displayName = "Forgejo"; + originUrl = "https://${forgejoDomain}/user/oauth2/kanidm/callback"; + originLanding = "https://${forgejoDomain}/"; + basicSecretFile = config.sops.secrets.kanidm-forgejo.path; + scopeMaps."forgejo.access" = [ + "openid" + "email" + "profile" + ]; + # XXX: PKCE is currently not supported by gitea/forgejo, + # see https://github.com/go-gitea/gitea/issues/21376. + allowInsecureClientDisablePkce = true; + preferShortUsername = true; + claimMaps.groups = { + joinType = "array"; + valuesByGroup."forgejo.admins" = [ "admin" ]; }; - paperless = { - displayName = "Paperless"; - originUrl = "https://${paperlessDomain}/accounts/oidc/kanidm/login/callback/"; - originLanding = "https://${paperlessDomain}/"; - basicSecretFile = config.sops.secrets.kanidm-paperless.path; - preferShortUsername = true; - scopeMaps."paperless.access" = [ - "openid" - "email" - "profile" - ]; - }; - forgejo = { - displayName = "Forgejo"; - originUrl = "https://${forgejoDomain}/user/oauth2/kanidm/callback"; - originLanding = "https://${forgejoDomain}/"; - basicSecretFile = config.sops.secrets.kanidm-forgejo.path; - scopeMaps."forgejo.access" = [ - "openid" - "email" - "profile" - ]; - # XXX: PKCE is currently not supported by gitea/forgejo, - # see https://github.com/go-gitea/gitea/issues/21376. - allowInsecureClientDisablePkce = true; - preferShortUsername = true; - claimMaps.groups = { - joinType = "array"; - valuesByGroup."forgejo.admins" = [ "admin" ]; + }; + grafana = { + displayName = "Grafana"; + originUrl = "https://${grafanaDomain}/login/generic_oauth"; + originLanding = "https://${grafanaDomain}/"; + basicSecretFile = config.sops.secrets.kanidm-grafana.path; + preferShortUsername = true; + scopeMaps."grafana.access" = [ + "openid" + "email" + "profile" + ]; + claimMaps.groups = { + joinType = "array"; + valuesByGroup = { + "grafana.editors" = [ "editor" ]; + "grafana.admins" = [ "admin" ]; + "grafana.server-admins" = [ "server_admin" ]; }; }; - grafana = { - displayName = "Grafana"; - originUrl = "https://${grafanaDomain}/login/generic_oauth"; - originLanding = "https://${grafanaDomain}/"; - basicSecretFile = config.sops.secrets.kanidm-grafana.path; - preferShortUsername = true; - scopeMaps."grafana.access" = [ + }; + nextcloud = { + displayName = "Nextcloud"; + originUrl = " https://${nextcloudDomain}/apps/sociallogin/custom_oidc/kanidm"; + originLanding = "https://${nextcloudDomain}/"; + basicSecretFile = config.sops.secrets.kanidm-nextcloud.path; + allowInsecureClientDisablePkce = true; + scopeMaps."nextcloud.access" = [ + "openid" + "email" + "profile" + ]; + preferShortUsername = true; + claimMaps.groups = { + joinType = "array"; + valuesByGroup = { + "nextcloud.admins" = [ "admin" ]; + }; + }; + }; + opkssh = { + displayName = "OPKSSH"; + originUrl = [ + "http://localhost:3000" + "http://localhost:3000/login-callback" + "http://localhost:10001/login-callback" + "http://localhost:11110/login-callback" + ]; + originLanding = "http://localhost:3000"; + public = true; + enableLocalhostRedirects = true; + scopeMaps."opkssh.access" = [ + "openid" + "email" + "profile" + ]; + }; + oauth2-proxy = { + displayName = "Oauth2-Proxy"; + originUrl = "https://${oauth2ProxyDomain}/oauth2/callback"; + originLanding = "https://${oauth2ProxyDomain}/"; + basicSecretFile = config.sops.secrets.kanidm-oauth2-proxy.path; + scopeMaps = { + "freshrss.access" = [ "openid" "email" "profile" ]; - claimMaps.groups = { - joinType = "array"; - valuesByGroup = { - "grafana.editors" = [ "editor" ]; - "grafana.admins" = [ "admin" ]; - "grafana.server-admins" = [ "server_admin" ]; - }; - }; - }; - nextcloud = { - displayName = "Nextcloud"; - originUrl = " https://${nextcloudDomain}/apps/sociallogin/custom_oidc/kanidm"; - originLanding = "https://${nextcloudDomain}/"; - basicSecretFile = config.sops.secrets.kanidm-nextcloud.path; - allowInsecureClientDisablePkce = true; - scopeMaps."nextcloud.access" = [ + "navidrome.access" = [ "openid" "email" "profile" ]; - preferShortUsername = true; - claimMaps.groups = { - joinType = "array"; - valuesByGroup = { - "nextcloud.admins" = [ "admin" ]; - }; - }; - }; - opkssh = { - displayName = "OPKSSH"; - originUrl = [ - "http://localhost:3000" - "http://localhost:3000/login-callback" - "http://localhost:10001/login-callback" - "http://localhost:11110/login-callback" + "firefly.access" = [ + "openid" + "email" + "profile" ]; - originLanding = "http://localhost:3000"; - public = true; - enableLocalhostRedirects = true; - scopeMaps."opkssh.access" = [ + "radicale.access" = [ + "openid" + "email" + "profile" + ]; + "slink.access" = [ + "openid" + "email" + "profile" + ]; + "adguardhome.access" = [ "openid" "email" "profile" ]; }; - oauth2-proxy = { - displayName = "Oauth2-Proxy"; - originUrl = "https://${oauth2ProxyDomain}/oauth2/callback"; - originLanding = "https://${oauth2ProxyDomain}/"; - basicSecretFile = config.sops.secrets.kanidm-oauth2-proxy.path; - scopeMaps = { - "freshrss.access" = [ - "openid" - "email" - "profile" - ]; - "navidrome.access" = [ - "openid" - "email" - "profile" - ]; - "firefly.access" = [ - "openid" - "email" - "profile" - ]; - "radicale.access" = [ - "openid" - "email" - "profile" - ]; - "slink.access" = [ - "openid" - "email" - "profile" - ]; - "adguardhome.access" = [ - "openid" - "email" - "profile" - ]; - }; - preferShortUsername = true; - claimMaps.groups = { - joinType = "array"; - valuesByGroup = { - "freshrss.access" = [ "ttrss_access" ]; - "navidrome.access" = [ "navidrome_access" ]; - "firefly.access" = [ "firefly_access" ]; - "radicale.access" = [ "radicale_access" ]; - "slink.access" = [ "slink_access" ]; - "adguardhome.access" = [ "adguardhome_access" ]; - }; + preferShortUsername = true; + claimMaps.groups = { + joinType = "array"; + valuesByGroup = { + "freshrss.access" = [ "ttrss_access" ]; + "navidrome.access" = [ "navidrome_access" ]; + "firefly.access" = [ "firefly_access" ]; + "radicale.access" = [ "radicale_access" ]; + "slink.access" = [ "slink_access" ]; + "adguardhome.access" = [ "adguardhome_access" ]; }; }; }; @@ -16019,14 +16020,17 @@ kanidm person credential create-reset-token }; }; }; + }; - nodes = let + nodes = + let extraConfig = '' - allow ${globals.networks.home-lan.vlans.services.cidrv4}; - allow ${globals.networks.home-lan.vlans.services.cidrv6}; + allow ${globals.networks.home-lan.vlans.services.cidrv4}; + allow ${globals.networks.home-lan.vlans.services.cidrv6}; ''; - in { + in + { ${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; }; @@ -16034,8 +16038,8 @@ kanidm person credential create-reset-token ${homeWebProxy}.services.nginx = confLib.genNginx { inherit servicePort serviceDomain serviceName; protocol = "https"; noSslVerify = true; extraConfig = extraConfig + nginxAccessRules; serviceAddress = homeServiceAddress; }; }; - }; - } + }; + } #+end_src **** oauth2-proxy @@ -16277,7 +16281,7 @@ This can be used to add OIDC in a way to services that do not support it nativel ${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 servicePort serviceAddress serviceDomain serviceName extraConfig; }; + ${webProxy}.services.nginx = confLib.genNginx { inherit servicePort serviceAddress serviceDomain serviceName extraConfig; }; ${homeWebProxy}.services.nginx = confLib.genNginx { inherit servicePort serviceDomain serviceName; extraConfig = extraConfig + nginxAccessRules; serviceAddress = globals.hosts.${oauthServer}.wanAddress4; }; }; }; @@ -16333,7 +16337,7 @@ My expenses tracker. globals.services.${serviceName} = { domain = serviceDomain; inherit proxyAddress4 proxyAddress6 isHome serviceAddress; - homeServiceAddress = lib.mkIf isHome homeServiceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { @@ -16462,10 +16466,10 @@ My collection tracker. I am not too happy with its GUI, but the API is good, and }; topology.nodes.${topologyContainerName}.services.${serviceName} = { - name = lib.swarselsystems.toCapitalized serviceName; - info = "https://${serviceDomain}"; - icon = "${self}/files/topology-images/${serviceName}.png"; - }; + name = lib.swarselsystems.toCapitalized serviceName; + info = "https://${serviceDomain}"; + icon = "${self}/files/topology-images/${serviceName}.png"; + }; globals = { networks = { @@ -16479,7 +16483,7 @@ My collection tracker. I am not too happy with its GUI, but the API is good, and services.${serviceName} = { domain = serviceDomain; inherit proxyAddress4 proxyAddress6 isHome serviceAddress; - homeServiceAddress = lib.mkIf isHome homeServiceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; }; @@ -16595,51 +16599,51 @@ Used to sync shell history accross machines and have it backed up somewhere. 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} { - - swarselmodules.server = { - postgresql = true; - }; - - 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; - 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; - }; - ${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; }); - }; + { + 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 = { + 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; + 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; + }; + ${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 @@ -17034,10 +17038,10 @@ Self-hosted link shortener. }; topology.nodes.${topologyContainerName}.services.${serviceName} = { - name = lib.swarselsystems.toCapitalized serviceName; - info = "https://${serviceDomain}"; - icon = "${self}/files/topology-images/${serviceName}.png"; - }; + name = lib.swarselsystems.toCapitalized serviceName; + info = "https://${serviceDomain}"; + icon = "${self}/files/topology-images/${serviceName}.png"; + }; virtualisation.oci-containers.containers.${serviceName} = { image = "shlinkio/shlink@${containerRev}"; @@ -17144,10 +17148,10 @@ Deployment notes: }; topology.nodes.${topologyContainerName}.services.${serviceName} = { - name = lib.swarselsystems.toCapitalized serviceName; - info = "https://${serviceDomain}"; - icon = "services.not-available"; - }; + name = lib.swarselsystems.toCapitalized serviceName; + info = "https://${serviceDomain}"; + icon = "services.not-available"; + }; virtualisation.oci-containers.containers.${serviceName} = { image = "anirdev/slink@${containerRev}"; @@ -17200,7 +17204,7 @@ Deployment notes: services.${serviceName} = { domain = serviceDomain; inherit proxyAddress4 proxyAddress6 isHome serviceAddress; - homeServiceAddress = lib.mkIf isHome homeServiceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; }; @@ -19408,7 +19412,7 @@ Handles my home DNS server. It also provides some nice blocklists, but the main ]; dhcp.enabled = false; }; - filtering.rewrites = (map + filtering.rewrites = (map (domain: { inherit domain; # FIXME: change to homeWebProxy once that is setup @@ -19417,12 +19421,12 @@ Handles my home DNS server. It also provides some nice blocklists, but the main enabled = true; }) homeDomains) ++ [ - { - domain = "smb.${globals.domains.main}"; - answer = globals.networks.home-lan.vlans.services.hosts.summers-storage.ipv4; - enabled = true; - } - ]; + { + domain = "smb.${globals.domains.main}"; + answer = globals.networks.home-lan.vlans.services.hosts.summers-storage.ipv4; + enabled = true; + } + ]; filters = [ { name = "AdGuard DNS filter"; @@ -20268,7 +20272,7 @@ Some standard options that should be set for every microvm guest. We set the def Some standard options that should be set for every microvm guest. We set the default #+begin_src nix-ts :tangle modules/nixos/optional/microvm-guest-shares.nix - { self, lib, config, inputs, microVMParent, nodes, ... }: + { lib, config, microVMParent, nodes, ... }: { config = { microvm = { @@ -20283,7 +20287,6 @@ Some standard options that should be set for every microvm guest. We set the def }; }; } - #+end_src **** systemd-networkd (base) @@ -20590,7 +20593,7 @@ Hold standard options for nix-topology per config The general structure here is the same as in the [[#h:6da812f5-358c-49cb-aff2-0a94f20d70b3][NixOS]] section. #+begin_src nix-ts :tangle modules/home/default.nix - # @ future me: dont panic, this file is not read in by readNix + # @ future me: dont panic, this file is not read in by readNix { lib, ... }: let importNames = lib.swarselsystems.readNix "modules/home"; @@ -20598,7 +20601,6 @@ The general structure here is the same as in the [[#h:6da812f5-358c-49cb-aff2-0a { imports = lib.swarselsystems.mkImports importNames "modules/home"; } - #+end_src *** Steps to setup/upgrade home-manager only @@ -25503,7 +25505,7 @@ Currently, I am too lazy to explain every option here, but most of it is very se "s=AU11806002320" "v=Philips Consumer Electronics Company" ]; - exec = ["notify-send shikane \"Profile $SHIKANE_PROFILE_NAME has been applied\""]; + exec = [ "notify-send shikane \"Profile $SHIKANE_PROFILE_NAME has been applied\"" ]; in { profile = [ @@ -27360,10 +27362,10 @@ Apart from configuring Noctalia, I here also add some systemd chains to make sur }; }; } // lib.optionalAttrs (type != "nixos") { - sops.secrets = lib.mkIf (!config.swarselsystems.isPublic && !config.swarselsystems.isNixos) { - radicale-token = { path = "${xdgDir}/secrets/radicaleToken"; }; + sops.secrets = lib.mkIf (!config.swarselsystems.isPublic && !config.swarselsystems.isNixos) { + radicale-token = { path = "${xdgDir}/secrets/radicaleToken"; }; + }; }; - }; } #+end_src @@ -27755,83 +27757,83 @@ When setting up a new machine: services = { - shikane = { - settings = - let - workRight = [ - "m=HP Z32" - "s=CN41212T55" - "v=HP Inc." - ]; - workLeft = [ - "m=HP 732pk" - "s=CNC4080YL5" - "v=HP Inc." - ]; - exec = ["notify-send shikane \"Profile $SHIKANE_PROFILE_NAME has been applied\""]; - in - { - profile = [ + shikane = { + settings = + let + workRight = [ + "m=HP Z32" + "s=CN41212T55" + "v=HP Inc." + ]; + workLeft = [ + "m=HP 732pk" + "s=CNC4080YL5" + "v=HP Inc." + ]; + exec = [ "notify-send shikane \"Profile $SHIKANE_PROFILE_NAME has been applied\"" ]; + in + { + profile = [ - { - name = "work-internal-on"; - inherit exec; - output = [ - { - match = config.swarselsystems.sharescreen; - enable = true; - scale = 1.7; - position = "2560,0"; - } - { - match = workRight; - enable = true; - scale = 1.0; - mode = "3840x2160@60Hz"; - position = "-1280,0"; - } - { - match = workLeft; - enable = true; - scale = 1.0; - transform = "270"; - mode = "3840x2160@60Hz"; - position = "-3440,-1050"; - } - ]; - } - { - name = "work-internal-off"; - inherit exec; - output = [ - { - match = config.swarselsystems.sharescreen; - enable = false; - scale = 1.7; - position = "2560,0"; - } - { - match = workRight; - enable = true; - scale = 1.0; - mode = "3840x2160@60Hz"; - position = "-1280,0"; - } - { - match = workLeft; - enable = true; - scale = 1.0; - transform = "270"; - mode = "3840x2160@60Hz"; - position = "-3440,-1050"; - } - ]; - } + { + name = "work-internal-on"; + inherit exec; + output = [ + { + match = config.swarselsystems.sharescreen; + enable = true; + scale = 1.7; + position = "2560,0"; + } + { + match = workRight; + enable = true; + scale = 1.0; + mode = "3840x2160@60Hz"; + position = "-1280,0"; + } + { + match = workLeft; + enable = true; + scale = 1.0; + transform = "270"; + mode = "3840x2160@60Hz"; + position = "-3440,-1050"; + } + ]; + } + { + name = "work-internal-off"; + inherit exec; + output = [ + { + match = config.swarselsystems.sharescreen; + enable = false; + scale = 1.7; + position = "2560,0"; + } + { + match = workRight; + enable = true; + scale = 1.0; + mode = "3840x2160@60Hz"; + position = "-1280,0"; + } + { + match = workLeft; + enable = true; + scale = 1.0; + transform = "270"; + mode = "3840x2160@60Hz"; + position = "-3440,-1050"; + } + ]; + } - ]; - }; - }; + ]; + }; + }; kanshi = { settings = [ { @@ -28824,7 +28826,8 @@ In short, the options defined here are passed to the modules systems using =_mod lib.nameValuePair "/storage/${eternorPath}" { pool = "Vault"; dataset = "Eternor/${eternorPath}"; - }) eternorPaths))); + }) + eternorPaths))); modules = [ (config.node.configDir + /guests/${guestName}/default.nix) { @@ -29459,7 +29462,7 @@ This app checks for different apps that I keep around in the scratchpad for quic cmd=(sh -c 'kitty --add-id spotifytui -T spotifytui -o confirm_os_window_close=0 spotify_player' '&') searchapp="spotifytui" ;; - ,*) break ;; + *) break ;; esac shift done @@ -29475,7 +29478,6 @@ This app checks for different apps that I keep around in the scratchpad for quic ''; } - #+end_src ***** swarselzellij @@ -30826,7 +30828,7 @@ AppImage version of mgba in which the lua scripting works. ;; -*) OPTIONS+=("$1") ;; - ,*) POSITIONAL_ARGS+=("$1") ;; + *) POSITIONAL_ARGS+=("$1") ;; esac shift done @@ -30892,7 +30894,6 @@ AppImage version of mgba in which the lua scripting works. done ''; } - #+end_src ***** swarsel-build @@ -31035,7 +31036,7 @@ This script allows for quick git replace of a string. target_dirs=rue ;; -h | --help) help_and_exit ;; - ,*) + *) echo "Invalid option detected." help_and_exit ;; @@ -31059,8 +31060,6 @@ This script allows for quick git replace of a string. fi ''; } - - #+end_src ***** gen-sops-guest @@ -31409,33 +31408,32 @@ Modules that need to be loaded on the NixOS level. Note that these will not be a options.swarselprofiles.server = lib.mkEnableOption "is this a server"; config = lib.mkIf config.swarselprofiles.server { swarselmodules = { + general = lib.mkDefault true; + lanzaboote = lib.mkDefault true; + pii = lib.mkDefault true; + home-manager = lib.mkDefault true; + xserver = lib.mkDefault true; + time = lib.mkDefault true; + users = lib.mkDefault true; + impermanence = lib.mkDefault true; + btrfs = lib.mkDefault true; + sops = lib.mkDefault true; + boot = lib.mkDefault true; + nftables = lib.mkDefault true; + server = { general = lib.mkDefault true; - lanzaboote = lib.mkDefault true; - pii = lib.mkDefault true; - home-manager = lib.mkDefault true; - xserver = lib.mkDefault true; - time = lib.mkDefault true; - users = lib.mkDefault true; - impermanence = lib.mkDefault true; - btrfs = lib.mkDefault true; - sops = lib.mkDefault true; - boot = lib.mkDefault true; - nftables = lib.mkDefault true; - server = { - general = lib.mkDefault true; - ids = lib.mkDefault true; - network = lib.mkDefault true; - diskEncryption = lib.mkDefault true; - packages = lib.mkDefault true; - ssh = lib.mkDefault true; - attic-setup = lib.mkDefault true; - dns-hostrecord = lib.mkDefault true; - }; + ids = lib.mkDefault true; + network = lib.mkDefault true; + diskEncryption = lib.mkDefault true; + packages = lib.mkDefault true; + ssh = lib.mkDefault true; + attic-setup = lib.mkDefault true; + dns-hostrecord = lib.mkDefault true; }; + }; }; } - #+end_src **** MicroVM :PROPERTIES: diff --git a/modules/nixos/optional/microvm-guest-shares.nix b/modules/nixos/optional/microvm-guest-shares.nix index f6ad083..9478898 100644 --- a/modules/nixos/optional/microvm-guest-shares.nix +++ b/modules/nixos/optional/microvm-guest-shares.nix @@ -1,4 +1,4 @@ -{ self, lib, config, inputs, microVMParent, nodes, ... }: +{ lib, config, microVMParent, nodes, ... }: { config = { microvm = { diff --git a/modules/nixos/server/disk-encrypt.nix b/modules/nixos/server/disk-encrypt.nix index d5dde08..cdc4823 100644 --- a/modules/nixos/server/disk-encrypt.nix +++ b/modules/nixos/server/disk-encrypt.nix @@ -1,11 +1,5 @@ -{ self, pkgs, lib, config, globals, minimal, ... }: +{ self, pkgs, lib, config, minimal, ... }: let - localIp = globals.networks.${config.swarselsystems.server.netConfigName}.hosts.${config.node.name}.ipv4; - subnetMask = globals.networks.${config.swarselsystems.server.netConfigName}.subnetMask4; - gatewayIp = globals.hosts.${config.node.name}.defaultGateway4; - - inherit (globals.general) routerServer; - isRouter = config.node.name == routerServer; hostKeyPathBase = "/etc/secrets/initrd/ssh_host_ed25519_key"; hostKeyPath = diff --git a/modules/nixos/server/postgresql.nix b/modules/nixos/server/postgresql.nix index 0a4f9f9..d02e28e 100644 --- a/modules/nixos/server/postgresql.nix +++ b/modules/nixos/server/postgresql.nix @@ -1,4 +1,4 @@ -{ self, config, lib, pkgs, confLib, ... }: +{ config, lib, pkgs, confLib, ... }: let inherit (confLib.gen { name = "postgresql"; port = 3254; }) serviceName; postgresVersion = 14;