diff --git a/.github/README.md b/.github/README.md index 0661cc1..e913975 100644 --- a/.github/README.md +++ b/.github/README.md @@ -159,13 +159,14 @@ |🖥️ **winters** | ASRock J4105-ITX, 32GB RAM | Secondary homeserver and data storgae | |🖥️ **summers** | ASUS Z10PA-D8, 2* Intel Xeon E5-2650 v4, 128GB RAM | Main homeserver running microvms, data storage | |🖥️ **hintbooth** | HUNSN RM02, 8GB RAM | Router | - |☁️ **milkywell** | Oracle Cloud: VM.Standard.E2.1.Micro | Server for lightweight synchronization tasks | + |☁️ **milkywell** | Oracle Cloud: VM.Standard.E2.1.Micro | Authoritative DNS server | |☁️ **moonside** | Oracle Cloud: VM.Standard.A1.Flex, 4 OCPUs, 24GB RAM| Proxy for local services, some lightweight services | |☁️ **belchsfactory**| Oracle Cloud: VM.Standard.A1.Flex, 4 OCPUs, 24GB RAM| Hydra builder and nix binary cache | |☁️ **monkeycave** | Oracle Cloud: VM.Standard.A1.Flex, 4 OCPUs, 24GB RAM| Gaming server | |☁️ **eagleland** | Hetzner Cloud: CX23 | Mail server | |📱 **magicant** | Samsung Galaxy Z Flip 6 | Phone | |💿 **drugstore** | - | ISO installer configuration | + |💿 **brickroad** | - | Kexec tarball | |❔ **chaotheatre** | - | Demo config for checking out my configurtion | |❔ **toto** | - | Helper configuration for bootstrapping a new system | diff --git a/SwarselSystems.org b/SwarselSystems.org index 5dd1d8c..4499300 100644 --- a/SwarselSystems.org +++ b/SwarselSystems.org @@ -239,13 +239,14 @@ Here I give a brief overview over the hostmachines that I am using. This is held |🖥️ **winters** | ASRock J4105-ITX, 32GB RAM | Secondary homeserver and data storgae | |🖥️ **summers** | ASUS Z10PA-D8, 2* Intel Xeon E5-2650 v4, 128GB RAM | Main homeserver running microvms, data storage | |🖥️ **hintbooth** | HUNSN RM02, 8GB RAM | Router | - |☁️ **milkywell** | Oracle Cloud: VM.Standard.E2.1.Micro | Server for lightweight synchronization tasks | + |☁️ **milkywell** | Oracle Cloud: VM.Standard.E2.1.Micro | Authoritative DNS server | |☁️ **moonside** | Oracle Cloud: VM.Standard.A1.Flex, 4 OCPUs, 24GB RAM| Proxy for local services, some lightweight services | |☁️ **belchsfactory**| Oracle Cloud: VM.Standard.A1.Flex, 4 OCPUs, 24GB RAM| Hydra builder and nix binary cache | |☁️ **monkeycave** | Oracle Cloud: VM.Standard.A1.Flex, 4 OCPUs, 24GB RAM| Gaming server | |☁️ **eagleland** | Hetzner Cloud: CX23 | Mail server | |📱 **magicant** | Samsung Galaxy Z Flip 6 | Phone | |💿 **drugstore** | - | ISO installer configuration | + |💿 **brickroad** | - | Kexec tarball | |❔ **chaotheatre** | - | Demo config for checking out my configurtion | |❔ **toto** | - | Helper configuration for bootstrapping a new system | #+end_src @@ -470,100 +471,57 @@ A short overview over each input and what it does: }; inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + smallpkgs.url = "github:nixos/nixpkgs/08fcb0dcb59df0344652b38ea6326a2d8271baff?narHash=sha256-HXIQzULIG/MEUW2Q/Ss47oE3QrjxvpUX7gUl4Xp6lnc%3D&shallow=1"; nixpkgs-dev.url = "github:Swarsel/nixpkgs/main"; nixpkgs-kernel.url = "github:NixOS/nixpkgs/063f43f2dbdef86376cc29ad646c45c46e93234c?narHash=sha256-6m1Y3/4pVw1RWTsrkAK2VMYSzG4MMIj7sqUy7o8th1o%3D"; #specifically pinned for kernel version nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.05"; nixpkgs-stable24_05.url = "github:NixOS/nixpkgs/nixos-24.05"; nixpkgs-stable24_11.url = "github:NixOS/nixpkgs/nixos-24.11"; nixpkgs-stable25_05.url = "github:NixOS/nixpkgs/nixos-25.05"; - systems.url = "github:nix-systems/default"; - swarsel-modules.url = "github:Swarsel/swarsel-modules/main"; - swarsel-nix.url = "github:Swarsel/swarsel-nix/main"; + home-manager = { # url = "github:nix-community/home-manager"; url = "github:Swarsel/home-manager/main"; inputs.nixpkgs.follows = "nixpkgs"; }; - swarsel.url = "github:Swarsel/.dotfiles"; - emacs-overlay = { - # url = "github:nix-community/emacs-overlay"; - url = "github:nix-community/emacs-overlay/aba8daa237dc07a3bb28a61c252a718e8eb38057?narHash=sha256-4OXXccXsY1sBXTXjYIthdjXLAotozSh4F8StGRuLyMQ%3D"; + nix-index-database = { + url = "github:nix-community/nix-index-database"; inputs.nixpkgs.follows = "nixpkgs"; }; + + # emacs-overlay.url = "github:nix-community/emacs-overlay"; + emacs-overlay.url = "github:nix-community/emacs-overlay/aba8daa237dc07a3bb28a61c252a718e8eb38057?narHash=sha256-4OXXccXsY1sBXTXjYIthdjXLAotozSh4F8StGRuLyMQ%3D"; + swarsel-nix.url = "github:Swarsel/swarsel-nix/main"; + systems.url = "github:nix-systems/default"; nur.url = "github:nix-community/NUR"; nixgl.url = "github:guibou/nixGL"; stylix.url = "github:danth/stylix"; sops-nix.url = "github:Mic92/sops-nix"; lanzaboote.url = "github:nix-community/lanzaboote"; - nix-on-droid = { - url = "github:nix-community/nix-on-droid/release-24.05"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - nixos-generators = { - url = "github:nix-community/nixos-generators"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - nixos-hardware = { - url = "github:NixOS/nixos-hardware/master"; - }; - nswitch-rcm-nix = { - url = "github:Swarsel/nswitch-rcm-nix"; - }; - nix-index-database = { - url = "github:nix-community/nix-index-database"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - disko = { - url = "github:nix-community/disko"; - inputs.nixpkgs.follows = "nixpkgs"; - }; + nix-on-droid.url = "github:nix-community/nix-on-droid/release-24.05"; + nixos-generators.url = "github:nix-community/nixos-generators"; + nixos-images.url = "github:Swarsel/nixos-images/main"; + nixos-hardware.url = "github:NixOS/nixos-hardware/master"; + nswitch-rcm-nix.url = "github:Swarsel/nswitch-rcm-nix"; + disko.url = "github:nix-community/disko"; impermanence.url = "github:nix-community/impermanence"; - zjstatus = { - url = "github:dj95/zjstatus"; - }; - # has been upstreamed - # fw-fanctrl = { - # # url = "github:TamtamHero/fw-fanctrl/packaging/nix"; - # url = "github:Swarsel/fw-fanctrl/packaging/nix"; - # inputs.nixpkgs.follows = "nixpkgs"; - # }; - nix-darwin = { - url = "github:lnl7/nix-darwin"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - pre-commit-hooks = { - url = "github:cachix/git-hooks.nix"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - vbc-nix = { - url = "git+ssh://git@github.com/vbc-it/vbc-nix.git?ref=main"; - inputs.nixpkgs.follows = "nixpkgs"; - }; + zjstatus.url = "github:dj95/zjstatus"; + nix-darwin.url = "github:lnl7/nix-darwin"; + pre-commit-hooks.url = "github:cachix/git-hooks.nix"; + vbc-nix.url = "git+ssh://git@github.com/vbc-it/vbc-nix.git?ref=main"; nix-topology.url = "github:oddlama/nix-topology"; flake-parts.url = "github:hercules-ci/flake-parts"; - devshell = { - url = "github:numtide/devshell"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - spicetify-nix = { - url = "github:Gerg-l/spicetify-nix"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - niri-flake = { - url = "github:sodiboo/niri-flake"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - nixos-extra-modules = { - url = "github:oddlama/nixos-extra-modules"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - microvm = { - url = "github:astro/microvm.nix"; - inputs.nixpkgs.follows = "nixpkgs"; - }; + devshell.url = "github:numtide/devshell"; + spicetify-nix.url = "github:Gerg-l/spicetify-nix"; + niri-flake.url = "github:sodiboo/niri-flake"; + nixos-extra-modules.url = "github:oddlama/nixos-extra-modules/main"; + microvm.url = "github:astro/microvm.nix"; treefmt-nix.url = "github:numtide/treefmt-nix"; - + dns.url = "github:kirelagin/dns.nix"; + nix-minecraft.url = "github:Infinidoge/nix-minecraft"; + simple-nixos-mailserver.url = "gitlab:simple-nixos-mailserver/nixos-mailserver/master"; }; + outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } { @@ -742,7 +700,7 @@ Concerning the =flake = _:= part: ) 4; subnetMask = lib.concatStringsSep "." (map toString octets); in - subnetMask; + subnetMask; mkIfElseList = p: yes: no: lib.mkMerge [ (lib.mkIf p yes) @@ -751,6 +709,23 @@ Concerning the =flake = _:= part: mkIfElse = p: yes: no: if p then yes else no; + getSubDomain = domain: + let + parts = builtins.split "\\." domain; + domainParts = builtins.filter (x: builtins.isString x && x != "") parts; + in + if builtins.length domainParts > 0 + then builtins.head domainParts + else ""; + + getBaseDomain = domain: + let + parts = builtins.split "\\." domain; + domainParts = builtins.filter (x: builtins.isString x && x != "") parts; + baseParts = builtins.tail domainParts; + in + builtins.concatStringsSep "." baseParts; + pkgsFor = lib.genAttrs (import systems) (system: import inputs.nixpkgs { inherit system; @@ -866,7 +841,7 @@ Lastly, in order make this actually available to my configurations, i use the =i #+begin_src nix-ts :tangle nix/globals.nix # adapted from https://github.com/oddlama/nix-config/blob/main/nix/globals.nix - { self, inputs, ... }: + { inputs, ... }: { flake = { config, lib, ... }: { @@ -972,41 +947,48 @@ The rest of the outputs either define or help define the actual configurations: }; modules = [ inputs.disko.nixosModules.disko - inputs.sops-nix.nixosModules.sops + inputs.home-manager.nixosModules.home-manager inputs.impermanence.nixosModules.impermanence inputs.lanzaboote.nixosModules.lanzaboote - inputs.nix-topology.nixosModules.default - inputs.home-manager.nixosModules.home-manager - inputs.stylix.nixosModules.stylix - inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm - # inputs.swarsel-modules.nixosModules.default - inputs.swarsel-nix.nixosModules.default - inputs.niri-flake.nixosModules.niri inputs.microvm.nixosModules.host inputs.microvm.nixosModules.microvm + inputs.niri-flake.nixosModules.niri + 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-nix.nixosModules.sops + inputs.stylix.nixosModules.stylix + inputs.swarsel-nix.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; + networking.hostName = lib.swarselsystems.mkStrong configName; + node = { name = lib.mkForce configName; secretsDir = ../hosts/nixos/${arch}/${configName}/secrets; + lockFromBootstrapping = lib.mkIf (!minimal) (lib.swarselsystems.mkStrong true); }; swarselprofiles = { - minimal = lib.mkIf minimal (lib.mkDefault true); + minimal = lib.mkIf minimal (lib.swarselsystems.mkStrong true); }; swarselmodules.server = { - ssh = lib.mkIf (!minimal) (lib.mkDefault true); + ssh = lib.mkIf (!minimal) (lib.swarselsystems.mkStrong true); }; swarselsystems = { - mainUser = lib.mkDefault "swarsel"; + mainUser = lib.swarselsystems.mkStrong "swarsel"; }; } ]; @@ -1802,7 +1784,9 @@ On the structure of overlays: as you notice, all of the attributes within overla // (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) ) (modifications final prev); @@ -1826,19 +1810,32 @@ This is an improvement to what I did earlier, where I did not use =nixos-generat { perSystem = { pkgs, system, ... }: { - # nix build --print-out-paths --no-link .#images..live-iso - packages.live-iso = inputs.nixos-generators.nixosGenerate { - inherit pkgs; - specialArgs = { inherit self; }; - modules = [ - inputs.home-manager.nixosModules.home-manager - "${self}/install/installer-config.nix" - ]; - format = + packages = { + # nix build --print-out-paths --no-link .#live-iso + live-iso = inputs.nixos-generators.nixosGenerate { + inherit pkgs; + specialArgs = { inherit self; }; + modules = [ + inputs.home-manager.nixosModules.home-manager + "${self}/install/installer-config.nix" + ]; + format = + { + x86_64-linux = "install-iso"; + aarch64-linux = "sd-aarch64-installer"; + }.${system}; + }; + + # nix build --print-out-paths --no-link .#pnap-kexec --system + swarsel-kexec = (inputs.smallpkgs.legacyPackages.${system}.nixos [ { - x86_64-linux = "install-iso"; - aarch64-linux = "sd-aarch64-installer"; - }.${system}; + imports = [ "${self}/install/kexec.nix" ]; + _file = __curPos.file; + system.kexec-installer.name = "swarsel-kexec"; + } + inputs.nixos-images.nixosModules.kexec-installer + ]).config.system.build.kexecInstallerTarball; + }; }; } @@ -2602,7 +2599,7 @@ This is my main server that I run at home. It handles most tasks that require bi :CUSTOM_ID: h:8ad68406-4a75-45ba-97ad-4c310b921124 :END: #+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/winters/default.nix - { lib, minimal, ... }: + { lib, config, minimal, ... }: { imports = [ @@ -2629,13 +2626,17 @@ This is my main server that I run at home. It handles most tasks that require bi isBtrfs = false; isLinux = true; isNixos = true; - server.garage = { - data_dir = [ - { - capacity = "200G"; - path = "/Vault/data/garage/main"; - } - ]; + proxyHost = "moonside"; + server = { + inherit (config.repo.secrets.local.networking) localNetwork; + garage = { + data_dir = [ + { + capacity = "200G"; + path = "/Vault/data/garage/main"; + } + ]; + }; }; }; @@ -3029,7 +3030,7 @@ This is my main server that I run at home. It handles most tasks that require bi ***** Main Configuration #+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/hintbooth/default.nix - { lib, minimal, ... }: + { lib, config, minimal, ... }: { imports = [ @@ -3049,6 +3050,9 @@ This is my main server that I run at home. It handles most tasks that require bi rootDisk = "/dev/sda"; swapSize = "8G"; networkKernelModules = [ "igb" ]; + server = { + inherit (config.repo.secrets.local.networking) localNetwork; + }; }; } // lib.optionalAttrs (!minimal) { @@ -3386,7 +3390,6 @@ This machine mainly acts as my proxy server to stand before my local machines. sops = { age.sshKeyPaths = lib.mkDefault [ "/etc/ssh/ssh_host_ed25519_key" ]; - # defaultSopsFile = lib.mkForce "/home/swarsel/.dotfiles/secrets/moonside/secrets.yaml"; secrets = { wireguard-private-key = { inherit sopsFile; }; wireguard-home-preshared-key = { inherit sopsFile; }; @@ -3513,9 +3516,12 @@ This machine mainly acts as my proxy server to stand before my local machines. isBtrfs = true; isNixos = true; isLinux = true; + proxyHost = "moonside"; + server = { + inherit (config.repo.secrets.local.networking) localNetwork; + }; syncthing = { serviceDomain = config.repo.secrets.common.services.domains.syncthing3; - serviceIP = "localhost"; }; }; } // lib.optionalAttrs (!minimal) { @@ -3688,6 +3694,642 @@ This machine mainly acts as my proxy server to stand before my local machines. } +#+end_src +**** Belchsfactory (OCI) + +***** Main Configuration + +#+begin_src nix-ts :tangle hosts/nixos/aarch64-linux/belchsfactory/default.nix + { lib, config, minimal, ... }: + { + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + ]; + + node.lockFromBootstrapping = lib.mkForce false; + + topology.self = { + icon = "devices.cloud-server"; + }; + swarselmodules.server.nginx = false; + + swarselsystems = { + flakePath = "/root/.dotfiles"; + info = "VM.Standard.A1.Flex, 4 vCPUs, 24GB RAM"; + isImpermanence = true; + isSecureBoot = false; + isCrypted = true; + isSwap = false; + rootDisk = "/dev/sda"; + isBtrfs = true; + isNixos = true; + isLinux = true; + proxyHost = "belchsfactory"; + server = { + inherit (config.repo.secrets.local.networking) localNetwork; + }; + }; + } // lib.optionalAttrs (!minimal) { + swarselprofiles = { + server = true; + }; + } + +#+end_src +***** hardware-configuration + +#+begin_src nix-ts :tangle hosts/nixos/aarch64-linux/belchsfactory/hardware-configuration.nix + { lib, modulesPath, ... }: + { + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + boot = { + initrd = { + availableKernelModules = [ "xhci_pci" "virtio_pci" "virtio_scsi" "usbhid" ]; + kernelModules = [ ]; + }; + kernelModules = [ ]; + extraModulePackages = [ ]; + }; + + nixpkgs.hostPlatform = lib.mkForce "aarch64-linux"; + } +#+end_src +***** disko + +#+begin_src nix-ts :tangle hosts/nixos/aarch64-linux/belchsfactory/disk-config.nix + { lib, pkgs, config, ... }: + let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; + in + { + disko = { + imageBuilder.extraDependencies = [ pkgs.kmod ]; + devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + } + +#+end_src +**** Milkywell (OCI) + +***** Main Configuration + +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/milkywell/default.nix + { lib, config, minimal, ... }: + { + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + ]; + node.lockFromBootstrapping = false; + sops = { + age.sshKeyPaths = lib.mkDefault [ "/etc/ssh/ssh_host_ed25519_key" ]; + }; + + topology.self = { + icon = "devices.cloud-server"; + }; + + networking = { + domain = "subnet03112148.vcn03112148.oraclevcn.com"; + firewall = { + allowedTCPPorts = [ 53 ]; + }; + }; + + system.stateVersion = "23.11"; + + swarselsystems = { + flakePath = "/root/.dotfiles"; + info = "VM.Standard.E2.1.Micro"; + isImpermanence = true; + isSecureBoot = false; + isCrypted = false; + isSwap = true; + swapSize = "8G"; + rootDisk = "/dev/sda"; + isBtrfs = true; + isNixos = true; + isLinux = true; + server = { + inherit (config.repo.secrets.local.networking) localNetwork; + }; + }; + } // lib.optionalAttrs (!minimal) { + swarselprofiles = { + server = true; + }; + + } + +#+end_src +***** hardware-configuration + +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/milkywell/hardware-configuration.nix + { lib, modulesPath, ... }: + + { + imports = + [ + (modulesPath + "/profiles/qemu-guest.nix") + ]; + + boot = { + initrd = { + availableKernelModules = [ "ata_piix" "uhci_hcd" "virtio_pci" "virtio_scsi" "sd_mod" ]; + kernelModules = [ "dm-snapshot" ]; + }; + kernelModules = [ "kvm-amd" ]; + extraModulePackages = [ ]; + }; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.ens3.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + } + +#+end_src +***** disko +:PROPERTIES: +:CUSTOM_ID: h:cec82b06-39ca-4c0e-b4f5-c1fda9b14e6d +:END: + +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/milkywell/disk-config.nix + { lib, pkgs, config, ... }: + let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; + in + { + disko = { + imageBuilder.extraDependencies = [ pkgs.kmod ]; + devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + } +#+end_src +**** Eagleland (Hetzner) + +***** Main Configuration + +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/eagleland/default.nix + { lib, config, minimal, ... }: + { + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + ]; + + topology.self = { + icon = "devices.cloud-server"; + }; + + networking = { + useDHCP = lib.mkForce false; + useNetworkd = true; + dhcpcd.enable = false; + renameInterfacesByMac = lib.mapAttrs (_: v: v.mac) ( + config.repo.secrets.local.networking.networks or { } + ); + }; + boot.initrd.systemd.network = { + enable = true; + networks = { + inherit (config.systemd.network.networks) "10-wan"; + }; + }; + + systemd = { + network = { + enable = true; + wait-online.enable = false; + networks = + let + netConfig = config.repo.secrets.local.networking; + in + { + "10-wan" = { + address = [ + "${netConfig.wanAddress4}/32" + "${netConfig.wanAddress6}/64" + ]; + gateway = [ "fe80::1" ]; + routes = [ + { Destination = netConfig.defaultGateway4; } + { + Gateway = netConfig.defaultGateway4; + GatewayOnLink = true; + } + ]; + matchConfig.MACAddress = netConfig.networks.${config.swarselsystems.server.localNetwork}.mac; + networkConfig.IPv6PrivacyExtensions = "yes"; + linkConfig.RequiredForOnline = "routable"; + }; + }; + }; + }; + + swarselmodules.server.mailserver = true; + + swarselsystems = { + flakePath = "/root/.dotfiles"; + info = "2vCPU, 4GB Ram"; + isImpermanence = true; + isSecureBoot = false; + isCrypted = true; + isCloud = true; + isSwap = true; + swapSize = "4G"; + rootDisk = "/dev/sda"; + isBtrfs = true; + isNixos = true; + isLinux = true; + proxyHost = "eagleland"; + server = { + inherit (config.repo.secrets.local.networking) localNetwork; + }; + }; + } // lib.optionalAttrs (!minimal) { + swarselprofiles = { + server = true; + }; + + } + +#+end_src +***** hardware-configuration + +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/eagleland/hardware-configuration.nix + { lib, modulesPath, ... }: + + { + imports = + [ + (modulesPath + "/profiles/qemu-guest.nix") + ]; + + boot = { + initrd = { + availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" ]; + kernelModules = [ ]; + }; + kernelModules = [ ]; + extraModulePackages = [ ]; + }; + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + } + +#+end_src +***** disko + +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/eagleland/disk-config.nix + { lib, pkgs, config, ... }: + let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; + in + { + disko = { + imageBuilder.extraDependencies = [ pkgs.kmod ]; + devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + } #+end_src *** Utility hosts :PROPERTIES: @@ -4067,6 +4709,108 @@ TODO: cleanup this mess #+end_src +**** Brick Road (kexec image) + +#+begin_src nix-ts :tangle install/kexec.nix + { lib, pkgs, modulesPath, options, ... }: + { + disabledModules = [ + # This module adds values to multiple lists (systemPackages, supportedFilesystems) + # which are impossible/unpractical to remove, so we disable the entire module. + "profiles/base.nix" + ]; + + imports = [ + # reduce closure size by removing perl + "${modulesPath}/profiles/perlless.nix" + # FIXME: we still are left with nixos-generate-config due to nixos-install-tools + { system.forbiddenDependenciesRegexes = lib.mkForce [ ]; } + ]; + + config = { + networking.hostName = "brickroad"; + + system = { + # nixos-option is mainly useful for interactive installations + tools.nixos-option.enable = false; + # among others, this prevents carrying a stdenv with gcc in the image + extraDependencies = lib.mkForce [ ]; + }; + # prevents shipping nixpkgs, unnecessary if system is evaluated externally + nix.registry = lib.mkForce { }; + + # would pull in nano + programs.nano.enable = false; + + # prevents strace + environment = { + defaultPackages = lib.mkForce [ + pkgs.parted + pkgs.gptfdisk + pkgs.e2fsprogs + ]; + + systemPackages = with pkgs; [ + cryptsetup.bin + ]; + + # Don't install the /lib/ld-linux.so.2 stub. This saves one instance of nixpkgs. + ldso32 = null; + }; + + # included in systemd anyway + systemd.sysusers.enable = true; + + # normal users are not allowed with sys-users + # see https://github.com/NixOS/nixpkgs/pull/328926 + users.users.nixos = { + isSystemUser = true; + isNormalUser = lib.mkForce false; + shell = "/run/current-system/sw/bin/bash"; + group = "nixos"; + }; + users.groups.nixos = { }; + + security = { + # we have still run0 from systemd and most of the time we just use root + sudo.enable = false; + polkit.enable = lib.mkForce false; + # introduces x11 dependencies + pam.services.su.forwardXAuth = lib.mkForce false; + }; + + documentation = { + enable = false; + man.enable = false; + nixos.enable = false; + info.enable = false; + doc.enable = false; + }; + + services = { + # no dependency on x11 + dbus.implementation = "broker"; + # we prefer root as this is also what we use in nixos-anywhere + getty.autologinUser = lib.mkForce "root"; + # included in systemd anyway + userborn.enable = false; + }; + + + + # we are missing this from base.nix + boot.supportedFilesystems = [ + "ext4" + "btrfs" + "xfs" + ]; + } // lib.optionalAttrs (options.hardware ? firmwareCompression) { + hardware.firmwareCompression = "xz"; + }; + } + +#+end_src + **** Hotel (Demo Physical/VM) :PROPERTIES: :CUSTOM_ID: h:e1498bef-ec67-483d-bf02-76264e30be8e @@ -4542,13 +5286,31 @@ in services = mkOption { type = types.attrsOf ( - types.submodule { + types.submodule (serviceSubmod: { options = { domain = mkOption { type = types.str; }; + subDomain = mkOption { + readOnly = true; + type = types.str; + default = lib.swarselsystems.getSubDomain serviceSubmod.config.domain; + }; + baseDomain = mkOption { + readOnly = true; + type = types.str; + default = lib.swarselsystems.getBaseDomain serviceSubmod.config.domain; + }; + proxyAddress4 = mkOption { + type = types.nullOr types.str; + default = null; + }; + proxyAddress6 = mkOption { + type = types.nullOr types.str; + default = null; + }; }; - } + }) ); }; @@ -4591,6 +5353,12 @@ in defaultGateway6 = mkOption { type = types.nullOr types.net.ipv6; }; + wanAddress4 = mkOption { + type = types.nullOr types.net.ipv4; + }; + wanAddress6 = mkOption { + type = types.nullOr types.net.ipv6; + }; }; } ); @@ -4635,6 +5403,10 @@ in description = "Node Name."; type = lib.types.str; }; + lockFromBootstrapping = lib.mkOption { + description = "Whether this host should be marked to not be bootstrapped again using swarsel-bootstrap."; + type = lib.types.bool; + }; }; }; } @@ -4746,136 +5518,138 @@ A breakdown of the flags being set: - nix.nixPath: Basically the same as =nix.registry=, but for the legacy nix commands #+begin_src nix-ts :tangle modules/nixos/common/settings.nix - { self, lib, pkgs, config, outputs, inputs, minimal, ... }: - let - settings = if minimal then { } else { - environment.etc."nixos/configuration.nix".source = pkgs.writeText "configuration.nix" '' - assert builtins.trace "This location is not used. The config is found in ${config.swarselsystems.flakePath}!" false; - { } - ''; + { self, lib, pkgs, config, outputs, inputs, minimal, ... }: + let + inherit (config.swarselsystems) mainUser; + settings = if minimal then { } else { + environment.etc."nixos/configuration.nix".source = pkgs.writeText "configuration.nix" '' + assert builtins.trace "This location is not used. The config is found in ${config.swarselsystems.flakePath}!" false; + { } + ''; - nix = - let - flakeInputs = lib.filterAttrs (_: lib.isType "flake") inputs; - in - { - settings = { - connect-timeout = 5; - bash-prompt-prefix = "$SHLVL:\\w "; - bash-prompt = "$(if [[ $? -gt 0 ]]; then printf \"\"; else printf \"\"; fi)λ "; - fallback = true; - min-free = 128000000; - max-free = 1000000000; - flake-registry = ""; - auto-optimise-store = true; - warn-dirty = false; - max-jobs = 1; - use-cgroups = lib.mkIf config.swarselsystems.isLinux true; + nix = + let + flakeInputs = lib.filterAttrs (_: lib.isType "flake") inputs; + in + { + settings = { + connect-timeout = 5; + bash-prompt-prefix = "$SHLVL:\\w "; + bash-prompt = "$(if [[ $? -gt 0 ]]; then printf \"\"; else printf \"\"; fi)λ "; + fallback = true; + min-free = 128000000; + max-free = 1000000000; + flake-registry = ""; + auto-optimise-store = true; + warn-dirty = false; + max-jobs = 1; + use-cgroups = lib.mkIf config.swarselsystems.isLinux true; + }; + gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 10d"; + }; + optimise = { + automatic = true; + dates = "weekly"; + }; + channel.enable = false; + registry = rec { + nixpkgs.flake = inputs.nixpkgs; + # swarsel.flake = inputs.swarsel; + swarsel.flake = self; + n = nixpkgs; + s = swarsel; + }; + nixPath = lib.mapAttrsToList (n: _: "${n}=flake:${n}") flakeInputs; }; - gc = { - automatic = true; - dates = "weekly"; - options = "--delete-older-than 10d"; - }; - optimise = { - automatic = true; - dates = "weekly"; - }; - channel.enable = false; - registry = rec { - nixpkgs.flake = inputs.nixpkgs; - swarsel.flake = inputs.swarsel; - n = nixpkgs; - s = swarsel; - }; - nixPath = lib.mapAttrsToList (n: _: "${n}=flake:${n}") flakeInputs; + + services.dbus.implementation = "broker"; + + systemd.services.nix-daemon = { + environment.TMPDIR = "/var/tmp"; }; - services.dbus.implementation = "broker"; - - systemd.services.nix-daemon = { - environment.TMPDIR = "/var/tmp"; }; + in + { + options.swarselmodules.general = lib.mkEnableOption "general nix settings"; + config = lib.mkIf config.swarselmodules.general + (lib.recursiveUpdate + { + sops.secrets.github-api-token = lib.mkIf (!minimal) { + owner = mainUser; + }; - }; - in - { - options.swarselmodules.general = lib.mkEnableOption "general nix settings"; - config = lib.mkIf config.swarselmodules.general - (lib.recursiveUpdate - { - sops.secrets.github-api-token = lib.mkIf (!minimal) { - sopsFile = "${config.swarselsystems.flakePath}/secrets/general/secrets.yaml"; - }; + nix = + let + nix-version = "2_30"; + in + { + package = pkgs.nixVersions."nix_${nix-version}"; + settings = { + experimental-features = [ + "nix-command" + "flakes" + "ca-derivations" + "cgroups" + "pipe-operators" + ]; + trusted-users = [ "@wheel" "${config.swarselsystems.mainUser}" ]; + }; + # extraOptions = '' + # plugin-files = ${pkgs.dev.nix-plugins}/lib/nix/plugins + # extra-builtins-file = ${self + /nix/extra-builtins.nix} + # '' + lib.optionalString (!minimal) '' + # !include ${config.sops.secrets.github-api-token.path} + # ''; + # extraOptions = '' + # plugin-files = ${pkgs.nix-plugins.overrideAttrs (o: { + # buildInputs = [config.nix.package pkgs.boost]; + # patches = o.patches or []; + # })}/lib/nix/plugins + # extra-builtins-file = ${self + /nix/extra-builtins.nix} + # ''; - nix = - let - nix-version = "2_30"; - in - { - package = pkgs.nixVersions."nix_${nix-version}"; - settings = { - experimental-features = [ - "nix-command" - "flakes" - "ca-derivations" - "cgroups" - "pipe-operators" - ]; - trusted-users = [ "@wheel" "${config.swarselsystems.mainUser}" ]; + extraOptions = + let + nix-plugins = pkgs.nix-plugins.override { + nixComponents = pkgs.nixVersions."nixComponents_${nix-version}"; + }; + in + '' + plugin-files = ${nix-plugins}/lib/nix/plugins + extra-builtins-file = ${self + /nix/extra-builtins.nix} + '' + lib.optionalString (!minimal) '' + !include ${config.sops.secrets.github-api-token.path} + ''; }; - # extraOptions = '' - # plugin-files = ${pkgs.dev.nix-plugins}/lib/nix/plugins - # extra-builtins-file = ${self + /nix/extra-builtins.nix} - # '' + lib.optionalString (!minimal) '' - # !include ${config.sops.secrets.github-api-token.path} - # ''; - # extraOptions = '' - # plugin-files = ${pkgs.nix-plugins.overrideAttrs (o: { - # buildInputs = [config.nix.package pkgs.boost]; - # patches = o.patches or []; - # })}/lib/nix/plugins - # extra-builtins-file = ${self + /nix/extra-builtins.nix} - # ''; - extraOptions = - let - nix-plugins = pkgs.nix-plugins.override { - nixComponents = pkgs.nixVersions."nixComponents_${nix-version}"; - }; - in - '' - plugin-files = ${nix-plugins}/lib/nix/plugins - extra-builtins-file = ${self + /nix/extra-builtins.nix} - '' + lib.optionalString (!minimal) '' - !include ${config.sops.secrets.github-api-token.path} - ''; + system.stateVersion = lib.mkDefault "23.05"; + + nixpkgs = { + overlays = [ + outputs.overlays.default + (final: prev: + let + additions = final: _: import "${self}/pkgs/config" { + inherit self config lib; + pkgs = final; + homeConfig = config.home-manager.users.${config.swarselsystems.mainUser}; + }; + in + additions final prev + ) + ]; + config = { + allowUnfree = true; + }; }; - system.stateVersion = lib.mkDefault "23.05"; - - nixpkgs = { - overlays = [ - outputs.overlays.default - (final: prev: - let - additions = final: _: import "${self}/pkgs/config" { - inherit self config lib; - pkgs = final; - homeConfig = config.home-manager.users.${config.swarselsystems.mainUser}; - }; - in - additions final prev - ) - ]; - config = { - allowUnfree = true; - }; - }; - - } - settings); - } + } + settings); + } #+end_src **** Setup home-manager base @@ -4900,7 +5674,6 @@ We enable the use of =home-manager= as a NixoS module. A nice trick here is the inputs.nix-index-database.homeModules.nix-index inputs.sops-nix.homeManagerModules.sops inputs.spicetify-nix.homeManagerModules.default - # inputs.swarsel-modules.homeModules.default inputs.swarsel-nix.homeModules.default { imports = [ @@ -4939,14 +5712,11 @@ In case of using a fully setup system, this makes also sure that no further user For that reason, make sure that =sops-nix= is properly working before finishing the minimal setup, otherwise we might lose user access. The bootstrapping script takes care of this. #+begin_src nix-ts :tangle modules/nixos/common/users.nix - { self, pkgs, config, lib, globals, minimal, ... }: - let - sopsFile = self + /secrets/general/secrets.yaml; - in + { pkgs, config, lib, globals, minimal, ... }: { options.swarselmodules.users = lib.mkEnableOption "user config"; config = lib.mkIf config.swarselmodules.users { - sops.secrets.main-user-hashed-pw = lib.mkIf (!config.swarselsystems.isPublic) { inherit sopsFile; neededForUsers = true; }; + sops.secrets.main-user-hashed-pw = lib.mkIf (!config.swarselsystems.isPublic) { neededForUsers = true; }; users = { mutableUsers = lib.mkIf (!minimal) false; @@ -5258,6 +6028,7 @@ Normally, doing that also resets the lecture that happens on the first use of =s hideMounts = true; directories = [ + "/root/.dotfiles" "/etc/nix" "/etc/NetworkManager/system-connections" "/var/lib/nixos" @@ -5313,102 +6084,106 @@ This section is for setting things that should be used on hosts that are using t Mostly used to install some compilers and lsp's that I want to have available when not using a devShell flake. Most other packages should go in [[#h:893a7f33-7715-415b-a895-2687ded31c18][Installed packages]]. #+begin_src nix-ts :tangle modules/nixos/client/packages.nix - { lib, config, pkgs, minimal, ... }: - { - options.swarselmodules.packages = lib.mkEnableOption "install packages"; - config = lib.mkIf config.swarselmodules.packages { + { lib, config, pkgs, minimal, ... }: + { + options.swarselmodules.packages = lib.mkEnableOption "install packages"; + config = lib.mkIf config.swarselmodules.packages { - environment.systemPackages = with pkgs; lib.optionals (!minimal) [ - # yubikey packages - gnupg - yubikey-personalization - yubico-pam - yubioath-flutter - yubikey-manager - yubikey-touch-detector - yubico-piv-tool - cfssl - pcsc-tools - pcscliteWithPolkit.out + environment.systemPackages = with pkgs; lib.optionals (!minimal) [ + # yubikey packages + gnupg + yubikey-personalization + yubico-pam + yubioath-flutter + yubikey-manager + yubikey-touch-detector + yubico-piv-tool + cfssl + pcsc-tools + pcscliteWithPolkit.out - # ledger packages - ledger-live-desktop + # ledger packages + ledger-live-desktop - # pinentry - dbus - # swaylock-effects - syncthingtray-minimal - swayosd + # pinentry + dbus + # swaylock-effects + syncthingtray-minimal + swayosd - # secure boot - sbctl + # secure boot + sbctl - libsForQt5.qt5.qtwayland + libsForQt5.qt5.qtwayland - # nix package database - nix-index - nixos-generators + # do not do this! clashes with the flake + # nix-index - # commit hooks - pre-commit + nixos-generators - # proc info - acpi + # commit hooks + pre-commit - # pci info - pciutils - usbutils + # proc info + acpi - # better make for general tasks - just + # pci info + pciutils + usbutils + # better make for general tasks + just - # keyboards - qmk - vial - via + # sops + ssh-to-age + sops - # theme related - adwaita-icon-theme + # keyboards + qmk + vial + via - # kde-connect - xdg-desktop-portal - xdg-desktop-portal-gtk - xdg-desktop-portal-wlr + # theme related + adwaita-icon-theme - # bluetooth - bluez - ghostscript_headless - wireguard-tools - nixd - zig - zls + # kde-connect + xdg-desktop-portal + xdg-desktop-portal-gtk + xdg-desktop-portal-wlr - elk-to-svg + # bluetooth + bluez + ghostscript_headless + wireguard-tools + nixd + zig + zls - ] ++ lib.optionals minimal [ - networkmanager - curl - git - gnupg - rsync - ssh-to-age - sops - vim - just - sbctl - ]; + elk-to-svg - nixpkgs.config.permittedInsecurePackages = lib.mkIf (!minimal) [ - "jitsi-meet-1.0.8043" - "electron-29.4.6" - "SDL_ttf-2.0.11" - # audacity? - "mbedtls-2.28.10" - # "qtwebengine-5.15.19" - ]; - }; - } + ] ++ lib.optionals minimal [ + networkmanager + curl + git + gnupg + rsync + ssh-to-age + sops + vim + just + sbctl + ]; + + nixpkgs.config.permittedInsecurePackages = lib.mkIf (!minimal) [ + "jitsi-meet-1.0.8043" + "electron-29.4.6" + "SDL_ttf-2.0.11" + # audacity? + "mbedtls-2.28.10" + # "qtwebengine-5.15.19" + ]; + }; + } #+end_src **** Environment setup @@ -5940,9 +6715,8 @@ I use sops-nix to handle secrets that I want to have available on my machines at sops = { # age.sshKeyPaths = lib.swarselsystems.mkIfElseList config.swarselsystems.isBtrfs [ "/persist/.ssh/sops" "/persist/.ssh/ssh_host_ed25519_key" ] [ "${config.swarselsystems.homeDir}/.ssh/sops" "/etc/ssh/sops" "/etc/ssh/ssh_host_ed25519_key" ]; - age.sshKeyPaths = [ "${config.swarselsystems.homeDir}/.ssh/sops" "/etc/ssh/sops" "/etc/ssh/ssh_host_ed25519_key" ]; - # defaultSopsFile = lib.swarselsystems.mkIfElseList config.swarselsystems.isBtrfs "/persist/.dotfiles/secrets/general/secrets.yaml" "${config.swarselsystems.flakePath}/secrets/general/secrets.yaml"; - defaultSopsFile = "${config.swarselsystems.flakePath}/secrets/general/secrets.yaml"; + age.sshKeyPaths = [ "${config.swarselsystems.homeDir}/.ssh/sops" "/etc/ssh/sops" "${if config.swarselsystems.isImpermanence then "/persist" else ""}/etc/ssh/ssh_host_ed25519_key" ]; + defaultSopsFile = "${if config.swarselsystems.isImpermanence then "/persist" else ""}${config.swarselsystems.flakePath}/secrets/general/secrets.yaml"; validateSopsFiles = false; @@ -6984,7 +7758,6 @@ Here we just define some aliases for rebuilding the system, and we allow some in config = lib.mkIf config.swarselmodules.server.packages { environment.systemPackages = with pkgs; [ gnupg - nix-index nvd nix-output-monitor ssh-to-age @@ -7155,6 +7928,7 @@ Here we just define some aliases for rebuilding the system, and we allow some in networking.firewall.allowedTCPPorts = [ 80 443 ]; environment.persistence."/persist" = lib.mkIf config.swarselsystems.isImpermanence { + directories = [ { directory = "/var/lib/acme"; } ]; files = [ dhParamsPathBase ]; }; @@ -7179,28 +7953,52 @@ Here we just define some aliases for rebuilding the system, and we allow some in ''; }; }; - system.activationScripts."createPersistentStorageDirs" = lib.mkIf config.swarselsystems.isImpermanence { - deps = [ "generateDHParams" "users" "groups" ]; - }; - system.activationScripts."generateDHParams" = - { - text = '' - set -eu - - ${pkgs.coreutils}/bin/install -d -m 0755 ${sslBasePath} - ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0755 /persist${sslBasePath}" else ""} - - if [ ! -f "${dhParamsPathBase}" ]; then - ${pkgs.openssl}/bin/openssl dhparam -out ${dhParamsPath} 4096 - chmod 0644 ${dhParamsPath} - chown ${serviceUser}:${serviceGroup} ${dhParamsPath} - fi - ''; - deps = [ - "etc" - (lib.mkIf config.swarselsystems.isImpermanence "specialfs") - ]; + systemd.services.generateDHParams = { + before = [ "nginx.service" ]; + requiredBy = [ "nginx.service" ]; + after = [ "local-fs.target" ]; + requires = [ "local-fs.target" ]; + serviceConfig = { + Type = "oneshot"; }; + + script = '' + set -eu + + install -d -m 0755 ${sslBasePath} + ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0755 /persist${sslBasePath}" else ""} + + if [ ! -f "${dhParamsPath}" ]; then + ${pkgs.openssl}/bin/openssl dhparam -out "${dhParamsPath}" 4096 + chmod 0644 "${dhParamsPath}" + chown ${serviceUser}:${serviceGroup} "${dhParamsPath}" + else + echo 'Already generated DHParams' + fi + ''; + }; + + # system.activationScripts."createPersistentStorageDirs" = lib.mkIf config.swarselsystems.isImpermanence { + # deps = [ "generateDHParams" "users" "groups" ]; + # }; + # system.activationScripts."generateDHParams" = + # { + # text = '' + # set -eu + + # ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0755 /persist${sslBasePath}" else "${pkgs.coreutils}/bin/install -d -m 0755 ${sslBasePath}"} + + # if [ ! -f "${dhParamsPath}" ]; then + # ${pkgs.openssl}/bin/openssl dhparam -out ${dhParamsPath} 4096 + # chmod 0644 ${dhParamsPath} + # chown ${serviceUser}:${serviceGroup} ${dhParamsPath} + # fi + # ''; + # deps = [ + # (lib.mkIf config.swarselsystems.isImpermanence "specialfs") + # (lib.mkIf (!config.swarselsystems.isImpermanence) "etc") + # ]; + # }; }; } #+end_src @@ -7249,20 +8047,30 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t **** Network settings +Generate hostId using =head -c4 /dev/urandom | od -A none -t x4= #+begin_src nix-ts :tangle modules/nixos/server/network.nix { lib, config, ... }: + let + inherit (config.swarselsystems.server) localNetwork; + in { options.swarselmodules.server.network = lib.mkEnableOption "enable server network config"; + options.swarselsystems.server.localNetwork = lib.mkOption { + type = lib.types.str; + default = "home"; + }; config = lib.mkIf config.swarselmodules.server.network { - globals.networks.home.hosts.${config.node.name} = { - inherit (config.repo.secrets.local.networking.networks.home) id; - mac = config.repo.secrets.local.networking.networks.home.mac or null; + globals.networks."${if config.swarselsystems.isCloud then config.node.name else "home"}-${localNetwork}".hosts.${config.node.name} = { + inherit (config.repo.secrets.local.networking.networks.${localNetwork}) id; + mac = config.repo.secrets.local.networking.networks.${localNetwork}.mac or null; }; globals.hosts.${config.node.name} = { inherit (config.repo.secrets.local.networking) defaultGateway4; + wanAddress4 = config.repo.secrets.local.networking.wanAddress4 or null; + wanAddress6 = config.repo.secrets.local.networking.wanAddress6 or null; }; networking = { @@ -7306,83 +8114,94 @@ lspci -k -d 14c3:0616 | | Kernel | modules: | mt7921e | | | | | | | | | #+begin_src nix-ts :tangle modules/nixos/server/disk-encrypt.nix - { self, pkgs, lib, config, globals, minimal, ... }: - let - localIp = globals.networks.home.hosts.${config.node.name}.ipv4; - subnetMask = globals.networks.home.subnetMask4; - gatewayIp = globals.hosts.${config.node.name}.defaultGateway4; + { self, pkgs, lib, config, globals, minimal, ... }: + let + localIp = globals.networks."${if config.swarselsystems.isCloud then config.node.name else "home"}-${config.swarselsystems.server.localNetwork}".hosts.${config.node.name}.ipv4; + subnetMask = globals.networks."${if config.swarselsystems.isCloud then config.node.name else "home"}-${config.swarselsystems.server.localNetwork}".subnetMask4; + gatewayIp = globals.hosts.${config.node.name}.defaultGateway4; - hostKeyPath = "/etc/secrets/initrd/ssh_host_ed25519_key"; - in - { - options.swarselmodules.server.diskEncryption = lib.mkEnableOption "enable disk encryption config"; - options.swarselsystems.networkKernelModules = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = [ ]; - }; - config = lib.mkIf (config.swarselmodules.server.diskEncryption && config.swarselsystems.isCrypted) { + hostKeyPathBase = "/etc/secrets/initrd/ssh_host_ed25519_key"; + hostKeyPath = + if config.swarselsystems.isImpermanence then + "/persist/${hostKeyPathBase}" + else + "${hostKeyPathBase}"; + in + { + options.swarselmodules.server.diskEncryption = lib.mkEnableOption "enable disk encryption config"; + options.swarselsystems.networkKernelModules = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + }; + config = lib.mkIf (config.swarselmodules.server.diskEncryption && config.swarselsystems.isCrypted) { - system.activationScripts.ensureInitrdHostkey = lib.mkIf (config.swarselprofiles.server || minimal) { - text = '' - [[ -e ${hostKeyPath} ]] || ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -N "" -f ${hostKeyPath} - ''; - deps = [ "users" ]; - }; - environment.persistence."/persist" = lib.mkIf (config.swarselsystems.isImpermanence && (config.swarselprofiles.server || minimal)) { - files = [ hostKeyPath ]; - }; + system.activationScripts."createPersistentStorageDirs" = lib.mkIf config.swarselsystems.isImpermanence { + deps = [ "ensureInitrdHostkey" ]; + }; + system.activationScripts.ensureInitrdHostkey = lib.mkIf (config.swarselprofiles.server || minimal) { + text = '' + [[ -e ${hostKeyPath} ]] || ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -N "" -f ${hostKeyPath} + ''; + deps = [ + "etc" + ]; + }; - boot = lib.mkIf (config.swarselprofiles.server || minimal) { - kernelParams = lib.mkIf (!config.swarselsystems.isLaptop) [ - "ip=${localIp}::${gatewayIp}:${subnetMask}:${config.networking.hostName}::none" - ]; - initrd = { - availableKernelModules = config.swarselsystems.networkKernelModules; - network = { - enable = true; - udhcpc.enable = lib.mkIf config.swarselsystems.isLaptop true; - flushBeforeStage2 = true; - ssh = { - enable = true; - port = 2222; # avoid hostkey changed nag - authorizedKeyFiles = [ - (self + /secrets/keys/ssh/yubikey.pub) - (self + /secrets/keys/ssh/magicant.pub) - ]; - hostKeys = [ hostKeyPath ]; - }; - # postCommands = '' - # echo 'cryptsetup-askpass || echo "Unlock was successful; exiting SSH session" && exit 1' >> /root/.profile - # ''; - }; - systemd = { - initrdBin = with pkgs; [ - cryptsetup - ]; - services = { - unlock-luks = { - wantedBy = [ "initrd.target" ]; - after = [ "network.target" ]; - before = [ "systemd-cryptsetup@cryptroot.service" ]; - path = [ "/bin" ]; + environment.persistence."/persist" = lib.mkIf (config.swarselsystems.isImpermanence && (config.swarselprofiles.server || minimal)) { + files = [ hostKeyPathBase ]; + }; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - }; + boot = lib.mkIf (!config.swarselsystems.isLaptop) { + kernelParams = lib.mkIf (!config.swarselsystems.isCloud) [ + "ip=${localIp}::${gatewayIp}:${subnetMask}:${config.networking.hostName}::none" + ]; + initrd = { + availableKernelModules = config.swarselsystems.networkKernelModules; + network = { + enable = true; + flushBeforeStage2 = true; + ssh = { + enable = true; + port = 2222; # avoid hostkey changed nag + authorizedKeys = [ + ''command="/bin/systemctl default" ${builtins.readFile "${self}/secrets/keys/ssh/yubikey.pub"}'' + ''command="/bin/systemctl default" ${builtins.readFile "${self}/secrets/keys/ssh/magicant.pub"}'' + ]; + hostKeys = [ hostKeyPathBase ]; + }; + # postCommands = '' + # echo 'cryptsetup-askpass || echo "Unlock was successful; exiting SSH session" && exit 1' >> /root/.profile + # ''; + }; + systemd = { + initrdBin = with pkgs; [ + cryptsetup + ]; + # NOTE: the below does put the text into /root/.profile, but the command will not be run + # services = { + # unlock-luks = { + # wantedBy = [ "initrd.target" ]; + # after = [ "network.target" ]; + # before = [ "systemd-cryptsetup@cryptroot.service" ]; + # path = [ "/bin" ]; - script = '' - echo "systemctl default" >> /root/.profile - ''; - }; - }; - }; - }; - }; - }; + # serviceConfig = { + # Type = "oneshot"; + # RemainAfterExit = true; + # }; - } + # script = '' + # echo "systemctl default" >> /root/.profile + # ''; + # }; + # }; + }; + }; + }; + }; + + } #+end_src **** Router @@ -7452,15 +8271,11 @@ lspci -k -d 14c3:0616 :END: #+begin_src nix-ts :tangle modules/nixos/server/kavita.nix - { self, lib, config, pkgs, globals, ... }: + { self, lib, config, pkgs, globals, dns, confLib, ... }: let inherit (config.swarselsystems) sopsFile; - servicePort = 8080; - serviceName = "kavita"; - serviceUser = "kavita"; - serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; - serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4; + inherit (confLib.gen { name = "kavita"; port = 8080; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; in { options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; @@ -7469,6 +8284,10 @@ lspci -k -d 14c3:0616 calibre ]; + swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + users.users.${serviceUser} = { extraGroups = [ "users" ]; }; @@ -7482,7 +8301,11 @@ lspci -k -d 14c3:0616 info = "https://${serviceDomain}"; icon = "${self}/files/topology-images/${serviceName}.png"; }; - globals.services.${serviceName}.domain = serviceDomain; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; services.${serviceName} = { enable = true; @@ -7492,7 +8315,7 @@ lspci -k -d 14c3:0616 dataDir = "/Vault/data/${serviceName}"; }; - nodes.moonside.services.nginx = { + nodes.${serviceProxy}.services.nginx = { upstreams = { ${serviceName} = { servers = { @@ -7526,23 +8349,26 @@ lspci -k -d 14c3:0616 :END: #+begin_src nix-ts :tangle modules/nixos/server/jellyfin.nix - { pkgs, lib, config, globals, ... }: + { pkgs, lib, config, globals, dns, confLib, ... }: let - servicePort = 8096; - serviceName = "jellyfin"; - serviceUser = "jellyfin"; - serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; - serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4; + inherit (confLib.gen { name = "jellyfin"; port = 8096; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; in { options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { + + swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + users.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; [ @@ -7554,7 +8380,11 @@ lspci -k -d 14c3:0616 }; topology.self.services.${serviceName}.info = "https://${serviceDomain}"; - globals.services.${serviceName}.domain = serviceDomain; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; services.${serviceName} = { enable = true; @@ -7562,7 +8392,7 @@ lspci -k -d 14c3:0616 openFirewall = true; # this works only for the default ports }; - nodes.moonside.services.nginx = { + nodes.${serviceProxy}.services.nginx = { upstreams = { ${serviceName} = { servers = { @@ -7597,18 +8427,18 @@ lspci -k -d 14c3:0616 :END: #+begin_src nix-ts :tangle modules/nixos/server/navidrome.nix - { pkgs, config, lib, globals, ... }: + { pkgs, config, lib, globals, dns, confLib, ... }: let - servicePort = 4040; - serviceName = "navidrome"; - serviceUser = "navidrome"; - serviceGroup = serviceUser; - serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; - serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4; + inherit (confLib.gen { name = "navidrome"; port = 4040; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; in { options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { + + swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + environment.systemPackages = with pkgs; [ pciutils alsa-utils @@ -7638,7 +8468,10 @@ lspci -k -d 14c3:0616 networking.firewall.allowedTCPPorts = [ servicePort ]; - globals.services.${serviceName}.domain = serviceDomain; + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; services.snapserver = { enable = true; @@ -7702,7 +8535,7 @@ lspci -k -d 14c3:0616 }; }; - nodes.moonside.services.nginx = { + nodes.${serviceProxy}.services.nginx = { upstreams = { ${serviceName} = { servers = { @@ -7764,12 +8597,9 @@ lspci -k -d 14c3:0616 :END: #+begin_src nix-ts :tangle modules/nixos/server/spotifyd.nix - { lib, config, ... }: + { lib, config, confLib, ... }: let - servicePort = 1025; - serviceName = "spotifyd"; - serviceUser = "spotifyd"; - serviceGroup = serviceUser; + inherit (confLib.gen { name = "spotifyd"; port = 1025; }) servicePort serviceName serviceUser serviceGroup; in { options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; @@ -7823,14 +8653,10 @@ lspci -k -d 14c3:0616 :END: #+begin_src nix-ts :tangle modules/nixos/server/mpd.nix - { self, lib, config, pkgs, ... }: + { self, lib, config, pkgs, confLib, ... }: let inherit (config.swarselsystems) sopsFile; - - servicePort = 3254; - serviceUser = "mpd"; - serviceGroup = serviceUser; - serviceName = "mpd"; + inherit (confLib.gen { name = "mpd"; port = 3254; }) servicePort serviceName serviceUser serviceGroup; in { options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; @@ -7925,9 +8751,9 @@ lspci -k -d 14c3:0616 :END: #+begin_src nix-ts :tangle modules/nixos/server/postgresql.nix - { config, lib, pkgs, ... }: + { config, lib, pkgs, confLib, ... }: let - serviceName = "postgresql"; + inherit (confLib.gen { name = "postgresql"; port = 3254; }) serviceName; postgresVersion = 14; in { @@ -7950,15 +8776,10 @@ lspci -k -d 14c3:0616 :END: #+begin_src nix-ts :tangle modules/nixos/server/matrix.nix - { lib, config, pkgs, globals, ... }: + { lib, config, pkgs, globals, dns, confLib, ... }: let inherit (config.swarselsystems) sopsFile; - - servicePort = 8008; - serviceName = "matrix"; - serviceDomain = config.repo.secrets.common.services.domains.matrix; - serviceUser = "matrix-synapse"; - serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4; + inherit (confLib.gen { name = "matrix"; user = "matrix-synapse"; port = 8008; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; federationPort = 8448; whatsappPort = 29318; @@ -7976,6 +8797,11 @@ lspci -k -d 14c3:0616 { options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { + + swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + environment.systemPackages = with pkgs; [ matrix-synapse lottieconverter @@ -8043,7 +8869,10 @@ lspci -k -d 14c3:0616 }; }; - globals.services.${serviceName}.domain = serviceDomain; + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; services = { postgresql = { @@ -8242,7 +9071,7 @@ lspci -k -d 14c3:0616 # messages out after a while. - nodes.moonside.services.nginx = { + nodes.${serviceProxy}.services.nginx = { upstreams = { ${serviceName} = { servers = { @@ -8306,17 +9135,11 @@ lspci -k -d 14c3:0616 :END: #+begin_src nix-ts :tangle modules/nixos/server/nextcloud.nix - { pkgs, lib, config, globals, ... }: + { pkgs, lib, config, globals, dns, confLib, ... }: let inherit (config.repo.secrets.local.nextcloud) adminuser; inherit (config.swarselsystems) sopsFile; - - servicePort = 80; - serviceUser = "nextcloud"; - serviceGroup = serviceUser; - serviceName = "nextcloud"; - serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; - serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4; + inherit (confLib.gen { name = "nextcloud"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; nextcloudVersion = "32"; in @@ -8324,13 +9147,19 @@ lspci -k -d 14c3:0616 options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { + swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + sops.secrets = { nextcloud-admin-pw = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; kanidm-nextcloud-client = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; }; - - globals.services.${serviceName}.domain = serviceDomain; + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; services = { ${serviceName} = { @@ -8358,7 +9187,7 @@ lspci -k -d 14c3:0616 }; }; - nodes.moonside.services.nginx = { + nodes.${serviceProxy}.services.nginx = { upstreams = { ${serviceName} = { servers = { @@ -8392,24 +9221,28 @@ lspci -k -d 14c3:0616 :END: #+begin_src nix-ts :tangle modules/nixos/server/immich.nix - { lib, pkgs, config, globals, ... }: + { lib, pkgs, config, globals, dns, confLib, ... }: let - servicePort = 3001; - serviceUser = "immich"; - serviceName = "immich"; - serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; - serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4; + inherit (confLib.gen { name = "immich"; port = 3001; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; in { options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { + swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + users.users.${serviceUser} = { extraGroups = [ "video" "render" "users" ]; }; topology.self.services.${serviceName}.info = "https://${serviceDomain}"; - globals.services.${serviceName}.domain = serviceDomain; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; services.${serviceName} = { enable = true; @@ -8423,9 +9256,9 @@ lspci -k -d 14c3:0616 }; }; - networking.firewall.allowedTCPPorts = [ 3001 ]; + networking.firewall.allowedTCPPorts = [ servicePort ]; - nodes.moonside.services.nginx = { + nodes.${serviceProxy}.services.nginx = { upstreams = { ${serviceName} = { servers = { @@ -8474,16 +9307,10 @@ This is my personal document management system. It automatically pulls documents Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml='s. This is needed for e.g. online services that only send their invoices through email body text. #+begin_src nix-ts :tangle modules/nixos/server/paperless.nix - { lib, pkgs, config, globals, ... }: + { lib, pkgs, config, dns, globals, confLib, ... }: let inherit (config.swarselsystems) sopsFile; - - servicePort = 28981; - serviceUser = "paperless"; - serviceGroup = serviceUser; - serviceName = "paperless"; - serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; - serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4; + inherit (confLib.gen { name = "paperless"; port = 28981; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; tikaPort = 9998; gotenbergPort = 3002; @@ -8493,6 +9320,10 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { + swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + users.users.${serviceUser} = { extraGroups = [ "users" ]; }; @@ -8504,7 +9335,10 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= networking.firewall.allowedTCPPorts = [ servicePort ]; - globals.services.${serviceName}.domain = serviceDomain; + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; services = { ${serviceName} = { @@ -8574,7 +9408,7 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= ) ''; - nodes.moonside.services.nginx = { + nodes.${serviceProxy}.services.nginx = { upstreams = { ${serviceName} = { servers = { @@ -8613,10 +9447,9 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= :END: #+begin_src nix-ts :tangle modules/nixos/server/transmission.nix - { self, pkgs, lib, config, ... }: + { self, pkgs, lib, config, confLib, ... }: let - serviceName = "transmission"; - serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; + inherit (confLib.gen { name = "transmission"; }) serviceName serviceDomain; lidarrUser = "lidarr"; lidarrGroup = lidarrUser; @@ -8802,17 +9635,12 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= :END: #+begin_src nix-ts :tangle modules/nixos/server/syncthing.nix - { lib, config, configName, globals, ... }: + { lib, config, globals, dns, confLib, ... }: let inherit (config.swarselsystems.syncthing) serviceDomain; - inherit (config.swarselsystems.syncthing) serviceIP; + inherit (confLib.gen { name = "syncthing"; port = 8384; }) servicePort serviceName serviceUser serviceGroup serviceAddress serviceProxy proxyAddress4 proxyAddress6; - servicePort = 8384; - serviceUser = "syncthing"; - serviceGroup = serviceUser; - serviceName = "syncthing"; - serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4; - specificServiceName = "syncthing-${configName}"; + specificServiceName = "${serviceName}-${config.node.name}"; cfg = config.services.${serviceName}; devices = config.swarselsystems.syncthing.syncDevices; @@ -8826,10 +9654,6 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= type = lib.types.str; default = config.repo.secrets.common.services.domains.syncthing1; }; - serviceIP = lib.mkOption { - type = lib.types.str; - default = "${serviceAddress}"; - }; syncDevices = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ "magicant" "winters" "pyramid" "moonside@oracle" ]; @@ -8855,6 +9679,10 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= }; config = lib.mkIf config.swarselmodules.server.${serviceName} { + swarselsystems.server.dns.${globals.services.${specificServiceName}.baseDomain}.subdomainRecords = { + "${globals.services.${specificServiceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + users.users.${serviceUser} = { extraGroups = [ "users" ]; group = serviceGroup; @@ -8865,7 +9693,10 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= networking.firewall.allowedTCPPorts = [ servicePort ]; - globals.services."${specificServiceName}".domain = serviceDomain; + globals.services.${specificServiceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; services.${serviceName} = rec { enable = true; @@ -8921,11 +9752,11 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= }; }; - nodes.moonside.services.nginx = { + nodes.${serviceProxy}.services.nginx = { upstreams = { ${specificServiceName} = { servers = { - "${serviceIP}:${builtins.toString servicePort}" = { }; + "${serviceAddress}:${builtins.toString servicePort}" = { }; }; }; }; @@ -9030,14 +9861,9 @@ This manages backups for my pictures and obsidian files. This section exposes several metrics that I use to check the health of my server. I need to expand on the exporters section at some point, but for now I have everything I need. #+begin_src nix-ts :tangle modules/nixos/server/monitoring.nix - { self, lib, config, globals, ... }: + { self, lib, config, globals, dns, confLib, ... }: let - servicePort = 3000; - serviceUser = "grafana"; - serviceGroup = serviceUser; - serviceName = "grafana"; - serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; - serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4; + inherit (confLib.gen { name = "grafana"; port = 3000; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; prometheusPort = 9090; prometheusUser = "prometheus"; @@ -9053,6 +9879,10 @@ This section exposes several metrics that I use to check the health of my server options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { + swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + sops = { secrets = { grafana-admin-pw = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; @@ -9089,7 +9919,11 @@ This section exposes several metrics that I use to check the health of my server networking.firewall.allowedTCPPorts = [ servicePort prometheusPort ]; topology.self.services.prometheus.info = "https://${serviceDomain}/${prometheusWebRoot}"; - globals.services.${serviceName}.domain = serviceDomain; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; services = { ${serviceName} = { @@ -9238,7 +10072,7 @@ This section exposes several metrics that I use to check the health of my server }; - nodes.moonside.services.nginx = { + nodes.${serviceProxy}.services.nginx = { upstreams = { "${grafanaUpstream}" = { servers = { @@ -9286,17 +10120,23 @@ This section exposes several metrics that I use to check the health of my server This is a WIP Jenkins instance. It is used to automatically build a new system when pushes to the main repository are detected. I have turned this service off for now however, as I actually prefer to start my builds manually. #+begin_src nix-ts :tangle modules/nixos/server/jenkins.nix - { pkgs, lib, config, globals, ... }: + { pkgs, lib, config, globals, dns, confLib, ... }: let - servicePort = 8088; - serviceName = "jenkins"; - serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; - serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4; + inherit (confLib.gen { name = "jenkins"; port = 8088; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; in { options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { + swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + services.jenkins = { enable = true; withCLI = true; @@ -9306,7 +10146,7 @@ This is a WIP Jenkins instance. It is used to automatically build a new system w home = "/Vault/apps/${serviceName}"; }; - services.nginx = { + nodes.${serviceProxy}.services.nginx = { upstreams = { ${serviceName} = { servers = { @@ -9343,10 +10183,9 @@ This is a WIP Jenkins instance. It is used to automatically build a new system w This was an approach of hosting an RSS server from within emacs. That would have been useful as it would have allowed me to allow my feeds from any device. However, it proved impossible to do bidirectional syncing, so I abandoned this configuration in favor of [[#h:9da3df74-6fc5-4ee1-a345-23ab4e8a613d][FreshRSS]]. #+begin_src nix-ts :tangle modules/nixos/server/emacs.nix - { lib, config, ... }: + { lib, config, confLib, ... }: let - serviceName = "emacs"; - servicePort = 9812; + inherit (confLib.gen { name = "emacs"; port = 9812; }) servicePort serviceName; in { options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} server on server"; @@ -9379,14 +10218,9 @@ I am using this with CapyReader on my phone, set it up as a FreshRSS account wit FreshRSS claims to support HTTP header auth, but at least it does not work with my oauth2-proxy setup. Until this is fixed, I resorted to the "form" login, since I mostly do not use the web version anyways. #+begin_src nix-ts :tangle modules/nixos/server/freshrss.nix - { self, lib, config, globals, ... }: + { self, lib, config, globals, dns, confLib, ... }: let - servicePort = 80; - serviceName = "freshrss"; - serviceUser = "freshrss"; - serviceGroup = serviceName; - serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; - serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4; + inherit (confLib.gen { name = "freshrss"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; inherit (config.swarselsystems) sopsFile; in @@ -9394,6 +10228,10 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { + swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + users.users.${serviceUser} = { extraGroups = [ "users" ]; group = serviceGroup; @@ -9435,7 +10273,10 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with icon = "${self}/files/topology-images/${serviceName}.png"; }; - globals.services.${serviceName}.domain = serviceDomain; + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; services.${serviceName} = let @@ -9455,7 +10296,7 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with # config.sops.templates.freshrss-env.path # ]; - nodes.moonside.services.nginx = { + nodes.${serviceProxy}.services.nginx = { upstreams = { ${serviceName} = { servers = { @@ -9493,16 +10334,10 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with :END: #+begin_src nix-ts :tangle modules/nixos/server/forgejo.nix - { lib, config, pkgs, globals, ... }: + { lib, config, pkgs, globals, dns, confLib, ... }: let inherit (config.swarselsystems) sopsFile; - - servicePort = 3004; - serviceUser = "forgejo"; - serviceGroup = serviceUser; - serviceName = "forgejo"; - serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; - serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4; + inherit (confLib.gen { name = "forgejo"; port = 3004; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; kanidmDomain = globals.services.kanidm.domain; in @@ -9510,6 +10345,10 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { + swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + networking.firewall.allowedTCPPorts = [ servicePort ]; users.users.${serviceUser} = { @@ -9523,7 +10362,10 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with kanidm-forgejo-client = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; }; - globals.services.${serviceName}.domain = serviceDomain; + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; services.${serviceName} = { enable = true; @@ -9624,7 +10466,7 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with ''; }; - nodes.moonside.services.nginx = { + nodes.${serviceProxy}.services.nginx = { upstreams = { ${serviceName} = { servers = { @@ -9659,14 +10501,10 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with :END: #+begin_src nix-ts :tangle modules/nixos/server/ankisync.nix - { self, lib, config, globals, ... }: + { self, lib, config, globals, dns, confLib, ... }: let inherit (config.swarselsystems) sopsFile; - - servicePort = 27701; - serviceName = "ankisync"; - serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; - serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4; + inherit (confLib.gen { name = "ankisync"; port = 27701; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; ankiUser = globals.user.name; in @@ -9674,6 +10512,10 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { + swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + networking.firewall.allowedTCPPorts = [ servicePort ]; sops.secrets.anki-pw = { inherit sopsFile; owner = "root"; }; @@ -9684,7 +10526,10 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with info = "https://${serviceDomain}"; }; - globals.services.${serviceName}.domain = serviceDomain; + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; services.anki-sync-server = { enable = true; @@ -9699,7 +10544,7 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with ]; }; - nodes.moonside.services.nginx = { + nodes.${serviceProxy}.services.nginx = { upstreams = { ${serviceName} = { servers = { @@ -9741,19 +10586,13 @@ A stupid (but simple) way to get the =originUrl= is to simply set any URL there To get other URLs (token, etc.), use https:///oauth2/openid//.well-known/oauth-authorization-server, e.g. https:///oauth2/openid/nextcloud/.well-known/oauth-authorization-server, with clienID being the client name as specified in kanidm. #+begin_src nix-ts :tangle modules/nixos/server/kanidm.nix - { self, lib, pkgs, config, globals, ... }: + { self, lib, pkgs, config, globals, dns, confLib, ... }: let certsSopsFile = self + /secrets/certs/secrets.yaml; inherit (config.swarselsystems) sopsFile; + inherit (confLib.gen { name = "kanidm"; port = 8300; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; - servicePort = 8300; - serviceUser = "kanidm"; - serviceGroup = serviceUser; - serviceName = "kanidm"; - serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; - serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4; - - oauth2ProxyDomain = globals.services.oauth2Proxy.domain; + oauth2ProxyDomain = globals.services.oauth2-proxy.domain; immichDomain = globals.services.immich.domain; paperlessDomain = globals.services.paperless.domain; forgejoDomain = globals.services.forgejo.domain; @@ -9780,6 +10619,10 @@ To get other URLs (token, etc.), use https:///oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid/ specify the ssh port to use for remote access. Default=${ssh_port}." echo " --debug Enable debug mode." + echo " --no-disko-deps Upload only disk script and not dependencies (for use on low ram)." echo " -h | --help Print this help." exit 0 } @@ -19751,14 +21110,14 @@ This program sets up a new NixOS host remotely. It also takes care of secret man SOPS_FILE=".sops.yaml" sed -i "{ - # Remove any * and & entries for this host - /[*&]$key_name/ d; - # Inject a new age: entry - # n matches the first line following age: and p prints it, then we transform it while reusing the spacing - /age:/{n; p; s/\(.*- \*\).*/\1$key_name/}; - # Inject a new hosts or user: entry - /&$key_type/{n; p; s/\(.*- &\).*/\1$key_name $key/} - }" $SOPS_FILE + # Remove any * and & entries for this host + /[*&]$key_name/ d; + # Inject a new age: entry + # n matches the first line following age: and p prints it, then we transform it while reusing the spacing + /age:/{n; p; s/\(.*- \*\).*/\1$key_name/}; + # Inject a new hosts or user: entry + /&$key_type/{n; p; s/\(.*- &\).*/\1$key_name $key/} + }" $SOPS_FILE green "Updating .sops.yaml" cd - } @@ -19785,6 +21144,9 @@ This program sets up a new NixOS host remotely. It also takes care of secret man shift ssh_port=$1 ;; + --no-disko-deps) + no_disko_deps="true" + ;; --debug) set -x ;; @@ -19802,6 +21164,12 @@ This program sets up a new NixOS host remotely. It also takes care of secret man help_and_exit fi + LOCKED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.node.lockFromBootstrapping)" + if [[ $LOCKED == "true" ]]; then + red "THIS SYSTEM IS LOCKED FROM BOOTSTRAPPING" + exit + fi + green "~SwarselSystems~ remote installer" green "Reading system information for $target_hostname ..." @@ -19812,6 +21180,11 @@ This program sets up a new NixOS host remotely. It also takes care of secret man if [[ $CRYPTED == "true" ]]; then green "Encryption: ✓" disk_encryption=1 + disk_encryption_args=( + --disk-encryption-keys + /tmp/disko-password + /tmp/disko-password + ) else red "Encryption: X" disk_encryption=0 @@ -19904,7 +21277,14 @@ This program sets up a new NixOS host remotely. It also takes care of secret man # ------------------------ green "Deploying minimal NixOS installation on $target_destination" - nix run github:nix-community/nixos-anywhere/1.10.0 -- --ssh-port "$ssh_port" --extra-files "$temp" --flake ./install#"$target_hostname" root@"$target_destination" + + if [[ $no_disko_deps == "true" ]]; then + green "Building without disko dependencies (using custom kexec)" + nix run github:nix-community/nixos-anywhere/1.10.0 -- "${disk_encryption_args[@]}" --no-disko-deps --ssh-port "$ssh_port" --extra-files "$temp" --flake ./install#"$target_hostname" --kexec "$(nix build --print-out-paths .#packages."$target_arch".swarsel-kexec)/swarsel-kexec-$target_arch.tar.gz" root@"$target_destination" + else + green "Building with disko dependencies (using nixos-images kexec)" + nix run github:nix-community/nixos-anywhere/1.10.0 -- "${disk_encryption_args[@]}" --ssh-port "$ssh_port" --extra-files "$temp" --flake ./install#"$target_hostname" root@"$target_destination" + fi echo "Updating ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true @@ -21532,6 +22912,7 @@ This holds modules that are to be used on most hosts. These are also the most im atuin = lib.mkDefault true; autotiling = lib.mkDefault false; batsignal = lib.mkDefault false; + bash = lib.mkDefault true; blueman-applet = lib.mkDefault true; desktop = lib.mkDefault false; direnv = lib.mkDefault true; @@ -25929,8 +27310,11 @@ This file defines a few workflows that I often need to run when working on my co sync USER HOST: rsync -rltv --filter=':- .gitignore' -e "ssh -l {{USER}}" . {{USER}}@{{HOST}}:.dotfiles/ - bootstrap DEST CONFIG ARCH="x86_64-linux": - nix develop .#deploy --command zsh -c "swarsel-bootstrap -n {{CONFIG}} -d {{DEST}} -a {{ARCH}}" + secrets USER HOST: + rsync -rltv -e "ssh -l {{USER}}" /var/tmp/nix-import-encrypted/1000/ {{USER}}@{{HOST}}:/var/tmp/nix-import-encrypted/0 + + bootstrap DEST CONFIG ARCH="x86_64-linux" NODISKODEPS="": + nix develop .#deploy --command zsh -c "swarsel-bootstrap {{NODISKODEPS}} -n {{CONFIG}} -d {{DEST}} -a {{ARCH}}" #+end_src ** aspell.conf @@ -26849,8 +28233,10 @@ The double source block is intended here to circumvent a org-babel convenience w transform-origin: 0px calc(0px - var(--tab-min-height) - var(--tab-block-margin) * 2); transform: rotateX(89.9deg); } - #mainPopupSet:has(> [panelopen]:not(#ask-chat-shortcuts,#selection-shortcut-action-panel,#chat-shortcuts-options-panel,#tab-preview-panel)) ~ toolbox #urlbar[popover], - /* swarsel: removed :hover from below line */ + + :root[window-modal-open] #urlbar[popover], + #mainPopupSet:has(> [panelopen]:not(#ask-chat-shortcuts,#selection-shortcut-action-panel,#chat-shortcuts-options-panel,#tab-preview-panel), > #tab-group-editor > [panelopen]) ~ toolbox #urlbar[popover], + /* swarsel: removed :hover from below line */ #navigator-toolbox:is(:focus-within,[movingtab]) #urlbar[popover], #urlbar-container > #urlbar[popover]:is([focused],[open]){ pointer-events: auto; @@ -26858,9 +28244,11 @@ The double source block is intended here to circumvent a org-babel convenience w transition-delay: 33ms; transform: rotateX(0deg); } - #mainPopupSet:has(> [panelopen]:not(#ask-chat-shortcuts,#selection-shortcut-action-panel,#chat-shortcuts-options-panel,#tab-preview-panel)) ~ toolbox, + + :root[window-modal-open] #navigator-toolbox, + #mainPopupSet:has(> [panelopen]:not(#ask-chat-shortcuts,#selection-shortcut-action-panel,#chat-shortcuts-options-panel,#tab-preview-panel), > #tab-group-editor > [panelopen]) ~ toolbox, #navigator-toolbox:has(#urlbar:is([open],[focus-within])), - /* swarsel: removed :hover from below line */ + /* swarsel: removed :hover from below line */ #navigator-toolbox:is(:focus-within,[movingtab]){ transition-delay: 33ms !important; transform: rotateX(0); @@ -26869,8 +28257,7 @@ The double source block is intended here to circumvent a org-babel convenience w /* This makes things like OS menubar/taskbar show the toolbox when hovered in maximized windows. ,* Unfortunately it also means that other OS native surfaces (such as context menu on macos) ,* and other always-on-top applications will trigger toolbox to show up. */ - @media (-moz-bool-pref: "userchrome.autohide-toolbox.unhide-by-native-ui.enabled"), - -moz-pref("userchrome.autohide-toolbox.unhide-by-native-ui.enabled"){ + @media -moz-pref("userchrome.autohide-toolbox.unhide-by-native-ui.enabled"){ :root[sizemode="maximized"]:not(:hover){ #navigator-toolbox:not(:-moz-window-inactive), #urlbar[popover]:not(:-moz-window-inactive){ @@ -26900,13 +28287,9 @@ The double source block is intended here to circumvent a org-babel convenience w padding-block: calc(min(4px,(var(--urlbar-container-height) - var(--urlbar-height)) / 2) + var(--urlbar-container-padding)) !important; } - /* Uncomment this if tabs toolbar is hidden with hide_tabs_toolbar.css */ - /*#titlebar{ margin-bottom: -9px }*/ - /* Uncomment the following for compatibility with tabs_on_bottom.css - this isn't well tested though */ /* #navigator-toolbox{ flex-direction: column; display: flex; } - #titlebar{ order: 2 } ,*/ #+end_src diff --git a/index.html b/index.html index 73a386f..c39ce5b 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> - + SwarselSystems: NixOS + Emacs Configurationo @@ -209,8 +209,8 @@
  • 1.4. Hosts
  • 1.5. Programs
  • 1.6. Services
  • -
  • 1.7. Manual steps when setting up a new machine
  • -
  • 1.8. Current issues
  • +
  • 1.7. Manual steps when setting up a new machine
  • +
  • 1.8. Current issues
  • 2. flake.nix @@ -269,28 +269,28 @@
  • 3.1.2.3.2. hardware-configuration
  • -
  • 3.1.2.4. Summers (Server: ASUS Z10PA-D8) +
  • 3.1.2.4. Summers (Server: ASUS Z10PA-D8)
  • -
  • 3.1.2.5. Hintbooth (Router: HUNSN RM02) +
  • 3.1.2.5. Hintbooth (Router: HUNSN RM02)
  • 3.1.2.6. machpizza (MacBook Pro)
  • 3.1.2.7. Magicant (Phone)
  • -
  • 3.1.2.8. Treehouse (DGX Spark)
  • +
  • 3.1.2.8. Treehouse (DGX Spark)
  • 3.1.3. Virtual hosts @@ -302,6 +302,27 @@
  • 3.1.3.1.3. disko
  • +
  • 3.1.3.2. Belchsfactory (OCI) + +
  • +
  • 3.1.3.3. Milkywell (OCI) + +
  • +
  • 3.1.3.4. Eagleland (Hetzner) + +
  • 3.1.4. Utility hosts @@ -313,12 +334,13 @@
  • 3.1.4.2. TODO Drugstore (ISO installer config)
  • -
  • 3.1.4.3. Hotel (Demo Physical/VM) +
  • 3.1.4.3. Brick Road (kexec image)
  • +
  • 3.1.4.4. Hotel (Demo Physical/VM)
  • @@ -406,9 +428,9 @@
  • 3.2.3.4. nfs/samba (smb)
  • 3.2.3.5. NGINX
  • 3.2.3.6. ssh
  • -
  • 3.2.3.7. Network settings
  • -
  • 3.2.3.8. Disk encryption
  • -
  • 3.2.3.9. Router
  • +
  • 3.2.3.7. Network settings
  • +
  • 3.2.3.8. Disk encryption
  • +
  • 3.2.3.9. Router
  • 3.2.3.10. kavita
  • 3.2.3.11. jellyfin
  • 3.2.3.12. navidrome
  • @@ -441,8 +463,12 @@
  • 3.2.3.39. slink
  • 3.2.3.40. Snipe-IT
  • 3.2.3.41. Homebox
  • -
  • 3.2.3.42. OPKSSH
  • -
  • 3.2.3.43. Garage
  • +
  • 3.2.3.42. OPKSSH
  • +
  • 3.2.3.43. Garage
  • +
  • 3.2.3.44. nsd (dns)
  • +
  • 3.2.3.45. nsd (dns) - site1
  • +
  • 3.2.3.46. Minecraft
  • +
  • 3.2.3.47. Mailserver
  • 3.2.4. Darwin @@ -462,15 +488,15 @@
  • 3.2.5.8. Hibernation
  • 3.2.5.9. BTRFS
  • 3.2.5.10. work
  • -
  • 3.2.5.11. microvm-host
  • -
  • 3.2.5.12. microvm-guest
  • +
  • 3.2.5.11. microvm-host
  • +
  • 3.2.5.12. microvm-guest
  • 3.3. Home-manager @@ -962,7 +990,7 @@ system-configuration-options
    ---prefix=/nix/store/3ncyph43ppsx6dnx46faxr5dmv9g8ym7-emacs-git-pgtk-20251013.0 --disable-build-details --with-modules --with-pgtk --disable-gc-mark-trace --with-compress-install --with-toolkit-scroll-bars --with-native-compilation --without-imagemagick --with-mailutils --without-small-ja-dic --with-tree-sitter --without-xinput2 --without-xwidgets --with-dbus --with-selinux
    +--prefix=/nix/store/al2a1g9wz4w7ixx0d7ain2myhchxiv74-emacs-git-pgtk-20251013.0 --disable-build-details --with-modules --with-pgtk --disable-gc-mark-trace --with-compress-install --with-toolkit-scroll-bars --with-native-compilation --without-imagemagick --with-mailutils --without-small-ja-dic --with-tree-sitter --without-xinput2 --without-xwidgets --with-dbus --with-selinux
     
    @@ -1193,13 +1221,14 @@ Here I give a brief overview over the hostmachines that I am using. This is held |🖥️ **winters** | ASRock J4105-ITX, 32GB RAM | Secondary homeserver and data storgae | |🖥️ **summers** | ASUS Z10PA-D8, 2* Intel Xeon E5-2650 v4, 128GB RAM | Main homeserver running microvms, data storage | |🖥️ **hintbooth** | HUNSN RM02, 8GB RAM | Router | -|☁️ **milkywell** | Oracle Cloud: VM.Standard.E2.1.Micro | Server for lightweight synchronization tasks | +|☁️ **milkywell** | Oracle Cloud: VM.Standard.E2.1.Micro | Authoritative DNS server | |☁️ **moonside** | Oracle Cloud: VM.Standard.A1.Flex, 4 OCPUs, 24GB RAM| Proxy for local services, some lightweight services | |☁️ **belchsfactory**| Oracle Cloud: VM.Standard.A1.Flex, 4 OCPUs, 24GB RAM| Hydra builder and nix binary cache | |☁️ **monkeycave** | Oracle Cloud: VM.Standard.A1.Flex, 4 OCPUs, 24GB RAM| Gaming server | |☁️ **eagleland** | Hetzner Cloud: CX23 | Mail server | |📱 **magicant** | Samsung Galaxy Z Flip 6 | Phone | |💿 **drugstore** | - | ISO installer configuration | +|💿 **brickroad** | - | Kexec tarball | |❔ **chaotheatre** | - | Demo config for checking out my configurtion | |❔ **toto** | - | Helper configuration for bootstrapping a new system | @@ -1258,8 +1287,8 @@ Here I give a brief overview over the hostmachines that I am using. This is held -
    -

    1.7. Manual steps when setting up a new machine

    +
    +

    1.7. Manual steps when setting up a new machine

    These steps are required when setting up a normal NixOS host:
    @@ -1335,8 +1364,8 @@ If the new machine is home-manager only, perform these steps:
       3) `home-manager --extra-experimental-features 'nix-command flakes' switch --flake .#$(hostname) --show-trace`
     
    -
    -

    1.8. Current issues

    +
    +

    1.8. Current issues

    Currently, these adaptions are made to the configuration to account for bugs in upstream repos:
    @@ -1519,100 +1548,57 @@ This provides devshell support for flake-parts
  • }; inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + smallpkgs.url = "github:nixos/nixpkgs/08fcb0dcb59df0344652b38ea6326a2d8271baff?narHash=sha256-HXIQzULIG/MEUW2Q/Ss47oE3QrjxvpUX7gUl4Xp6lnc%3D&shallow=1"; nixpkgs-dev.url = "github:Swarsel/nixpkgs/main"; nixpkgs-kernel.url = "github:NixOS/nixpkgs/063f43f2dbdef86376cc29ad646c45c46e93234c?narHash=sha256-6m1Y3/4pVw1RWTsrkAK2VMYSzG4MMIj7sqUy7o8th1o%3D"; #specifically pinned for kernel version nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.05"; nixpkgs-stable24_05.url = "github:NixOS/nixpkgs/nixos-24.05"; nixpkgs-stable24_11.url = "github:NixOS/nixpkgs/nixos-24.11"; nixpkgs-stable25_05.url = "github:NixOS/nixpkgs/nixos-25.05"; - systems.url = "github:nix-systems/default"; - swarsel-modules.url = "github:Swarsel/swarsel-modules/main"; - swarsel-nix.url = "github:Swarsel/swarsel-nix/main"; + home-manager = { # url = "github:nix-community/home-manager"; url = "github:Swarsel/home-manager/main"; inputs.nixpkgs.follows = "nixpkgs"; }; - swarsel.url = "github:Swarsel/.dotfiles"; - emacs-overlay = { - # url = "github:nix-community/emacs-overlay"; - url = "github:nix-community/emacs-overlay/aba8daa237dc07a3bb28a61c252a718e8eb38057?narHash=sha256-4OXXccXsY1sBXTXjYIthdjXLAotozSh4F8StGRuLyMQ%3D"; + nix-index-database = { + url = "github:nix-community/nix-index-database"; inputs.nixpkgs.follows = "nixpkgs"; }; + + # emacs-overlay.url = "github:nix-community/emacs-overlay"; + emacs-overlay.url = "github:nix-community/emacs-overlay/aba8daa237dc07a3bb28a61c252a718e8eb38057?narHash=sha256-4OXXccXsY1sBXTXjYIthdjXLAotozSh4F8StGRuLyMQ%3D"; + swarsel-nix.url = "github:Swarsel/swarsel-nix/main"; + systems.url = "github:nix-systems/default"; nur.url = "github:nix-community/NUR"; nixgl.url = "github:guibou/nixGL"; stylix.url = "github:danth/stylix"; sops-nix.url = "github:Mic92/sops-nix"; lanzaboote.url = "github:nix-community/lanzaboote"; - nix-on-droid = { - url = "github:nix-community/nix-on-droid/release-24.05"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - nixos-generators = { - url = "github:nix-community/nixos-generators"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - nixos-hardware = { - url = "github:NixOS/nixos-hardware/master"; - }; - nswitch-rcm-nix = { - url = "github:Swarsel/nswitch-rcm-nix"; - }; - nix-index-database = { - url = "github:nix-community/nix-index-database"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - disko = { - url = "github:nix-community/disko"; - inputs.nixpkgs.follows = "nixpkgs"; - }; + nix-on-droid.url = "github:nix-community/nix-on-droid/release-24.05"; + nixos-generators.url = "github:nix-community/nixos-generators"; + nixos-images.url = "github:Swarsel/nixos-images/main"; + nixos-hardware.url = "github:NixOS/nixos-hardware/master"; + nswitch-rcm-nix.url = "github:Swarsel/nswitch-rcm-nix"; + disko.url = "github:nix-community/disko"; impermanence.url = "github:nix-community/impermanence"; - zjstatus = { - url = "github:dj95/zjstatus"; - }; - # has been upstreamed - # fw-fanctrl = { - # # url = "github:TamtamHero/fw-fanctrl/packaging/nix"; - # url = "github:Swarsel/fw-fanctrl/packaging/nix"; - # inputs.nixpkgs.follows = "nixpkgs"; - # }; - nix-darwin = { - url = "github:lnl7/nix-darwin"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - pre-commit-hooks = { - url = "github:cachix/git-hooks.nix"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - vbc-nix = { - url = "git+ssh://git@github.com/vbc-it/vbc-nix.git?ref=main"; - inputs.nixpkgs.follows = "nixpkgs"; - }; + zjstatus.url = "github:dj95/zjstatus"; + nix-darwin.url = "github:lnl7/nix-darwin"; + pre-commit-hooks.url = "github:cachix/git-hooks.nix"; + vbc-nix.url = "git+ssh://git@github.com/vbc-it/vbc-nix.git?ref=main"; nix-topology.url = "github:oddlama/nix-topology"; flake-parts.url = "github:hercules-ci/flake-parts"; - devshell = { - url = "github:numtide/devshell"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - spicetify-nix = { - url = "github:Gerg-l/spicetify-nix"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - niri-flake = { - url = "github:sodiboo/niri-flake"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - nixos-extra-modules = { - url = "github:oddlama/nixos-extra-modules"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - microvm = { - url = "github:astro/microvm.nix"; - inputs.nixpkgs.follows = "nixpkgs"; - }; + devshell.url = "github:numtide/devshell"; + spicetify-nix.url = "github:Gerg-l/spicetify-nix"; + niri-flake.url = "github:sodiboo/niri-flake"; + nixos-extra-modules.url = "github:oddlama/nixos-extra-modules/main"; + microvm.url = "github:astro/microvm.nix"; treefmt-nix.url = "github:numtide/treefmt-nix"; - + dns.url = "github:kirelagin/dns.nix"; + nix-minecraft.url = "github:Infinidoge/nix-minecraft"; + simple-nixos-mailserver.url = "gitlab:simple-nixos-mailserver/nixos-mailserver/master"; }; + outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } { @@ -1829,7 +1815,7 @@ let ) 4; subnetMask = lib.concatStringsSep "." (map toString octets); in - subnetMask; + subnetMask; mkIfElseList = p: yes: no: lib.mkMerge [ (lib.mkIf p yes) @@ -1838,6 +1824,23 @@ let mkIfElse = p: yes: no: if p then yes else no; + getSubDomain = domain: + let + parts = builtins.split "\\." domain; + domainParts = builtins.filter (x: builtins.isString x && x != "") parts; + in + if builtins.length domainParts > 0 + then builtins.head domainParts + else ""; + + getBaseDomain = domain: + let + parts = builtins.split "\\." domain; + domainParts = builtins.filter (x: builtins.isString x && x != "") parts; + baseParts = builtins.tail domainParts; + in + builtins.concatStringsSep "." baseParts; + pkgsFor = lib.genAttrs (import systems) (system: import inputs.nixpkgs { inherit system; @@ -1969,7 +1972,7 @@ Lastly, in order make this actually available to my configurations, i use the
    # adapted from https://github.com/oddlama/nix-config/blob/main/nix/globals.nix
    -{ self, inputs, ... }:
    +{ inputs, ... }:
     {
       flake = { config, lib, ... }:
         {
    @@ -2085,41 +2088,48 @@ The rest of the outputs either define or help define the actual configurations:
               };
               modules = [
                 inputs.disko.nixosModules.disko
    -            inputs.sops-nix.nixosModules.sops
    +            inputs.home-manager.nixosModules.home-manager
                 inputs.impermanence.nixosModules.impermanence
                 inputs.lanzaboote.nixosModules.lanzaboote
    -            inputs.nix-topology.nixosModules.default
    -            inputs.home-manager.nixosModules.home-manager
    -            inputs.stylix.nixosModules.stylix
    -            inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm
    -            # inputs.swarsel-modules.nixosModules.default
    -            inputs.swarsel-nix.nixosModules.default
    -            inputs.niri-flake.nixosModules.niri
                 inputs.microvm.nixosModules.host
                 inputs.microvm.nixosModules.microvm
    +            inputs.niri-flake.nixosModules.niri
    +            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-nix.nixosModules.sops
    +            inputs.stylix.nixosModules.stylix
    +            inputs.swarsel-nix.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;
     
    +              networking.hostName = lib.swarselsystems.mkStrong configName;
    +
                   node = {
                     name = lib.mkForce configName;
                     secretsDir = ../hosts/nixos/${arch}/${configName}/secrets;
    +                lockFromBootstrapping = lib.mkIf (!minimal) (lib.swarselsystems.mkStrong true);
                   };
     
                   swarselprofiles = {
    -                minimal = lib.mkIf minimal (lib.mkDefault true);
    +                minimal = lib.mkIf minimal (lib.swarselsystems.mkStrong true);
                   };
     
                   swarselmodules.server = {
    -                ssh = lib.mkIf (!minimal) (lib.mkDefault true);
    +                ssh = lib.mkIf (!minimal) (lib.swarselsystems.mkStrong true);
                   };
     
                   swarselsystems = {
    -                mainUser = lib.mkDefault "swarsel";
    +                mainUser = lib.swarselsystems.mkStrong "swarsel";
                   };
                 }
               ];
    @@ -2965,7 +2975,9 @@ in
                   // (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)
                 )
                 (modifications final prev);
    @@ -2996,19 +3008,32 @@ This is an improvement to what I did earlier, where I did not use nixos-ge
     {
       perSystem = { pkgs, system, ... }:
         {
    -      # nix build --print-out-paths --no-link .#images.<target-system>.live-iso
    -      packages.live-iso = inputs.nixos-generators.nixosGenerate {
    -        inherit pkgs;
    -        specialArgs = { inherit self; };
    -        modules = [
    -          inputs.home-manager.nixosModules.home-manager
    -          "${self}/install/installer-config.nix"
    -        ];
    -        format =
    +      packages = {
    +        # nix build --print-out-paths --no-link .#live-iso
    +        live-iso = inputs.nixos-generators.nixosGenerate {
    +          inherit pkgs;
    +          specialArgs = { inherit self; };
    +          modules = [
    +            inputs.home-manager.nixosModules.home-manager
    +            "${self}/install/installer-config.nix"
    +          ];
    +          format =
    +            {
    +              x86_64-linux = "install-iso";
    +              aarch64-linux = "sd-aarch64-installer";
    +            }.${system};
    +        };
    +
    +        # nix build --print-out-paths --no-link .#pnap-kexec --system <system>
    +        swarsel-kexec = (inputs.smallpkgs.legacyPackages.${system}.nixos [
               {
    -            x86_64-linux = "install-iso";
    -            aarch64-linux = "sd-aarch64-installer";
    -          }.${system};
    +            imports = [ "${self}/install/kexec.nix" ];
    +            _file = __curPos.file;
    +            system.kexec-installer.name = "swarsel-kexec";
    +          }
    +          inputs.nixos-images.nixosModules.kexec-installer
    +        ]).config.system.build.kexecInstallerTarball;
    +
           };
         };
     }
    @@ -3803,7 +3828,7 @@ This is my main server that I run at home. It handles most tasks that require bi
     
    3.1.2.3.1. Main Configuration
    -
    { lib, minimal, ... }:
    +
    { lib, config, minimal, ... }:
     {
     
       imports = [
    @@ -3830,13 +3855,17 @@ This is my main server that I run at home. It handles most tasks that require bi
         isBtrfs = false;
         isLinux = true;
         isNixos = true;
    -    server.garage = {
    -      data_dir = [
    -        {
    -          capacity = "200G";
    -          path = "/Vault/data/garage/main";
    -        }
    -      ];
    +    proxyHost = "moonside";
    +    server = {
    +      inherit (config.repo.secrets.local.networking) localNetwork;
    +      garage = {
    +        data_dir = [
    +          {
    +            capacity = "200G";
    +            path = "/Vault/data/garage/main";
    +          }
    +        ];
    +      };
         };
       };
     
    @@ -3940,12 +3969,12 @@ This is my main server that I run at home. It handles most tasks that require bi
     
    -
    -
    3.1.2.4. Summers (Server: ASUS Z10PA-D8)
    +
    +
    3.1.2.4. Summers (Server: ASUS Z10PA-D8)
    -
    -
    3.1.2.4.1. Main Configuration
    +
    +
    3.1.2.4.1. Main Configuration
    { inputs, lib, config, minimal, nodes, globals, ... }:
    @@ -4053,8 +4082,8 @@ This is my main server that I run at home. It handles most tasks that require bi
     
    -
    -
    3.1.2.4.2. hardware-configuration
    +
    +
    3.1.2.4.2. hardware-configuration
    { config, lib, modulesPath, ... }:
    @@ -4089,8 +4118,8 @@ This is my main server that I run at home. It handles most tasks that require bi
     
    -
    -
    3.1.2.4.3. disko
    +
    +
    3.1.2.4.3. disko
    { lib, config, ... }:
    @@ -4215,12 +4244,12 @@ in
     
    -
    -
    3.1.2.4.4. Guests
    +
    +
    3.1.2.4.4. Guests
    -
    -3.1.2.4.4.1. Guest 1 +
    +3.1.2.4.4.1. Guest 1
    { lib, minimal, ... }:
    @@ -4255,15 +4284,15 @@ in
     
    -
    -
    3.1.2.5. Hintbooth (Router: HUNSN RM02)
    +
    +
    3.1.2.5. Hintbooth (Router: HUNSN RM02)
    -
    -
    3.1.2.5.1. Main Configuration
    +
    +
    3.1.2.5.1. Main Configuration
    -
    { lib, minimal,  ... }:
    +
    { lib, config, minimal,  ... }:
     {
     
       imports = [
    @@ -4283,6 +4312,9 @@ in
         rootDisk = "/dev/sda";
         swapSize = "8G";
         networkKernelModules = [ "igb" ];
    +    server = {
    +      inherit (config.repo.secrets.local.networking) localNetwork;
    +    };
       };
     
     } // lib.optionalAttrs (!minimal) {
    @@ -4304,8 +4336,8 @@ in
     
    -
    -
    3.1.2.5.2. hardware-configuration
    +
    +
    3.1.2.5.2. hardware-configuration
    { config, lib, modulesPath, ... }:
    @@ -4336,8 +4368,8 @@ in
     
    -
    -
    3.1.2.5.3. disko
    +
    +
    3.1.2.5.3. disko
    { lib, config, ... }:
    @@ -4557,8 +4589,8 @@ My phone. I use only a minimal config for remote debugging here.
     
    -
    -
    3.1.2.8. Treehouse (DGX Spark)
    +
    +
    3.1.2.8. Treehouse (DGX Spark)
    { self, ... }:
    @@ -4642,7 +4674,6 @@ in
     
       sops = {
         age.sshKeyPaths = lib.mkDefault [ "/etc/ssh/ssh_host_ed25519_key" ];
    -    # defaultSopsFile = lib.mkForce "/home/swarsel/.dotfiles/secrets/moonside/secrets.yaml";
         secrets = {
           wireguard-private-key = { inherit sopsFile; };
           wireguard-home-preshared-key = { inherit sopsFile; };
    @@ -4769,9 +4800,12 @@ in
         isBtrfs = true;
         isNixos = true;
         isLinux = true;
    +    proxyHost = "moonside";
    +    server = {
    +      inherit (config.repo.secrets.local.networking) localNetwork;
    +    };
         syncthing = {
           serviceDomain = config.repo.secrets.common.services.domains.syncthing3;
    -      serviceIP = "localhost";
         };
       };
     } // lib.optionalAttrs (!minimal) {
    @@ -4946,6 +4980,684 @@ in
     }
     
     
    +
    +
    +
    +
    +
    +
    +
    3.1.3.2. Belchsfactory (OCI)
    +
    +
    +
    +
    3.1.3.2.1. Main Configuration
    +
    +
    +
    { lib, config, minimal, ... }:
    +{
    +  imports = [
    +    ./hardware-configuration.nix
    +    ./disk-config.nix
    +  ];
    +
    +  node.lockFromBootstrapping = lib.mkForce false;
    +
    +  topology.self = {
    +    icon = "devices.cloud-server";
    +  };
    +  swarselmodules.server.nginx = false;
    +
    +  swarselsystems = {
    +    flakePath = "/root/.dotfiles";
    +    info = "VM.Standard.A1.Flex, 4 vCPUs, 24GB RAM";
    +    isImpermanence = true;
    +    isSecureBoot = false;
    +    isCrypted = true;
    +    isSwap = false;
    +    rootDisk = "/dev/sda";
    +    isBtrfs = true;
    +    isNixos = true;
    +    isLinux = true;
    +    proxyHost = "belchsfactory";
    +    server = {
    +      inherit (config.repo.secrets.local.networking) localNetwork;
    +    };
    +  };
    +} // lib.optionalAttrs (!minimal) {
    +  swarselprofiles = {
    +    server = true;
    +  };
    +}
    +
    +
    +
    +
    +
    +
    +
    3.1.3.2.2. hardware-configuration
    +
    +
    +
    { lib, modulesPath, ... }:
    +{
    +  imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
    +
    +  boot = {
    +    initrd = {
    +      availableKernelModules = [ "xhci_pci" "virtio_pci" "virtio_scsi" "usbhid" ];
    +      kernelModules = [ ];
    +    };
    +    kernelModules = [ ];
    +    extraModulePackages = [ ];
    +  };
    +
    +  nixpkgs.hostPlatform = lib.mkForce "aarch64-linux";
    +}
    +
    +
    +
    +
    +
    +
    3.1.3.2.3. disko
    +
    +
    +
    { lib, pkgs, config, ... }:
    +let
    +  type = "btrfs";
    +  extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite
    +  subvolumes = {
    +    "/root" = {
    +      mountpoint = "/";
    +      mountOptions = [
    +        "subvol=root"
    +        "compress=zstd"
    +        "noatime"
    +      ];
    +    };
    +    "/home" = lib.mkIf config.swarselsystems.isImpermanence {
    +      mountpoint = "/home";
    +      mountOptions = [
    +        "subvol=home"
    +        "compress=zstd"
    +        "noatime"
    +      ];
    +    };
    +    "/persist" = lib.mkIf config.swarselsystems.isImpermanence {
    +      mountpoint = "/persist";
    +      mountOptions = [
    +        "subvol=persist"
    +        "compress=zstd"
    +        "noatime"
    +      ];
    +    };
    +    "/log" = lib.mkIf config.swarselsystems.isImpermanence {
    +      mountpoint = "/var/log";
    +      mountOptions = [
    +        "subvol=log"
    +        "compress=zstd"
    +        "noatime"
    +      ];
    +    };
    +    "/nix" = {
    +      mountpoint = "/nix";
    +      mountOptions = [
    +        "subvol=nix"
    +        "compress=zstd"
    +        "noatime"
    +      ];
    +    };
    +    "/swap" = lib.mkIf config.swarselsystems.isSwap {
    +      mountpoint = "/.swapvol";
    +      swap.swapfile.size = config.swarselsystems.swapSize;
    +    };
    +  };
    +in
    +{
    +  disko = {
    +    imageBuilder.extraDependencies = [ pkgs.kmod ];
    +    devices = {
    +      disk = {
    +        disk0 = {
    +          type = "disk";
    +          device = config.swarselsystems.rootDisk;
    +          content = {
    +            type = "gpt";
    +            partitions = {
    +              ESP = {
    +                priority = 1;
    +                name = "ESP";
    +                size = "512M";
    +                type = "EF00";
    +                content = {
    +                  type = "filesystem";
    +                  format = "vfat";
    +                  mountpoint = "/boot";
    +                  mountOptions = [ "defaults" ];
    +                };
    +              };
    +              root = lib.mkIf (!config.swarselsystems.isCrypted) {
    +                size = "100%";
    +                content = {
    +                  inherit type subvolumes extraArgs;
    +                  postCreateHook = lib.mkIf config.swarselsystems.isImpermanence ''
    +                    MNTPOINT=$(mktemp -d)
    +                    mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5
    +                    trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT
    +                    btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank
    +                  '';
    +                };
    +              };
    +              luks = lib.mkIf config.swarselsystems.isCrypted {
    +                size = "100%";
    +                content = {
    +                  type = "luks";
    +                  name = "cryptroot";
    +                  passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh
    +                  settings = {
    +                    allowDiscards = true;
    +                    # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36
    +                    crypttabExtraOpts = [
    +                      "fido2-device=auto"
    +                      "token-timeout=10"
    +                    ];
    +                  };
    +                  content = {
    +                    inherit type subvolumes extraArgs;
    +                    postCreateHook = lib.mkIf config.swarselsystems.isImpermanence ''
    +                      MNTPOINT=$(mktemp -d)
    +                      mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5
    +                      trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT
    +                      btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank
    +                    '';
    +                  };
    +                };
    +              };
    +            };
    +          };
    +        };
    +      };
    +    };
    +  };
    +
    +  fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true;
    +  fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true;
    +}
    +
    +
    +
    +
    +
    +
    +
    +
    3.1.3.3. Milkywell (OCI)
    +
    +
    +
    +
    3.1.3.3.1. Main Configuration
    +
    +
    +
    { lib, config, minimal, ... }:
    +{
    +  imports = [
    +    ./hardware-configuration.nix
    +    ./disk-config.nix
    +  ];
    +  node.lockFromBootstrapping = false;
    +  sops = {
    +    age.sshKeyPaths = lib.mkDefault [ "/etc/ssh/ssh_host_ed25519_key" ];
    +  };
    +
    +  topology.self = {
    +    icon = "devices.cloud-server";
    +  };
    +
    +  networking = {
    +    domain = "subnet03112148.vcn03112148.oraclevcn.com";
    +    firewall = {
    +      allowedTCPPorts = [ 53 ];
    +    };
    +  };
    +
    +  system.stateVersion = "23.11";
    +
    +  swarselsystems = {
    +    flakePath = "/root/.dotfiles";
    +    info = "VM.Standard.E2.1.Micro";
    +    isImpermanence = true;
    +    isSecureBoot = false;
    +    isCrypted = false;
    +    isSwap = true;
    +    swapSize = "8G";
    +    rootDisk = "/dev/sda";
    +    isBtrfs = true;
    +    isNixos = true;
    +    isLinux = true;
    +    server = {
    +      inherit (config.repo.secrets.local.networking) localNetwork;
    +    };
    +  };
    +} // lib.optionalAttrs (!minimal) {
    +  swarselprofiles = {
    +    server = true;
    +  };
    +
    +}
    +
    +
    +
    +
    +
    +
    +
    3.1.3.3.2. hardware-configuration
    +
    +
    +
    { lib, modulesPath, ... }:
    +
    +{
    +  imports =
    +    [
    +      (modulesPath + "/profiles/qemu-guest.nix")
    +    ];
    +
    +  boot = {
    +    initrd = {
    +      availableKernelModules = [ "ata_piix" "uhci_hcd" "virtio_pci" "virtio_scsi" "sd_mod" ];
    +      kernelModules = [ "dm-snapshot" ];
    +    };
    +    kernelModules = [ "kvm-amd" ];
    +    extraModulePackages = [ ];
    +  };
    +
    +  # Enables DHCP on each ethernet and wireless interface. In case of scripted networking
    +  # (the default) this is the recommended approach. When using systemd-networkd it's
    +  # still possible to use this option, but it's recommended to use it in conjunction
    +  # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
    +  networking.useDHCP = lib.mkDefault true;
    +  # networking.interfaces.ens3.useDHCP = lib.mkDefault true;
    +
    +  nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
    +}
    +
    +
    +
    +
    +
    +
    +
    3.1.3.3.3. disko
    +
    +
    +
    { lib, pkgs, config, ... }:
    +let
    +  type = "btrfs";
    +  extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite
    +  subvolumes = {
    +    "/root" = {
    +      mountpoint = "/";
    +      mountOptions = [
    +        "subvol=root"
    +        "compress=zstd"
    +        "noatime"
    +      ];
    +    };
    +    "/home" = lib.mkIf config.swarselsystems.isImpermanence {
    +      mountpoint = "/home";
    +      mountOptions = [
    +        "subvol=home"
    +        "compress=zstd"
    +        "noatime"
    +      ];
    +    };
    +    "/persist" = lib.mkIf config.swarselsystems.isImpermanence {
    +      mountpoint = "/persist";
    +      mountOptions = [
    +        "subvol=persist"
    +        "compress=zstd"
    +        "noatime"
    +      ];
    +    };
    +    "/log" = lib.mkIf config.swarselsystems.isImpermanence {
    +      mountpoint = "/var/log";
    +      mountOptions = [
    +        "subvol=log"
    +        "compress=zstd"
    +        "noatime"
    +      ];
    +    };
    +    "/nix" = {
    +      mountpoint = "/nix";
    +      mountOptions = [
    +        "subvol=nix"
    +        "compress=zstd"
    +        "noatime"
    +      ];
    +    };
    +    "/swap" = lib.mkIf config.swarselsystems.isSwap {
    +      mountpoint = "/.swapvol";
    +      swap.swapfile.size = config.swarselsystems.swapSize;
    +    };
    +  };
    +in
    +{
    +  disko = {
    +    imageBuilder.extraDependencies = [ pkgs.kmod ];
    +    devices = {
    +      disk = {
    +        disk0 = {
    +          type = "disk";
    +          device = config.swarselsystems.rootDisk;
    +          content = {
    +            type = "gpt";
    +            partitions = {
    +              ESP = {
    +                priority = 1;
    +                name = "ESP";
    +                size = "512M";
    +                type = "EF00";
    +                content = {
    +                  type = "filesystem";
    +                  format = "vfat";
    +                  mountpoint = "/boot";
    +                  mountOptions = [ "defaults" ];
    +                };
    +              };
    +              root = lib.mkIf (!config.swarselsystems.isCrypted) {
    +                size = "100%";
    +                content = {
    +                  inherit type subvolumes extraArgs;
    +                  postCreateHook = lib.mkIf config.swarselsystems.isImpermanence ''
    +                    MNTPOINT=$(mktemp -d)
    +                    mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5
    +                    trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT
    +                    btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank
    +                  '';
    +                };
    +              };
    +              luks = lib.mkIf config.swarselsystems.isCrypted {
    +                size = "100%";
    +                content = {
    +                  type = "luks";
    +                  name = "cryptroot";
    +                  passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh
    +                  settings = {
    +                    allowDiscards = true;
    +                    # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36
    +                    crypttabExtraOpts = [
    +                      "fido2-device=auto"
    +                      "token-timeout=10"
    +                    ];
    +                  };
    +                  content = {
    +                    inherit type subvolumes extraArgs;
    +                    postCreateHook = lib.mkIf config.swarselsystems.isImpermanence ''
    +                      MNTPOINT=$(mktemp -d)
    +                      mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5
    +                      trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT
    +                      btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank
    +                    '';
    +                  };
    +                };
    +              };
    +            };
    +          };
    +        };
    +      };
    +    };
    +  };
    +
    +  fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true;
    +  fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true;
    +}
    +
    +
    +
    +
    +
    +
    +
    3.1.3.4. Eagleland (Hetzner)
    +
    +
    +
    +
    3.1.3.4.1. Main Configuration
    +
    +
    +
    { lib, config, minimal, ... }:
    +{
    +  imports = [
    +    ./hardware-configuration.nix
    +    ./disk-config.nix
    +  ];
    +
    +  topology.self = {
    +    icon = "devices.cloud-server";
    +  };
    +
    +  networking = {
    +    useDHCP = lib.mkForce false;
    +    useNetworkd = true;
    +    dhcpcd.enable = false;
    +    renameInterfacesByMac = lib.mapAttrs (_: v: v.mac) (
    +      config.repo.secrets.local.networking.networks or { }
    +    );
    +  };
    +  boot.initrd.systemd.network = {
    +    enable = true;
    +    networks = {
    +      inherit (config.systemd.network.networks) "10-wan";
    +    };
    +  };
    +
    +  systemd = {
    +    network = {
    +      enable = true;
    +      wait-online.enable = false;
    +      networks =
    +        let
    +          netConfig = config.repo.secrets.local.networking;
    +        in
    +        {
    +          "10-wan" = {
    +            address = [
    +              "${netConfig.wanAddress4}/32"
    +              "${netConfig.wanAddress6}/64"
    +            ];
    +            gateway = [ "fe80::1" ];
    +            routes = [
    +              { Destination = netConfig.defaultGateway4; }
    +              {
    +                Gateway = netConfig.defaultGateway4;
    +                GatewayOnLink = true;
    +              }
    +            ];
    +            matchConfig.MACAddress = netConfig.networks.${config.swarselsystems.server.localNetwork}.mac;
    +            networkConfig.IPv6PrivacyExtensions = "yes";
    +            linkConfig.RequiredForOnline = "routable";
    +          };
    +        };
    +    };
    +  };
    +
    +  swarselmodules.server.mailserver = true;
    +
    +  swarselsystems = {
    +    flakePath = "/root/.dotfiles";
    +    info = "2vCPU, 4GB Ram";
    +    isImpermanence = true;
    +    isSecureBoot = false;
    +    isCrypted = true;
    +    isCloud = true;
    +    isSwap = true;
    +    swapSize = "4G";
    +    rootDisk = "/dev/sda";
    +    isBtrfs = true;
    +    isNixos = true;
    +    isLinux = true;
    +    proxyHost = "eagleland";
    +    server = {
    +      inherit (config.repo.secrets.local.networking) localNetwork;
    +    };
    +  };
    +} // lib.optionalAttrs (!minimal) {
    +  swarselprofiles = {
    +    server = true;
    +  };
    +
    +}
    +
    +
    +
    +
    +
    +
    +
    3.1.3.4.2. hardware-configuration
    +
    +
    +
    { lib, modulesPath, ... }:
    +
    +{
    +  imports =
    +    [
    +      (modulesPath + "/profiles/qemu-guest.nix")
    +    ];
    +
    +  boot = {
    +    initrd = {
    +      availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" ];
    +      kernelModules = [ ];
    +    };
    +    kernelModules = [ ];
    +    extraModulePackages = [ ];
    +  };
    +  nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
    +}
    +
    +
    +
    +
    +
    +
    +
    3.1.3.4.3. disko
    +
    +
    +
    { lib, pkgs, config, ... }:
    +let
    +  type = "btrfs";
    +  extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite
    +  subvolumes = {
    +    "/root" = {
    +      mountpoint = "/";
    +      mountOptions = [
    +        "subvol=root"
    +        "compress=zstd"
    +        "noatime"
    +      ];
    +    };
    +    "/home" = lib.mkIf config.swarselsystems.isImpermanence {
    +      mountpoint = "/home";
    +      mountOptions = [
    +        "subvol=home"
    +        "compress=zstd"
    +        "noatime"
    +      ];
    +    };
    +    "/persist" = lib.mkIf config.swarselsystems.isImpermanence {
    +      mountpoint = "/persist";
    +      mountOptions = [
    +        "subvol=persist"
    +        "compress=zstd"
    +        "noatime"
    +      ];
    +    };
    +    "/log" = lib.mkIf config.swarselsystems.isImpermanence {
    +      mountpoint = "/var/log";
    +      mountOptions = [
    +        "subvol=log"
    +        "compress=zstd"
    +        "noatime"
    +      ];
    +    };
    +    "/nix" = {
    +      mountpoint = "/nix";
    +      mountOptions = [
    +        "subvol=nix"
    +        "compress=zstd"
    +        "noatime"
    +      ];
    +    };
    +    "/swap" = lib.mkIf config.swarselsystems.isSwap {
    +      mountpoint = "/.swapvol";
    +      swap.swapfile.size = config.swarselsystems.swapSize;
    +    };
    +  };
    +in
    +{
    +  disko = {
    +    imageBuilder.extraDependencies = [ pkgs.kmod ];
    +    devices = {
    +      disk = {
    +        disk0 = {
    +          type = "disk";
    +          device = config.swarselsystems.rootDisk;
    +          content = {
    +            type = "gpt";
    +            partitions = {
    +              ESP = {
    +                priority = 1;
    +                name = "ESP";
    +                size = "512M";
    +                type = "EF00";
    +                content = {
    +                  type = "filesystem";
    +                  format = "vfat";
    +                  mountpoint = "/boot";
    +                  mountOptions = [ "defaults" ];
    +                };
    +              };
    +              root = lib.mkIf (!config.swarselsystems.isCrypted) {
    +                size = "100%";
    +                content = {
    +                  inherit type subvolumes extraArgs;
    +                  postCreateHook = lib.mkIf config.swarselsystems.isImpermanence ''
    +                    MNTPOINT=$(mktemp -d)
    +                    mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5
    +                    trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT
    +                    btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank
    +                  '';
    +                };
    +              };
    +              luks = lib.mkIf config.swarselsystems.isCrypted {
    +                size = "100%";
    +                content = {
    +                  type = "luks";
    +                  name = "cryptroot";
    +                  passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh
    +                  settings = {
    +                    allowDiscards = true;
    +                    # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36
    +                    crypttabExtraOpts = [
    +                      "fido2-device=auto"
    +                      "token-timeout=10"
    +                    ];
    +                  };
    +                  content = {
    +                    inherit type subvolumes extraArgs;
    +                    postCreateHook = lib.mkIf config.swarselsystems.isImpermanence ''
    +                      MNTPOINT=$(mktemp -d)
    +                      mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5
    +                      trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT
    +                      btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank
    +                    '';
    +                  };
    +                };
    +              };
    +            };
    +          };
    +        };
    +      };
    +    };
    +  };
    +
    +  fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true;
    +  fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true;
    +}
     
    @@ -5335,12 +6047,117 @@ in } +
    + + + +
    +
    3.1.4.3. Brick Road (kexec image)
    +
    +
    +
    { lib, pkgs, modulesPath, options, ... }:
    +{
    +  disabledModules = [
    +    # This module adds values to multiple lists (systemPackages, supportedFilesystems)
    +    # which are impossible/unpractical to remove, so we disable the entire module.
    +    "profiles/base.nix"
    +  ];
    +
    +  imports = [
    +    # reduce closure size by removing perl
    +    "${modulesPath}/profiles/perlless.nix"
    +    # FIXME: we still are left with nixos-generate-config due to nixos-install-tools
    +    { system.forbiddenDependenciesRegexes = lib.mkForce [ ]; }
    +  ];
    +
    +  config = {
    +    networking.hostName = "brickroad";
    +
    +    system = {
    +      # nixos-option is mainly useful for interactive installations
    +      tools.nixos-option.enable = false;
    +      # among others, this prevents carrying a stdenv with gcc in the image
    +      extraDependencies = lib.mkForce [ ];
    +    };
    +    # prevents shipping nixpkgs, unnecessary if system is evaluated externally
    +    nix.registry = lib.mkForce { };
    +
    +    # would pull in nano
    +    programs.nano.enable = false;
    +
    +    # prevents strace
    +    environment = {
    +      defaultPackages = lib.mkForce [
    +        pkgs.parted
    +        pkgs.gptfdisk
    +        pkgs.e2fsprogs
    +      ];
    +
    +      systemPackages = with pkgs; [
    +        cryptsetup.bin
    +      ];
    +
    +      # Don't install the /lib/ld-linux.so.2 stub. This saves one instance of nixpkgs.
    +      ldso32 = null;
    +    };
    +
    +    # included in systemd anyway
    +    systemd.sysusers.enable = true;
    +
    +    # normal users are not allowed with sys-users
    +    # see https://github.com/NixOS/nixpkgs/pull/328926
    +    users.users.nixos = {
    +      isSystemUser = true;
    +      isNormalUser = lib.mkForce false;
    +      shell = "/run/current-system/sw/bin/bash";
    +      group = "nixos";
    +    };
    +    users.groups.nixos = { };
    +
    +    security = {
    +      # we have still run0 from systemd and most of the time we just use root
    +      sudo.enable = false;
    +      polkit.enable = lib.mkForce false;
    +      # introduces x11 dependencies
    +      pam.services.su.forwardXAuth = lib.mkForce false;
    +    };
    +
    +    documentation = {
    +      enable = false;
    +      man.enable = false;
    +      nixos.enable = false;
    +      info.enable = false;
    +      doc.enable = false;
    +    };
    +
    +    services = {
    +      # no dependency on x11
    +      dbus.implementation = "broker";
    +      # we prefer root as this is also what we use in nixos-anywhere
    +      getty.autologinUser = lib.mkForce "root";
    +      # included in systemd anyway
    +      userborn.enable = false;
    +    };
    +
    +
    +
    +    # we are missing this from base.nix
    +    boot.supportedFilesystems = [
    +      "ext4"
    +      "btrfs"
    +      "xfs"
    +    ];
    +  } // lib.optionalAttrs (options.hardware ? firmwareCompression) {
    +    hardware.firmwareCompression = "xz";
    +  };
    +}
    +
     
    -
    3.1.4.3. Hotel (Demo Physical/VM)
    +
    3.1.4.4. Hotel (Demo Physical/VM)

    This is just a demo host. It applies all the configuration found in the common parts of the flake, but disables all secrets-related features (as they would not work without the proper SSH keys). @@ -5351,7 +6168,7 @@ I also set the WLR_RENDERER_ALLOW_SOFTWARE=1 to allow this configur

    -
    3.1.4.3.1. Main configuration
    +
    3.1.4.4.1. Main configuration
    { self, config, pkgs, lib, minimal, ... }:
    @@ -5421,7 +6238,7 @@ in
     
    -
    3.1.4.3.2. disko
    +
    3.1.4.4.2. disko
    # NOTE: ... is needed because dikso passes diskoFile
    @@ -5557,7 +6374,7 @@ in
     
    -
    3.1.4.3.3. NixOS dummy options configuration
    +
    3.1.4.4.3. NixOS dummy options configuration
    _:
    @@ -5568,7 +6385,7 @@ in
     
    -
    3.1.4.3.4. home-manager dummy options configuration
    +
    3.1.4.4.4. home-manager dummy options configuration
    _:
    @@ -5821,13 +6638,31 @@ in
     
               services = mkOption {
                 type = types.attrsOf (
    -              types.submodule {
    +              types.submodule (serviceSubmod: {
                     options = {
                       domain = mkOption {
                         type = types.str;
                       };
    +                  subDomain = mkOption {
    +                    readOnly = true;
    +                    type = types.str;
    +                    default = lib.swarselsystems.getSubDomain serviceSubmod.config.domain;
    +                  };
    +                  baseDomain = mkOption {
    +                    readOnly = true;
    +                    type = types.str;
    +                    default = lib.swarselsystems.getBaseDomain serviceSubmod.config.domain;
    +                  };
    +                  proxyAddress4 = mkOption {
    +                    type = types.nullOr types.str;
    +                    default = null;
    +                  };
    +                  proxyAddress6 = mkOption {
    +                    type = types.nullOr types.str;
    +                    default = null;
    +                  };
                     };
    -              }
    +              })
                 );
               };
     
    @@ -5870,6 +6705,12 @@ in
                       defaultGateway6 = mkOption {
                         type = types.nullOr types.net.ipv6;
                       };
    +                  wanAddress4 = mkOption {
    +                    type = types.nullOr types.net.ipv4;
    +                  };
    +                  wanAddress6 = mkOption {
    +                    type = types.nullOr types.net.ipv6;
    +                  };
                     };
                   }
                 );
    @@ -5913,6 +6754,10 @@ in
             description = "Node Name.";
             type = lib.types.str;
           };
    +      lockFromBootstrapping = lib.mkOption {
    +        description = "Whether this host should be marked to not be bootstrapped again using swarsel-bootstrap.";
    +        type = lib.types.bool;
    +      };
         };
       };
     }
    @@ -6038,6 +6883,7 @@ A breakdown of the flags being set:
     
    { self, lib, pkgs, config, outputs, inputs, minimal, ... }:
     let
    +  inherit (config.swarselsystems) mainUser;
       settings = if minimal then { } else {
         environment.etc."nixos/configuration.nix".source = pkgs.writeText "configuration.nix" ''
           assert builtins.trace "This location is not used. The config is found in ${config.swarselsystems.flakePath}!" false;
    @@ -6074,7 +6920,8 @@ let
             channel.enable = false;
             registry = rec {
               nixpkgs.flake = inputs.nixpkgs;
    -          swarsel.flake = inputs.swarsel;
    +          # swarsel.flake = inputs.swarsel;
    +          swarsel.flake = self;
               n = nixpkgs;
               s = swarsel;
             };
    @@ -6095,7 +6942,7 @@ in
         (lib.recursiveUpdate
           {
             sops.secrets.github-api-token = lib.mkIf (!minimal) {
    -          sopsFile = "${config.swarselsystems.flakePath}/secrets/general/secrets.yaml";
    +          owner = mainUser;
             };
     
             nix =
    @@ -6192,7 +7039,6 @@ We enable the use of home-manager as a NixoS module. A nice trick h
             inputs.nix-index-database.homeModules.nix-index
             inputs.sops-nix.homeManagerModules.sops
             inputs.spicetify-nix.homeManagerModules.default
    -        # inputs.swarsel-modules.homeModules.default
             inputs.swarsel-nix.homeModules.default
             {
               imports = [
    @@ -6235,14 +7081,11 @@ For that reason, make sure that sops-nix is properly working before
     

    -
    { self, pkgs, config, lib, globals, minimal, ... }:
    -let
    -  sopsFile = self + /secrets/general/secrets.yaml;
    -in
    +
    { pkgs, config, lib, globals, minimal, ... }:
     {
       options.swarselmodules.users = lib.mkEnableOption "user config";
       config = lib.mkIf config.swarselmodules.users {
    -    sops.secrets.main-user-hashed-pw = lib.mkIf (!config.swarselsystems.isPublic) { inherit sopsFile; neededForUsers = true; };
    +    sops.secrets.main-user-hashed-pw = lib.mkIf (!config.swarselsystems.isPublic) { neededForUsers = true; };
     
         users = {
           mutableUsers = lib.mkIf (!minimal) false;
    @@ -6566,6 +7409,7 @@ in
           hideMounts = true;
           directories =
             [
    +          "/root/.dotfiles"
               "/etc/nix"
               "/etc/NetworkManager/system-connections"
               "/var/lib/nixos"
    @@ -6658,8 +7502,9 @@ Mostly used to install some compilers and lsp's that I want to have available wh
     
           libsForQt5.qt5.qtwayland
     
    -      # nix package database
    -      nix-index
    +      # do not do this! clashes with the flake
    +      # nix-index
    +
           nixos-generators
     
           # commit hooks
    @@ -6675,6 +7520,9 @@ Mostly used to install some compilers and lsp's that I want to have available wh
           # better make for general tasks
           just
     
    +      # sops
    +      ssh-to-age
    +      sops
     
           # keyboards
           qmk
    @@ -7273,9 +8121,8 @@ I use sops-nix to handle secrets that I want to have available on my machines at
         sops = {
     
           # age.sshKeyPaths = lib.swarselsystems.mkIfElseList config.swarselsystems.isBtrfs [ "/persist/.ssh/sops" "/persist/.ssh/ssh_host_ed25519_key" ] [ "${config.swarselsystems.homeDir}/.ssh/sops" "/etc/ssh/sops" "/etc/ssh/ssh_host_ed25519_key" ];
    -      age.sshKeyPaths = [ "${config.swarselsystems.homeDir}/.ssh/sops" "/etc/ssh/sops" "/etc/ssh/ssh_host_ed25519_key" ];
    -      # defaultSopsFile = lib.swarselsystems.mkIfElseList config.swarselsystems.isBtrfs "/persist/.dotfiles/secrets/general/secrets.yaml" "${config.swarselsystems.flakePath}/secrets/general/secrets.yaml";
    -      defaultSopsFile = "${config.swarselsystems.flakePath}/secrets/general/secrets.yaml";
    +      age.sshKeyPaths = [ "${config.swarselsystems.homeDir}/.ssh/sops" "/etc/ssh/sops" "${if config.swarselsystems.isImpermanence then "/persist" else ""}/etc/ssh/ssh_host_ed25519_key" ];
    +      defaultSopsFile = "${if config.swarselsystems.isImpermanence then "/persist" else ""}${config.swarselsystems.flakePath}/secrets/general/secrets.yaml";
     
           validateSopsFiles = false;
     
    @@ -8394,7 +9241,6 @@ in
       config = lib.mkIf config.swarselmodules.server.packages {
         environment.systemPackages = with pkgs; [
           gnupg
    -      nix-index
           nvd
           nix-output-monitor
           ssh-to-age
    @@ -8565,6 +9411,7 @@ in
         networking.firewall.allowedTCPPorts = [ 80 443 ];
     
         environment.persistence."/persist" = lib.mkIf config.swarselsystems.isImpermanence {
    +      directories = [ { directory = "/var/lib/acme"; } ];
           files = [ dhParamsPathBase ];
         };
     
    @@ -8589,28 +9436,52 @@ in
             '';
           };
         };
    -    system.activationScripts."createPersistentStorageDirs" = lib.mkIf config.swarselsystems.isImpermanence {
    -      deps = [ "generateDHParams" "users" "groups" ];
    -    };
    -    system.activationScripts."generateDHParams" =
    -      {
    -        text = ''
    -          set -eu
    -
    -          ${pkgs.coreutils}/bin/install -d -m 0755 ${sslBasePath}
    -          ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0755 /persist${sslBasePath}" else ""}
    -
    -          if [ ! -f "${dhParamsPathBase}" ]; then
    -            ${pkgs.openssl}/bin/openssl dhparam -out ${dhParamsPath} 4096
    -            chmod 0644 ${dhParamsPath}
    -            chown ${serviceUser}:${serviceGroup} ${dhParamsPath}
    -          fi
    -        '';
    -        deps = [
    -          "etc"
    -          (lib.mkIf config.swarselsystems.isImpermanence "specialfs")
    -        ];
    +    systemd.services.generateDHParams = {
    +      before = [ "nginx.service" ];
    +      requiredBy = [ "nginx.service" ];
    +      after = [ "local-fs.target" ];
    +      requires = [ "local-fs.target" ];
    +      serviceConfig = {
    +        Type = "oneshot";
           };
    +
    +      script = ''
    +        set -eu
    +
    +        install -d -m 0755 ${sslBasePath}
    +        ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0755 /persist${sslBasePath}" else ""}
    +
    +        if [ ! -f "${dhParamsPath}" ]; then
    +          ${pkgs.openssl}/bin/openssl dhparam -out "${dhParamsPath}" 4096
    +          chmod 0644 "${dhParamsPath}"
    +          chown ${serviceUser}:${serviceGroup} "${dhParamsPath}"
    +        else
    +          echo 'Already generated DHParams'
    +        fi
    +      '';
    +    };
    +
    +    # system.activationScripts."createPersistentStorageDirs" = lib.mkIf config.swarselsystems.isImpermanence {
    +    #   deps = [ "generateDHParams" "users" "groups" ];
    +    # };
    +    # system.activationScripts."generateDHParams" =
    +    #   {
    +    #     text = ''
    +    #       set -eu
    +
    +    #       ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0755 /persist${sslBasePath}" else "${pkgs.coreutils}/bin/install -d -m 0755 ${sslBasePath}"}
    +
    +    #       if [ ! -f "${dhParamsPath}" ]; then
    +    #         ${pkgs.openssl}/bin/openssl dhparam -out ${dhParamsPath} 4096
    +    #         chmod 0644 ${dhParamsPath}
    +    #         chown ${serviceUser}:${serviceGroup} ${dhParamsPath}
    +    #       fi
    +    #     '';
    +    #     deps = [
    +    #       (lib.mkIf config.swarselsystems.isImpermanence "specialfs")
    +    #       (lib.mkIf (!config.swarselsystems.isImpermanence) "etc")
    +    #     ];
    +    #   };
       };
     }
     
    @@ -8661,22 +9532,35 @@ Here I am forcing startWhenNeeded to false so that the value will n
    -
    -
    3.2.3.7. Network settings
    +
    +
    3.2.3.7. Network settings
    +

    +Generate hostId using head -c4 /dev/urandom | od -A none -t x4 +

    +
    { lib, config, ... }:
    +let
    +  inherit (config.swarselsystems.server) localNetwork;
    +in
     {
       options.swarselmodules.server.network = lib.mkEnableOption "enable server network config";
    +  options.swarselsystems.server.localNetwork = lib.mkOption {
    +    type = lib.types.str;
    +    default = "home";
    +  };
       config = lib.mkIf config.swarselmodules.server.network {
     
    -    globals.networks.home.hosts.${config.node.name} = {
    -      inherit (config.repo.secrets.local.networking.networks.home) id;
    -      mac = config.repo.secrets.local.networking.networks.home.mac or null;
    +    globals.networks."${if config.swarselsystems.isCloud then config.node.name else "home"}-${localNetwork}".hosts.${config.node.name} = {
    +      inherit (config.repo.secrets.local.networking.networks.${localNetwork}) id;
    +      mac = config.repo.secrets.local.networking.networks.${localNetwork}.mac or null;
         };
     
         globals.hosts.${config.node.name} = {
           inherit (config.repo.secrets.local.networking) defaultGateway4;
    +      wanAddress4 = config.repo.secrets.local.networking.wanAddress4 or null;
    +      wanAddress6 = config.repo.secrets.local.networking.wanAddress6 or null;
         };
     
         networking = {
    @@ -8695,8 +9579,8 @@ Here I am forcing startWhenNeeded to false so that the value will n
     
    -
    -
    3.2.3.8. Disk encryption
    +
    +
    3.2.3.8. Disk encryption

    The hostkey can be generated with ssh-keygen -t ed25519 -N "" -f /etc/secrets/initrd/ssh_host_ed25519_key. @@ -8884,11 +9768,16 @@ From the last bracket you then find out the correct kernel module:

    { self, pkgs, lib, config, globals, minimal, ... }:
     let
    -  localIp = globals.networks.home.hosts.${config.node.name}.ipv4;
    -  subnetMask = globals.networks.home.subnetMask4;
    +  localIp = globals.networks."${if config.swarselsystems.isCloud then config.node.name else "home"}-${config.swarselsystems.server.localNetwork}".hosts.${config.node.name}.ipv4;
    +  subnetMask = globals.networks."${if config.swarselsystems.isCloud then config.node.name else "home"}-${config.swarselsystems.server.localNetwork}".subnetMask4;
       gatewayIp = globals.hosts.${config.node.name}.defaultGateway4;
     
    -  hostKeyPath = "/etc/secrets/initrd/ssh_host_ed25519_key";
    +  hostKeyPathBase = "/etc/secrets/initrd/ssh_host_ed25519_key";
    +  hostKeyPath =
    +    if config.swarselsystems.isImpermanence then
    +      "/persist/${hostKeyPathBase}"
    +    else
    +      "${hostKeyPathBase}";
     in
     {
       options.swarselmodules.server.diskEncryption = lib.mkEnableOption "enable disk encryption config";
    @@ -8898,35 +9787,40 @@ in
       };
       config = lib.mkIf (config.swarselmodules.server.diskEncryption && config.swarselsystems.isCrypted) {
     
    +
    +    system.activationScripts."createPersistentStorageDirs" = lib.mkIf config.swarselsystems.isImpermanence {
    +      deps = [ "ensureInitrdHostkey" ];
    +    };
         system.activationScripts.ensureInitrdHostkey = lib.mkIf (config.swarselprofiles.server || minimal) {
           text = ''
             [[ -e ${hostKeyPath} ]] || ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -N "" -f ${hostKeyPath}
           '';
    -      deps = [ "users" ];
    +      deps = [
    +        "etc"
    +      ];
         };
     
         environment.persistence."/persist" = lib.mkIf (config.swarselsystems.isImpermanence && (config.swarselprofiles.server || minimal)) {
    -      files = [ hostKeyPath ];
    +      files = [ hostKeyPathBase ];
         };
     
    -    boot = lib.mkIf (config.swarselprofiles.server || minimal) {
    -      kernelParams = lib.mkIf (!config.swarselsystems.isLaptop) [
    +    boot = lib.mkIf (!config.swarselsystems.isLaptop) {
    +      kernelParams = lib.mkIf (!config.swarselsystems.isCloud) [
             "ip=${localIp}::${gatewayIp}:${subnetMask}:${config.networking.hostName}::none"
           ];
           initrd = {
             availableKernelModules = config.swarselsystems.networkKernelModules;
             network = {
               enable = true;
    -          udhcpc.enable = lib.mkIf config.swarselsystems.isLaptop true;
               flushBeforeStage2 = true;
               ssh = {
                 enable = true;
                 port = 2222; # avoid hostkey changed nag
    -            authorizedKeyFiles = [
    -              (self + /secrets/keys/ssh/yubikey.pub)
    -              (self + /secrets/keys/ssh/magicant.pub)
    +            authorizedKeys = [
    +              ''command="/bin/systemctl default" ${builtins.readFile "${self}/secrets/keys/ssh/yubikey.pub"}''
    +              ''command="/bin/systemctl default" ${builtins.readFile "${self}/secrets/keys/ssh/magicant.pub"}''
                 ];
    -            hostKeys = [ hostKeyPath ];
    +            hostKeys = [ hostKeyPathBase ];
               };
               # postCommands = ''
               #   echo 'cryptsetup-askpass || echo "Unlock was successful; exiting SSH session" && exit 1' >> /root/.profile
    @@ -8936,23 +9830,24 @@ in
               initrdBin = with pkgs; [
                 cryptsetup
               ];
    -          services = {
    -            unlock-luks = {
    -              wantedBy = [ "initrd.target" ];
    -              after = [ "network.target" ];
    -              before = [ "systemd-cryptsetup@cryptroot.service" ];
    -              path = [ "/bin" ];
    +          # NOTE: the below does put the text into /root/.profile, but the command will not be run
    +          # services = {
    +          #   unlock-luks = {
    +          #     wantedBy = [ "initrd.target" ];
    +          #     after = [ "network.target" ];
    +          #     before = [ "systemd-cryptsetup@cryptroot.service" ];
    +          #     path = [ "/bin" ];
     
    -              serviceConfig = {
    -                Type = "oneshot";
    -                RemainAfterExit = true;
    -              };
    +          #     serviceConfig = {
    +          #       Type = "oneshot";
    +          #       RemainAfterExit = true;
    +          #     };
     
    -              script = ''
    -                echo "systemctl default" >> /root/.profile
    -              '';
    -            };
    -          };
    +          #     script = ''
    +          #       echo "systemctl default" >> /root/.profile
    +          #     '';
    +          #   };
    +          # };
             };
           };
         };
    @@ -8963,8 +9858,8 @@ in
     
    -
    -
    3.2.3.9. Router
    +
    +
    3.2.3.9. Router
    { lib, config, ... }:
    @@ -9031,15 +9926,11 @@ in
     
    3.2.3.10. kavita
    -
    { self, lib, config, pkgs, globals, ... }:
    +
    { self, lib, config, pkgs, globals, dns, confLib, ... }:
     let
       inherit (config.swarselsystems) sopsFile;
     
    -  servicePort = 8080;
    -  serviceName = "kavita";
    -  serviceUser = "kavita";
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    +  inherit (confLib.gen { name = "kavita"; port = 8080; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     in
     {
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
    @@ -9048,6 +9939,10 @@ in
           calibre
         ];
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         users.users.${serviceUser} = {
           extraGroups = [ "users" ];
         };
    @@ -9061,7 +9956,11 @@ in
           info = "https://${serviceDomain}";
           icon = "${self}/files/topology-images/${serviceName}.png";
         };
    -    globals.services.${serviceName}.domain = serviceDomain;
    +
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services.${serviceName} = {
           enable = true;
    @@ -9071,7 +9970,7 @@ in
           dataDir = "/Vault/data/${serviceName}";
         };
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -9105,23 +10004,26 @@ in
     
    3.2.3.11. jellyfin
    -
    { pkgs, lib, config, globals, ... }:
    +
    { pkgs, lib, config, globals, dns, confLib, ... }:
     let
    -  servicePort = 8096;
    -  serviceName = "jellyfin";
    -  serviceUser = "jellyfin";
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    +  inherit (confLib.gen { name = "jellyfin"; port = 8096; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     in
     {
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
    +
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         users.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; [
    @@ -9133,7 +10035,11 @@ in
         };
     
         topology.self.services.${serviceName}.info = "https://${serviceDomain}";
    -    globals.services.${serviceName}.domain = serviceDomain;
    +
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services.${serviceName} = {
           enable = true;
    @@ -9141,7 +10047,7 @@ in
           openFirewall = true; # this works only for the default ports
         };
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -9176,18 +10082,18 @@ in
     
    3.2.3.12. navidrome
    -
    { pkgs, config, lib, globals, ... }:
    +
    { pkgs, config, lib, globals, dns, confLib, ... }:
     let
    -  servicePort = 4040;
    -  serviceName = "navidrome";
    -  serviceUser = "navidrome";
    -  serviceGroup = serviceUser;
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    +  inherit (confLib.gen { name = "navidrome"; port = 4040; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     in
     {
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
    +
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         environment.systemPackages = with pkgs; [
           pciutils
           alsa-utils
    @@ -9217,7 +10123,10 @@ in
     
         networking.firewall.allowedTCPPorts = [ servicePort ];
     
    -    globals.services.${serviceName}.domain = serviceDomain;
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services.snapserver = {
           enable = true;
    @@ -9281,7 +10190,7 @@ in
           };
         };
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -9343,12 +10252,9 @@ in
     
    3.2.3.13. spotifyd
    -
    { lib, config, ... }:
    +
    { lib, config, confLib, ... }:
     let
    -  servicePort = 1025;
    -  serviceName = "spotifyd";
    -  serviceUser = "spotifyd";
    -  serviceGroup = serviceUser;
    +  inherit (confLib.gen { name = "spotifyd"; port = 1025; }) servicePort serviceName serviceUser serviceGroup;
     in
     {
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
    @@ -9402,14 +10308,10 @@ in
     
    3.2.3.14. mpd
    -
    { self, lib, config, pkgs, ... }:
    +
    { self, lib, config, pkgs, confLib, ... }:
     let
       inherit (config.swarselsystems) sopsFile;
    -
    -  servicePort = 3254;
    -  serviceUser = "mpd";
    -  serviceGroup = serviceUser;
    -  serviceName = "mpd";
    +  inherit (confLib.gen { name = "mpd"; port = 3254; }) servicePort serviceName serviceUser serviceGroup;
     in
     {
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
    @@ -9504,9 +10406,9 @@ in
     
    3.2.3.16. postgresql
    -
    { config, lib, pkgs, ... }:
    +
    { config, lib, pkgs, confLib, ... }:
     let
    -  serviceName = "postgresql";
    +  inherit (confLib.gen { name = "postgresql"; port = 3254; }) serviceName;
       postgresVersion = 14;
     in
     {
    @@ -9529,15 +10431,10 @@ in
     
    3.2.3.17. matrix
    -
    { lib, config, pkgs, globals, ... }:
    +
    { lib, config, pkgs, globals, dns, confLib, ... }:
     let
       inherit (config.swarselsystems) sopsFile;
    -
    -  servicePort = 8008;
    -  serviceName = "matrix";
    -  serviceDomain = config.repo.secrets.common.services.domains.matrix;
    -  serviceUser = "matrix-synapse";
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    +  inherit (confLib.gen { name = "matrix"; user = "matrix-synapse"; port = 8008; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     
       federationPort = 8448;
       whatsappPort = 29318;
    @@ -9555,6 +10452,11 @@ in
     {
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
    +
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         environment.systemPackages = with pkgs; [
           matrix-synapse
           lottieconverter
    @@ -9622,7 +10524,10 @@ in
           };
         };
     
    -    globals.services.${serviceName}.domain = serviceDomain;
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services = {
           postgresql = {
    @@ -9821,7 +10726,7 @@ in
         # messages out after a while.
     
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -9885,17 +10790,11 @@ in
     
    3.2.3.18. nextcloud
    -
    { pkgs, lib, config, globals, ... }:
    +
    { pkgs, lib, config, globals, dns, confLib, ... }:
     let
       inherit (config.repo.secrets.local.nextcloud) adminuser;
       inherit (config.swarselsystems) sopsFile;
    -
    -  servicePort = 80;
    -  serviceUser = "nextcloud";
    -  serviceGroup = serviceUser;
    -  serviceName = "nextcloud";
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    +  inherit (confLib.gen { name = "nextcloud"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     
       nextcloudVersion = "32";
     in
    @@ -9903,13 +10802,19 @@ in
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         sops.secrets = {
           nextcloud-admin-pw = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
           kanidm-nextcloud-client = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
         };
     
    -
    -    globals.services.${serviceName}.domain = serviceDomain;
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services = {
           ${serviceName} = {
    @@ -9937,7 +10842,7 @@ in
           };
         };
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -9971,24 +10876,28 @@ in
     
    3.2.3.19. immich
    -
    { lib, pkgs, config, globals, ... }:
    +
    { lib, pkgs, config, globals, dns, confLib, ... }:
     let
    -  servicePort = 3001;
    -  serviceUser = "immich";
    -  serviceName = "immich";
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    +  inherit (confLib.gen { name = "immich"; port = 3001; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     in
     {
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         users.users.${serviceUser} = {
           extraGroups = [ "video" "render" "users" ];
         };
     
         topology.self.services.${serviceName}.info = "https://${serviceDomain}";
    -    globals.services.${serviceName}.domain = serviceDomain;
    +
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services.${serviceName} = {
           enable = true;
    @@ -10002,9 +10911,9 @@ in
           };
         };
     
    -    networking.firewall.allowedTCPPorts = [ 3001 ];
    +    networking.firewall.allowedTCPPorts = [ servicePort ];
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -10057,16 +10966,10 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of 
     

    -
    { lib, pkgs, config, globals, ... }:
    +
    { lib, pkgs, config, dns, globals, confLib, ... }:
     let
       inherit (config.swarselsystems) sopsFile;
    -
    -  servicePort = 28981;
    -  serviceUser = "paperless";
    -  serviceGroup = serviceUser;
    -  serviceName = "paperless";
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    +  inherit (confLib.gen { name = "paperless"; port = 28981; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     
       tikaPort = 9998;
       gotenbergPort = 3002;
    @@ -10076,6 +10979,10 @@ in
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         users.users.${serviceUser} = {
           extraGroups = [ "users" ];
         };
    @@ -10087,7 +10994,10 @@ in
     
         networking.firewall.allowedTCPPorts = [ servicePort ];
     
    -    globals.services.${serviceName}.domain = serviceDomain;
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services = {
           ${serviceName} = {
    @@ -10157,7 +11067,7 @@ in
                          )
         '';
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -10196,10 +11106,9 @@ in
     
    3.2.3.21. transmission
    -
    { self, pkgs, lib, config, ... }:
    +
    { self, pkgs, lib, config, confLib, ... }:
     let
    -  serviceName = "transmission";
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    +  inherit (confLib.gen { name = "transmission"; }) serviceName serviceDomain;
     
       lidarrUser = "lidarr";
       lidarrGroup = lidarrUser;
    @@ -10385,17 +11294,12 @@ in
     
    3.2.3.22. syncthing
    -
    { lib, config, configName, globals, ... }:
    +
    { lib, config, globals, dns, confLib, ... }:
     let
       inherit (config.swarselsystems.syncthing) serviceDomain;
    -  inherit (config.swarselsystems.syncthing) serviceIP;
    +  inherit (confLib.gen { name = "syncthing"; port = 8384; }) servicePort serviceName serviceUser serviceGroup serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     
    -  servicePort = 8384;
    -  serviceUser = "syncthing";
    -  serviceGroup = serviceUser;
    -  serviceName = "syncthing";
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    -  specificServiceName = "syncthing-${configName}";
    +  specificServiceName = "${serviceName}-${config.node.name}";
     
       cfg = config.services.${serviceName};
       devices = config.swarselsystems.syncthing.syncDevices;
    @@ -10409,10 +11313,6 @@ in
             type = lib.types.str;
             default = config.repo.secrets.common.services.domains.syncthing1;
           };
    -      serviceIP = lib.mkOption {
    -        type = lib.types.str;
    -        default = "${serviceAddress}";
    -      };
           syncDevices = lib.mkOption {
             type = lib.types.listOf lib.types.str;
             default = [ "magicant" "winters" "pyramid" "moonside@oracle" ];
    @@ -10438,6 +11338,10 @@ in
       };
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${specificServiceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${specificServiceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         users.users.${serviceUser} = {
           extraGroups = [ "users" ];
           group = serviceGroup;
    @@ -10448,7 +11352,10 @@ in
     
         networking.firewall.allowedTCPPorts = [ servicePort ];
     
    -    globals.services."${specificServiceName}".domain = serviceDomain;
    +    globals.services.${specificServiceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services.${serviceName} = rec {
           enable = true;
    @@ -10504,11 +11411,11 @@ in
           };
         };
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${specificServiceName} = {
               servers = {
    -            "${serviceIP}:${builtins.toString servicePort}" = { };
    +            "${serviceAddress}:${builtins.toString servicePort}" = { };
               };
             };
           };
    @@ -10617,14 +11524,9 @@ This section exposes several metrics that I use to check the health of my server
     

    -
    { self, lib, config, globals, ... }:
    +
    { self, lib, config, globals, dns, confLib, ... }:
     let
    -  servicePort = 3000;
    -  serviceUser = "grafana";
    -  serviceGroup = serviceUser;
    -  serviceName = "grafana";
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    +  inherit (confLib.gen { name = "grafana"; port = 3000; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     
       prometheusPort = 9090;
       prometheusUser = "prometheus";
    @@ -10640,6 +11542,10 @@ in
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         sops = {
           secrets = {
             grafana-admin-pw = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
    @@ -10676,7 +11582,11 @@ in
         networking.firewall.allowedTCPPorts = [ servicePort prometheusPort ];
     
         topology.self.services.prometheus.info = "https://${serviceDomain}/${prometheusWebRoot}";
    -    globals.services.${serviceName}.domain = serviceDomain;
    +
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services = {
           ${serviceName} = {
    @@ -10825,7 +11735,7 @@ in
         };
     
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             "${grafanaUpstream}" = {
               servers = {
    @@ -10875,17 +11785,23 @@ This is a WIP Jenkins instance. It is used to automatically build a new system w
     

    -
    { pkgs, lib, config, globals, ... }:
    +
    { pkgs, lib, config, globals, dns, confLib, ... }:
     let
    -  servicePort = 8088;
    -  serviceName = "jenkins";
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    +  inherit (confLib.gen { name = "jenkins"; port = 8088; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     in
     {
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
    +
         services.jenkins = {
           enable = true;
           withCLI = true;
    @@ -10895,7 +11811,7 @@ in
           home = "/Vault/apps/${serviceName}";
         };
     
    -    services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -10934,10 +11850,9 @@ This was an approach of hosting an RSS server from within emacs. That would have
     

    -
    { lib, config, ... }:
    +
    { lib, config, confLib, ... }:
     let
    -  serviceName = "emacs";
    -  servicePort = 9812;
    +  inherit (confLib.gen { name = "emacs"; port = 9812; }) servicePort serviceName;
     in
     {
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} server on server";
    @@ -10978,14 +11893,9 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with
     

    -
    { self, lib, config, globals, ... }:
    +
    { self, lib, config, globals, dns, confLib, ... }:
     let
    -  servicePort = 80;
    -  serviceName = "freshrss";
    -  serviceUser = "freshrss";
    -  serviceGroup = serviceName;
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    +  inherit (confLib.gen { name = "freshrss"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     
       inherit (config.swarselsystems) sopsFile;
     in
    @@ -10993,6 +11903,10 @@ in
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         users.users.${serviceUser} = {
           extraGroups = [ "users" ];
           group = serviceGroup;
    @@ -11034,7 +11948,10 @@ in
           icon = "${self}/files/topology-images/${serviceName}.png";
         };
     
    -    globals.services.${serviceName}.domain = serviceDomain;
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services.${serviceName} =
           let
    @@ -11054,7 +11971,7 @@ in
         #   config.sops.templates.freshrss-env.path
         # ];
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -11092,16 +12009,10 @@ in
     
    3.2.3.28. forgejo (git server)
    -
    { lib, config, pkgs, globals, ... }:
    +
    { lib, config, pkgs, globals, dns, confLib, ... }:
     let
       inherit (config.swarselsystems) sopsFile;
    -
    -  servicePort = 3004;
    -  serviceUser = "forgejo";
    -  serviceGroup = serviceUser;
    -  serviceName = "forgejo";
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    +  inherit (confLib.gen { name = "forgejo"; port = 3004; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     
       kanidmDomain = globals.services.kanidm.domain;
     in
    @@ -11109,6 +12020,10 @@ in
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         networking.firewall.allowedTCPPorts = [ servicePort ];
     
         users.users.${serviceUser} = {
    @@ -11122,7 +12037,10 @@ in
           kanidm-forgejo-client = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
         };
     
    -    globals.services.${serviceName}.domain = serviceDomain;
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services.${serviceName} = {
           enable = true;
    @@ -11223,7 +12141,7 @@ in
             '';
         };
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -11258,14 +12176,10 @@ in
     
    3.2.3.29. Anki Sync Server
    -
    { self, lib, config, globals, ... }:
    +
    { self, lib, config, globals, dns, confLib, ... }:
     let
       inherit (config.swarselsystems) sopsFile;
    -
    -  servicePort = 27701;
    -  serviceName = "ankisync";
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    +  inherit (confLib.gen { name = "ankisync"; port = 27701; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     
       ankiUser = globals.user.name;
     in
    @@ -11273,6 +12187,10 @@ in
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         networking.firewall.allowedTCPPorts = [ servicePort ];
     
         sops.secrets.anki-pw = { inherit sopsFile; owner = "root"; };
    @@ -11283,7 +12201,10 @@ in
           info = "https://${serviceDomain}";
         };
     
    -    globals.services.${serviceName}.domain = serviceDomain;
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services.anki-sync-server = {
           enable = true;
    @@ -11298,7 +12219,7 @@ in
           ];
         };
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -11346,19 +12267,13 @@ To get other URLs (token, etc.), use 
    -
    { self, lib, pkgs, config, globals, ... }:
    +
    { self, lib, pkgs, config, globals, dns, confLib, ... }:
     let
       certsSopsFile = self + /secrets/certs/secrets.yaml;
       inherit (config.swarselsystems) sopsFile;
    +  inherit (confLib.gen { name = "kanidm"; port = 8300; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     
    -  servicePort = 8300;
    -  serviceUser = "kanidm";
    -  serviceGroup = serviceUser;
    -  serviceName = "kanidm";
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    -
    -  oauth2ProxyDomain = globals.services.oauth2Proxy.domain;
    +  oauth2ProxyDomain = globals.services.oauth2-proxy.domain;
       immichDomain = globals.services.immich.domain;
       paperlessDomain = globals.services.paperless.domain;
       forgejoDomain = globals.services.forgejo.domain;
    @@ -11385,6 +12300,10 @@ in
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         users.users.${serviceUser} = {
           group = serviceGroup;
           isSystemUser = true;
    @@ -11410,7 +12329,10 @@ in
     
         networking.firewall.allowedTCPPorts = [ servicePort ];
     
    -    globals.services.${serviceName}.domain = serviceDomain;
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         environment.persistence."/persist" = lib.mkIf config.swarselsystems.isImpermanence {
           files = [
    @@ -11418,17 +12340,22 @@ in
             keyPathBase
           ];
         };
    -
    -    system.activationScripts."createPersistentStorageDirs" = lib.mkIf config.swarselsystems.isImpermanence {
    -      deps = [ "generateSSLCert-${serviceName}" "users" "groups" ];
    -    };
    -    system.activationScripts."generateSSLCert-${serviceName}" =
    +    systemd.services."generateSSLCert-${serviceName}" =
           let
             daysValid = 3650;
             renewBeforeDays = 365;
           in
           {
    -        text = ''
    +        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}
    @@ -11437,16 +12364,18 @@ in
               ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0750 /persist${privateDir}" else ""}
     
               need_gen=0
    -          if [ ! -f "${certPathBase}" ] || [ ! -f "${keyPathBase}" ]; then
    +          if [ ! -f "${certPath}" ] || [ ! -f "${keyPath}" ]; then
                 need_gen=1
               else
    -            enddate="$(${pkgs.openssl}/bin/openssl x509 -noout -enddate -in "${certPathBase}" | cut -d= -f2)"
    +            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
     
    @@ -11462,12 +12391,58 @@ in
                 chown ${serviceUser}:${serviceGroup} "${certPath}" "${keyPath}"
               fi
             '';
    -        deps = [
    -          "etc"
    -          (lib.mkIf config.swarselsystems.isImpermanence "specialfs")
    -        ];
           };
     
    +
    +    # 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 ""}
    +
    +    #       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}"
    +
    +    #         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_7;
    @@ -11674,7 +12649,7 @@ in
           ${serviceName}.serviceConfig.RestartSec = "30";
         };
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -11708,13 +12683,9 @@ in
     
    3.2.3.31. oauth2-proxy
    -
    { lib, config, globals, ... }:
    +
    { lib, config, globals, dns, confLib, ... }:
     let
    -  servicePort = 3004;
    -  serviceUser = "oauth2-proxy";
    -  serviceGroup = serviceUser;
    -  serviceName = "oauth2-proxy";
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    +  inherit (confLib.gen { name = "oauth2-proxy"; port = 3004; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     
       kanidmDomain = globals.services.kanidm.domain;
       mainDomain = globals.domains.main;
    @@ -11833,6 +12804,10 @@ in
       };
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         sops = {
           secrets = {
             "oauth2-cookie-secret" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
    @@ -11854,7 +12829,10 @@ in
     
         networking.firewall.allowedTCPPorts = [ servicePort ];
     
    -    globals.services.oauth2Proxy.domain = serviceDomain;
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services = {
           ${serviceName} = {
    @@ -11905,11 +12883,11 @@ in
           };
         };
     
    -    services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    -            "localhost:${builtins.toString servicePort}" = { };
    +            "${serviceAddress}:${builtins.toString servicePort}" = { };
               };
             };
           };
    @@ -11940,14 +12918,9 @@ in
     
    3.2.3.32. Firefly-III
    -
    { self, lib, config, globals, ... }:
    +
    { self, lib, config, globals, dns, confLib, ... }:
     let
    -  servicePort = 80;
    -  serviceUser = "firefly-iii";
    -  serviceGroup = serviceUser;
    -  serviceName = "firefly-iii";
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    +  inherit (confLib.gen { name = "firefly-iii"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     
       nginxGroup = "nginx";
     
    @@ -11958,6 +12931,10 @@ in
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         users = {
           groups.${serviceGroup} = { };
           users.${serviceUser} = {
    @@ -11978,7 +12955,11 @@ in
           info = "https://${serviceDomain}";
           icon = "${self}/files/topology-images/${serviceName}.png";
         };
    -    globals.services.${serviceName}.domain = serviceDomain;
    +
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services = {
           ${serviceName} = {
    @@ -12020,7 +13001,7 @@ in
           };
         };
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -12060,15 +13041,10 @@ in
     
    3.2.3.33. Koillection
    -
    { self, lib, config, globals, ... }:
    +
    { self, lib, config, globals, dns, confLib, ... }:
     let
    -  serviceUser = "koillection";
    +  inherit (confLib.gen { name = "koillection"; port = 2282; dir = "/Vault/data/koillection"; }) servicePort serviceName serviceUser serviceDir serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
       serviceDB = "koillection";
    -  serviceName = "koillection";
    -  servicePort = 2282;
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceDir = "/Vault/data/koillection";
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
     
       postgresUser = config.systemd.services.postgresql.serviceConfig.User; # postgres
       postgresPort = config.services.postgresql.settings.port; # 5432
    @@ -12080,6 +13056,10 @@ in
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
         sops.secrets = {
           koillection-db-password = { inherit sopsFile; owner = postgresUser; group = postgresUser; mode = "0440"; };
           koillection-env-file = { inherit sopsFile; };
    @@ -12090,7 +13070,11 @@ in
           info = "https://${serviceDomain}";
           icon = "${self}/files/topology-images/${serviceName}.png";
         };
    -    globals.services.${serviceName}.domain = serviceDomain;
    +
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         virtualisation.oci-containers.containers = {
           koillection = {
    @@ -12166,7 +13150,7 @@ in
           };
         };
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -12202,19 +13186,24 @@ in
     
    3.2.3.34. Atuin
    -
    { lib, config, globals, ... }:
    +
    { lib, config, globals, dns, confLib, ... }:
     let
    -  servicePort = 8888;
    -  serviceName = "atuin";
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    +  inherit (confLib.gen { name = "atuin"; port = 8888; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     in
     {
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         topology.self.services.${serviceName}.info = "https://${serviceDomain}";
    -    globals.services.${serviceName}.domain = serviceDomain;
    +
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services.${serviceName} = {
           enable = true;
    @@ -12224,7 +13213,7 @@ in
           openRegistration = false;
         };
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -12260,23 +13249,21 @@ in
     
    3.2.3.35. Radicale
    -
    { self, lib, config, globals, ... }:
    +
    { self, lib, config, globals, dns, confLib, ... }:
     let
    +  inherit (confLib.gen { name = "radicale"; port = 8000; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
       sopsFile = self + /secrets/winters/secrets2.yaml;
     
    -  servicePort = 8000;
    -  serviceName = "radicale";
    -  serviceUser = "radicale";
    -  serviceGroup = serviceUser;
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    -
       cfg = config.services.${serviceName};
     in
     {
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         sops = {
           secrets.radicale-user = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
     
    @@ -12297,7 +13284,11 @@ in
         };
     
         topology.self.services.${serviceName}.info = "https://${serviceDomain}";
    -    globals.services.${serviceName}.domain = serviceDomain;
    +
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services.${serviceName} = {
           enable = true;
    @@ -12350,7 +13341,7 @@ in
     
         networking.firewall.allowedTCPPorts = [ servicePort ];
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -12387,8 +13378,9 @@ in
     
    3.2.3.36. croc
    -
    { self, lib, config, pkgs, ... }:
    +
    { self, lib, config, pkgs, dns, globals, confLib, ... }:
     let
    +  inherit (confLib.gen { name = "croc"; }) serviceName serviceDomain proxyAddress4 proxyAddress6;
       servicePorts = [
         9009
         9010
    @@ -12396,8 +13388,6 @@ let
         9012
         9013
       ];
    -  serviceName = "croc";
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
     
       inherit (config.swarselsystems) sopsFile;
     
    @@ -12407,6 +13397,10 @@ in
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         sops = {
           secrets = {
             croc-password = { inherit sopsFile; };
    @@ -12428,7 +13422,10 @@ in
           icon = "${self}/files/topology-images/${serviceName}.png";
         };
     
    -    globals.services.${serviceName}.domain = serviceDomain;
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services.${serviceName} = {
           enable = true;
    @@ -12463,13 +13460,9 @@ in
     
    3.2.3.37. microbin
    -
    { self, lib, config, ... }:
    +
    { self, lib, config, dns, globals, confLib, ... }:
     let
    -  servicePort = 8777;
    -  serviceName = "microbin";
    -  serviceUser = "microbin";
    -  serviceGroup = serviceUser;
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    +  inherit (confLib.gen { name = "microbin"; port = 8777; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     
       inherit (config.swarselsystems) sopsFile;
     
    @@ -12479,6 +13472,10 @@ in
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         users = {
           groups.${serviceGroup} = { };
     
    @@ -12514,7 +13511,11 @@ in
           info = "https://${serviceDomain}";
           icon = "${self}/files/topology-images/${serviceName}.png";
         };
    -    globals.services.${serviceName}.domain = serviceDomain;
    +
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services.${serviceName} = {
           enable = true;
    @@ -12566,11 +13567,11 @@ in
           { directory = cfg.dataDir; user = serviceUser; group = serviceGroup; mode = "0700"; }
         ];
     
    -    services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    -            "localhost:${builtins.toString servicePort}" = { };
    +            "${serviceAddress}:${builtins.toString servicePort}" = { };
               };
             };
           };
    @@ -12602,12 +13603,9 @@ in
     
    3.2.3.38. shlink
    -
    { self, lib, config, ... }:
    +
    { self, lib, config, dns, globals, confLib, ... }:
     let
    -  servicePort = 8081;
    -  serviceName = "shlink";
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceDir = "/var/lib/shlink";
    +  inherit (confLib.gen { name = "shlink"; port = 8081; dir = "/var/lib/shlink";}) servicePort serviceName serviceDomain serviceDir serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     
       containerRev = "sha256:1a697baca56ab8821783e0ce53eb4fb22e51bb66749ec50581adc0cb6d031d7a";
     
    @@ -12619,6 +13617,10 @@ in
       };
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         sops = {
           secrets = {
             shlink-api = { inherit sopsFile; };
    @@ -12684,13 +13686,17 @@ in
           info = "https://${serviceDomain}";
           icon = "${self}/files/topology-images/${serviceName}.png";
         };
    -    globals.services.${serviceName}.domain = serviceDomain;
     
    -    services.nginx = {
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
    +
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    -            "localhost:${builtins.toString servicePort}" = { };
    +            "${serviceAddress}:${builtins.toString servicePort}" = { };
               };
             };
           };
    @@ -12726,12 +13732,9 @@ Deployment notes:
     
     
     
    -
    { self, lib, config, ... }:
    +
    { self, lib, config, dns, globals, confLib, ... }:
     let
    -  servicePort = 3000;
    -  serviceName = "slink";
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceDir = "/var/lib/slink";
    +  inherit (confLib.gen { name = "slink"; port = 3000; dir = "/var/lib/slink";}) servicePort serviceName serviceDomain serviceDir serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     
       containerRev = "sha256:98b9442696f0a8cbc92f0447f54fa4bad227af5dcfd6680545fedab2ed28ddd9";
     in
    @@ -12741,6 +13744,10 @@ in
       };
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         virtualisation.oci-containers.containers.${serviceName} = {
           image = "anirdev/slink@${containerRev}";
           environment = {
    @@ -12785,13 +13792,17 @@ in
           info = "https://${serviceDomain}";
           icon = "${self}/files/topology-images/shlink.png";
         };
    -    globals.services.${serviceName}.domain = serviceDomain;
     
    -    services.nginx = {
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
    +
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    -            "localhost:${builtins.toString servicePort}" = { };
    +            "${serviceAddress}:${builtins.toString servicePort}" = { };
               };
             };
           };
    @@ -12825,25 +13836,23 @@ in
     
    3.2.3.40. Snipe-IT
    -
    { self, lib, config, globals, ... }:
    +
    { self, lib, config, globals, dns, confLib, ... }:
     let
    +  inherit (confLib.gen { name = "snipeit"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
       sopsFile = self + /secrets/winters/secrets2.yaml;
     
       serviceDB = "snipeit";
     
    -  servicePort = 80;
    -  serviceName = "snipeit";
    -  serviceUser = "snipeit";
    -  serviceGroup = serviceUser;
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    -
       mysqlPort = 3306;
     in
     {
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         sops = {
           secrets = {
             snipe-it-appkey = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
    @@ -12851,7 +13860,11 @@ in
         };
     
         topology.self.services.${serviceName}.info = "https://${serviceDomain}";
    -    globals.services.${serviceName}.domain = serviceDomain;
    +
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services.snipe-it = {
           enable = true;
    @@ -12870,7 +13883,7 @@ in
           };
         };
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -12904,19 +13917,24 @@ in
     
    3.2.3.41. Homebox
    -
    { lib, pkgs, config, globals, ... }:
    +
    { lib, pkgs, config, globals, dns, confLib, ... }:
     let
    -  servicePort = 7745;
    -  serviceName = "homebox";
    -  serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    +  inherit (confLib.gen { name = "homebox"; port = 7745; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     in
     {
       options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         topology.self.services.${serviceName}.info = "https://${serviceDomain}";
    -    globals.services.${serviceName}.domain = serviceDomain;
    +
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
     
         services.${serviceName} = {
           enable = true;
    @@ -12932,7 +13950,7 @@ in
     
         networking.firewall.allowedTCPPorts = [ servicePort ];
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -12962,15 +13980,13 @@ in
     
    -
    -
    3.2.3.42. OPKSSH
    +
    +
    3.2.3.42. OPKSSH
    -
    { lib, config, globals, ... }:
    +
    { lib, config, globals, confLib, ... }:
     let
    -  serviceName = "opkssh";
    -  serviceUser = "opksshuser";
    -  serviceGroup = serviceUser;
    +  inherit (confLib.gen { name = "opkssh"; user = "opksshuser"; group = "opksshuser"; }) serviceName serviceUser serviceGroup;
     
       kanidmDomain = globals.services.kanidm.domain;
     
    @@ -13008,8 +14024,8 @@ in
     
    -
    -
    3.2.3.43. Garage
    +
    +
    3.2.3.43. Garage

    Generate the admin token using openssl rand -base64 32. @@ -13017,14 +14033,11 @@ Generate the rpc token using openssl rand -hex 32.

    -
    { self, lib, pkgs, config, configName, globals, ... }:
    +
    { self, lib, pkgs, config, configName, globals, dns, confLib, ... }:
     let
    -  sopsFile = self + /secrets/${configName}/secrets2.yaml;
    +  inherit (confLib.gen { name = "garage"; port = 3900; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
     
    -  serviceName = "garage";
    -  servicePort = 3900;
    -  serviceDomain = config.repo.secrets.common.services.domains."${serviceName}-${configName}";
    -  serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
    +  sopsFile = self + /secrets/${configName}/secrets2.yaml;
     
       cfg = config.services.${serviceName};
       metadata_dir = "/var/lib/garage/meta";
    @@ -13041,6 +14054,10 @@ in
       };
       config = lib.mkIf config.swarselmodules.server.${serviceName} {
     
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
         sops = {
           secrets.garage-admin-token = { inherit sopsFile; };
           secrets.garage-rpc-secret = { inherit sopsFile; };
    @@ -13055,6 +14072,11 @@ in
           ];
         };
     
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
    +
         systemd.services.${serviceName}.serviceConfig = {
           DynamicUser = false;
           ProtectHome = lib.mkForce false;
    @@ -13093,7 +14115,7 @@ in
           };
         };
     
    -    nodes.moonside.services.nginx = {
    +    nodes.${serviceProxy}.services.nginx = {
           upstreams = {
             ${serviceName} = {
               servers = {
    @@ -13122,6 +14144,356 @@ in
     
    +
    +
    3.2.3.44. nsd (dns)
    +
    +
    +
    { inputs, lib, config, globals, dns, confLib, ... }:
    +let
    +  inherit (confLib.gen { name = "nsd"; port = 53; }) serviceName;
    +  # servicePort = 53;
    +  # serviceDomain = config.repo.secrets.common.services.domains."${serviceName}";
    +  # serviceAddress = globals.networks."${if config.swarselsystems.isCloud then config.node.name else "home"}-${config.swarselsystems.server.localNetwork}".hosts.${config.node.name}.ipv4;
    +
    +in
    +{
    +  options = {
    +    swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
    +    swarselsystems.server.dns = lib.mkOption {
    +      type = lib.types.attrsOf (
    +        lib.types.submodule {
    +          options = {
    +            subdomainRecords = lib.mkOption {
    +              type = lib.types.attrsOf inputs.dns.subzone;
    +              default = { };
    +            };
    +          };
    +        }
    +      );
    +    };
    +  };
    +  config = lib.mkIf config.swarselmodules.server.${serviceName} {
    +    services.nsd = {
    +      enable = true;
    +      zones = {
    +        "${globals.domains.main}" = {
    +          # provideXFR = [ ... ];
    +          # notify = [ ... ];
    +          data = dns.lib.toString "${globals.domains.main}" (import ./site1.nix { inherit config globals dns; });
    +        };
    +      };
    +    };
    +
    +  };
    +}
    +
    +
    +
    +
    +
    +
    3.2.3.45. nsd (dns) - site1
    +
    +
    +
    { config, globals, dns, ... }:
    +with dns.lib.combinators; {
    +  SOA = {
    +    nameServer = "soa";
    +    adminEmail = "admin@${globals.domains.main}";
    +    serial = 2025112101;
    +  };
    +
    +  useOrigin = false;
    +
    +  NS = [
    +    "soa.${globals.domains.name}."
    +    "ns1.he.net"
    +    "ns2.he.net"
    +    "ns3.he.net"
    +    "ns4.he.net"
    +    "ns5.he.net"
    +    "oxygen.ns.hetzner.com"
    +    "pola.ns.cloudflare.com"
    +  ];
    +
    +  A = [ "75.2.60.5" ];
    +
    +  SRV = [
    +    {
    +      service = "_matrix";
    +      proto = "_tcp";
    +      port = 443;
    +      target = "${globals.services.matrix.baseDomain}.${globals.domains.main}";
    +      priority = 10;
    +      wweight = 5;
    +    }
    +    {
    +      service = "_submissions";
    +      proto = "_tcp";
    +      port = 465;
    +      target = "${globals.services.mailserver.baseDomain}.${globals.domains.main}";
    +      priority = 5;
    +      weight = 0;
    +      ttl = 3600;
    +    }
    +    {
    +      service = "_submission";
    +      proto = "_tcp";
    +      port = 587;
    +      target = "${globals.services.mailserver.baseDomain}.${globals.domains.main}";
    +      priority = 5;
    +      weight = 0;
    +      ttl = 3600;
    +    }
    +    {
    +      service = "_imap";
    +      proto = "_tcp";
    +      port = 143;
    +      target = "${globals.services.mailserver.baseDomain}.${globals.domains.main}";
    +      priority = 5;
    +      weight = 0;
    +      ttl = 3600;
    +    }
    +    {
    +      service = "_imaps";
    +      proto = "_tcp";
    +      port = 993;
    +      target = "${globals.services.mailserver.baseDomain}.${globals.domains.main}";
    +      priority = 5;
    +      weight = 0;
    +      ttl = 3600;
    +    }
    +  ];
    +
    +  MX = [
    +    {
    +      preference = 10;
    +      exchange = "${globals.services.mailserver.baseDomain}.${globals.domains.main}";
    +    }
    +  ];
    +
    +  CNAME = [
    +    {
    +      cname = "www.${glovals.domains.main}";
    +    }
    +  ];
    +
    +  DKIM = [
    +    {
    +    selector = "mail";
    +      k = "rsa";
    +      p = config.repo.secrets.local.dns.mailserver.dkim-public;
    +      ttl = 10800;
    +    }
    +  ];
    +
    +  DMARC = [
    +    {
    +      p = "none";
    +      ttl = 10800;
    +    }
    +  ];
    +
    +  TXT = [
    +    (with spf; strict [ "a:${globals.services.mailserver.baseDomain}.${globals.domains.main}" ])
    +    "google-site-verification=${config.repo.secrets.local.dns.google-site-verification}"
    +  ];
    +
    +  DMARC = [
    +    {
    +    selector = "mail";
    +      k = "rsa";
    +      p = "none";
    +      ttl = 10800;
    +    }
    +  ];
    +
    +  subdomains = config.swarselsystems.server.dns.${globals.domain.main}.subdomainRecords // {
    +    "minecraft" = host "130.61.119.12" null;
    +  };
    +}
    +
    +
    +
    +
    +
    +
    3.2.3.46. Minecraft
    +
    +
    +
    { lib, config, globals, dns, confLib, ... }:
    +let
    +  inherit (confLib.gen { name = "minecraft"; port = 25565; dir = "/var/lib/minecraft"; }) serviceName servicePort serviceDir serviceDomain proxyAddress4 proxyAddress6;
    +in
    +{
    +  options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
    +  config = lib.mkIf config.swarselmodules.server.${serviceName} {
    +
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
    +    topology.self.services.${serviceName}.info = "https://${serviceDomain}";
    +
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
    +
    +    networking.firewall.allowedTCPPorts = [ servicePort ];
    +
    +    environment.persistence."/persist".directories = lib.mkIf config.swarselsystems.isImpermanence [
    +      { directory = serviceDir; mode = "0755"; }
    +    ];
    +
    +    systemd.services.minecraft-swarselcraft = {
    +      description = "Minecraft Server";
    +      wants = [ "network-online.target" ];
    +      after = [ "network-online.target" ];
    +
    +      serviceConfig = {
    +        User = "root";
    +        WorkingDirectory = "/var/lib/minecraft/swarselcraft";
    +
    +        ExecStart = "/usr/bin/java @user_jvm_args.txt @libraries/net/minecraftforge/forge/1.20.1-47.2.20/unix_args.txt nogui";
    +
    +        Restart = "always";
    +        RestartSec = 30;
    +        StandardInput = "null";
    +      };
    +
    +      wantedBy = [ "multi-user.target" ];
    +    };
    +
    +
    +  };
    +
    +}
    +
    +
    +
    +
    +
    +
    3.2.3.47. Mailserver
    +
    +
    +
    { 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 serviceDomain serviceProxy proxyAddress4 proxyAddress6;
    +  inherit (config.repo.secrets.local.mailserver) user1 alias1_1 alias1_2 alias1_3 alias1_4 user2 alias2_1 user3;
    +  baseDomain = globals.domains.main;
    +in
    +{
    +  options = {
    +    swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
    +  };
    +  config = lib.mkIf config.swarselmodules.server.${serviceName} {
    +
    +    swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
    +      "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
    +    };
    +
    +    globals.services.${serviceName} = {
    +      domain = serviceDomain;
    +      inherit proxyAddress4 proxyAddress6;
    +    };
    +
    +    sops.secrets = {
    +      user1-hashed-pw = { inherit sopsFile; owner = serviceUser; };
    +      user2-hashed-pw = { inherit sopsFile; owner = serviceUser; };
    +      user3-hashed-pw = { inherit sopsFile; owner = serviceUser; };
    +    };
    +
    +    environment.persistence."/persist".directories = lib.mkIf config.swarselsystems.isImpermanence [
    +      { directory = "/var/vmail"; user = serviceUser; group = serviceGroup; mode = "0770"; }
    +      { directory = "/var/sieve"; user = serviceUser; group = serviceGroup; mode = "0770"; }
    +      { directory = "/var/dkim"; user = "rspamd"; group = "rspamd"; mode = "0700"; }
    +      { directory = serviceDir; user = serviceUser; group = serviceGroup; mode = "0700"; }
    +      { directory = "/var/lib/postgresql"; user = "postgres"; group = "postgres"; mode = "0750"; }
    +      { directory = "/var/lib/rspamd"; user = "rspamd"; group = "rspamd"; mode = "0700"; }
    +      { directory = "/var/lib/roundcube"; user = "roundcube"; group = "roundcube"; mode = "0700"; }
    +      { directory = "/var/lib/redis-rspamd"; user = "redis-rspamd"; group = "redis-rspamd"; mode = "0700"; }
    +      { directory = "/var/lib/postfix"; user = "root"; group = "root"; mode = "0755"; }
    +      { directory = "/var/lib/knot-resolver"; user = "knot-resolver"; group = "knot-resolver"; mode = "0770"; }
    +    ];
    +
    +    mailserver = {
    +      enable = true;
    +      stateVersion = 3;
    +      fqdn = serviceDomain;
    +      domains = [ baseDomain ];
    +      indexDir = "${serviceDir}/indices";
    +      openFirewall = true;
    +      certificateScheme = "acme";
    +      dmarcReporting.enable = true;
    +
    +      loginAccounts = {
    +        "${user1}@${baseDomain}" = {
    +          hashedPasswordFile = config.sops.secrets.user1-hashed-pw.path;
    +          aliases = [
    +            "${alias1_1}@${baseDomain}"
    +            "${alias1_2}@${baseDomain}"
    +            "${alias1_3}@${baseDomain}"
    +            "${alias1_4}@${baseDomain}"
    +          ];
    +        };
    +        "${user2}@${baseDomain}" = {
    +          hashedPasswordFile = config.sops.secrets.user2-hashed-pw.path;
    +          aliases = [
    +            "${alias2_1}@${baseDomain}"
    +          ];
    +          sendOnly = true;
    +        };
    +        "${user3}@${baseDomain}" = {
    +          hashedPasswordFile = config.sops.secrets.user3-hashed-pw.path;
    +          aliases = [
    +            "@${baseDomain}"
    +          ];
    +          catchAll = [
    +            baseDomain
    +          ];
    +        };
    +      };
    +    };
    +
    +    services.roundcube = {
    +      enable = true;
    +      # this is the url of the vhost, not necessarily the same as the fqdn of
    +      # the mailserver
    +      hostName = serviceDomain;
    +      extraConfig = ''
    +        $config['imap_host'] = "ssl://${config.mailserver.fqdn}";
    +        $config['smtp_host'] = "ssl://${config.mailserver.fqdn}";
    +        $config['smtp_user'] = "%u";
    +        $config['smtp_pass'] = "%p";
    +      '';
    +      configureNginx = true;
    +    };
    +
    +    # the rest of the ports are managed by snm
    +    networking.firewall.allowedTCPPorts = [ 80 servicePort ];
    +
    +    nodes.${serviceProxy}.services.nginx = {
    +      virtualHosts = {
    +        "${serviceDomain}" = {
    +          enableACME = true;
    +          forceSSL = true;
    +          acmeRoot = null;
    +          locations = {
    +            "/".recommendedSecurityHeaders = false;
    +            "~ ^/(SQL|bin|config|logs|temp|vendor)/".recommendedSecurityHeaders = false;
    +            "~ ^/(CHANGELOG.md|INSTALL|LICENSE|README.md|SECURITY.md|UPGRADING|composer.json|composer.lock)".recommendedSecurityHeaders = false;
    +            "~* \\.php(/|$)".recommendedSecurityHeaders = false;
    +          };
    +        };
    +      };
    +    };
    +
    +  };
    +}
    +
    +
    +
    +

    3.2.4. Darwin

    @@ -13744,8 +15116,8 @@ in
    -
    -
    3.2.5.11. microvm-host
    +
    +
    3.2.5.11. microvm-host

    Some standard options that should be set for every microvm host. @@ -13772,8 +15144,8 @@ Some standard options that should be set for every microvm host.

    -
    -
    3.2.5.12. microvm-guest
    +
    +
    3.2.5.12. microvm-guest

    Some standard options that should be set vor every microvm guest. We set the default @@ -13818,8 +15190,8 @@ in

    -
    -

    3.3.1. Steps to setup/upgrade home-manager only

    +
    +

    3.3.1. Steps to setup/upgrade home-manager only

    Steps to get a home-manager only setup up and running: @@ -14154,7 +15526,6 @@ This holds packages that I can use as provided, or with small modifications (as nix-inspect nixpkgs-review manix - comma # shellscripts shfmt @@ -14364,8 +15735,8 @@ in options.swarselmodules.sops = lib.mkEnableOption "sops settings"; config = lib.optionalAttrs (inputs ? sops) { sops = { - age.sshKeyPaths = [ "${homeDir}/.ssh/sops" "${homeDir}/.ssh/ssh_host_ed25519_key" ]; - defaultSopsFile = "${homeDir}/.dotfiles/secrets/general/secrets.yaml"; + age.sshKeyPaths = [ "${homeDir}/.ssh/sops" "${if config.swarselsystems.isImpermanence then "/persist" else ""}${homeDir}/.ssh/ssh_host_ed25519_key" ]; + defaultSopsFile = "${if config.swarselsystems.isImpermanence then "/persist" else ""}${homeDir}/.dotfiles/secrets/general/secrets.yaml"; validateSopsFiles = false; }; @@ -14809,7 +16180,7 @@ This section is for programs that require no further configuration. zsh Integrat

    3.3.2.14. nix-index

    -nix-index provides a way to find out which packages are provided by which derivations. By default it also comes with a replacement for command-not-found.sh, however, the implementation is based on a channel based setup. I like consistency, so I replace the command with one that provides a flakes-based output. +nix-index provides a way to find out which packages are provided by which derivations. By default it also comes with a replacement for command-not-found.sh, however, the implementation is based on a channel based setup. I like consistency, so I replace the command with one that provides a flakes-based output. This also uses the nix-index-with-full-db from the nix-index-database input thanks to its overlay.

    @@ -14829,20 +16200,22 @@ nix-index provides a way to find out which packages are provided by which deriva in { + enable = true; package = pkgs.symlinkJoin { name = "nix-index"; paths = [ commandNotFound ]; }; }; + programs.nix-index-database.comma.enable = true; }; }
    -
    -
    3.3.2.15. nix-your-shell
    +
    +
    3.3.2.15. nix-your-shell
    { lib, config, ... }:
    @@ -15426,12 +16799,32 @@ in
     
    -
    -
    3.3.2.25. zellij
    +
    +
    3.3.2.25. bash
    +
    +
    { config, pkgs, lib, ... }:
    +{
    +  options.swarselmodules.bash = lib.mkEnableOption "bash settings";
    +  config = lib.mkIf config.swarselmodules.bash {
    +
    +    programs.bash = {
    +      bashrcExtra = ''
    +        export PATH="${pkgs.nix}/bin:$PATH"
    +      '';
    +    };
    +  };
    +}
    +
    +
    +
    +
    +
    +
    3.3.2.26. zellij
    +
    -
    3.3.2.25.1. Main config
    +
    3.3.2.26.1. Main config
    { self, lib, config, pkgs, ... }:
    @@ -15495,9 +16888,9 @@ in
     
    -
    -
    3.3.2.25.2. Keybinds
    -
    +
    +
    3.3.2.26.2. Keybinds
    +
    { lib, config, ... }:
     {
    @@ -16649,7 +18042,7 @@ in
     
    -
    3.3.2.26. tmux
    +
    3.3.2.27. tmux
    { lib, config, pkgs, ... }:
    @@ -16758,16 +18151,16 @@ in
     
    -
    3.3.2.27. Mail
    +
    3.3.2.28. Mail

    Normally I use 4 mail accounts - here I set them all up. Three of them are Google accounts (sadly), which are a chore to setup. The last is just a sender account that I setup SMTP for here.

    -
    { lib, config, inputs, nixosConfig ? config, ... }:
    +
    { lib, config, inputs, globals, nixosConfig ? config, ... }:
     let
    -  inherit (nixosConfig.repo.secrets.common.mail) address1 address2 address2-name address3 address3-name address4 address4-user address4-host;
    +  inherit (nixosConfig.repo.secrets.common.mail) address1 address2 address2-name address3 address3-name address4;
       inherit (nixosConfig.repo.secrets.common) fullName;
       inherit (config.swarselsystems) xdgDir;
     in
    @@ -16890,24 +18283,43 @@ in
                 maildirBasePath = "Mail";
                 accounts = {
                   swarsel = {
    +                imap = {
    +                  host = globals.services.mailserver.domain;
    +                  port = 993;
    +                  tls.enable = true; # SSL/TLS
    +                };
    +                smtp = {
    +                  host = globals.services.mailserver.domain;
    +                  port = 465;
    +                  tls.enable = true; # SSL/TLS
    +                };
    +                thunderbird = {
    +                  enable = true;
    +                  profiles = [ "default" ];
    +                };
                     address = address4;
    -                userName = address4-user;
    +                userName = address4;
                     realName = fullName;
                     passwordCommand = "cat ${nixosConfig.sops.secrets.address4-token.path}";
    -                smtp = {
    -                  host = address4-host;
    -                  port = 587;
    -                  tls = {
    -                    enable = true;
    -                    useStartTls = true;
    -                  };
    -                };
    -                mu.enable = false;
    +                mu.enable = true;
                     msmtp = {
                       enable = true;
                     };
                     mbsync = {
    -                  enable = false;
    +                  enable = true;
    +                  create = "maildir";
    +                  expunge = "both";
    +                  patterns = [ "*" ];
    +                  extraConfig = {
    +                    channel = {
    +                      Sync = "All";
    +                    };
    +                    account = {
    +                      Timeout = 120;
    +                      PipelineDepth = 1;
    +                      AuthMechs = "LOGIN";
    +                    };
    +                  };
                     };
                   };
     
    @@ -16962,7 +18374,7 @@ in
     
    -
    3.3.2.28. Home-manager: Emacs
    +
    3.3.2.29. Home-manager: Emacs

    By using the emacs-overlay NixOS module, I can install all Emacs packages that I want to use right through NixOS. This is done by passing my init.el file to the configuration which will then be parsed upon system rebuild, looking for use-package sections in the Elisp code. Also I define here the style of Emacs that I want to run - I am going with native Wayland Emacs here (emacs-pgtk). All of the nice options such as tree-sitter support are enabled by default, so I do not need to adjust the build process. @@ -17102,7 +18514,7 @@ in

    -
    3.3.2.29. Waybar
    +
    3.3.2.30. Waybar

    Again I am just using the first bar option here that I was able to find good understandable documentation for. Of note is that the `cpu` section's `format` is not defined here, but in section 1 (since not every machine has the same number of cores) @@ -17458,7 +18870,7 @@ in

    -
    3.3.2.30. Firefox
    +
    3.3.2.31. Firefox

    Setting up firefox along with some policies that are important to me (mostly disabling telemetry related stuff as well as Pocket). I also enable some integrations that enable super useful packages, namely tridactyl and browserpass. @@ -17637,14 +19049,14 @@ I used to build the firefox addon bypass-paywalls-clean myself here

    -
    3.3.2.31. Services
    +
    3.3.2.32. Services

    Services that can be defined through home-manager should be defined here.

    -
    3.3.2.31.1. gnome-keyring
    +
    3.3.2.32.1. gnome-keyring

    Used for storing sessions in e.g. Nextcloud @@ -17665,7 +19077,7 @@ Used for storing sessions in e.g. Nextcloud

    -
    3.3.2.31.2. KDE Connect
    +
    3.3.2.32.2. KDE Connect

    This enables phone/computer communication, including sending clipboard, files etc. Sadly on Wayland many of the features are broken (like remote control). @@ -17688,7 +19100,7 @@ This enables phone/computer communication, including sending clipboard, files et

    -
    3.3.2.31.3. Mako
    +
    3.3.2.32.3. Mako

    Desktop notifications! @@ -17742,7 +19154,7 @@ The `extraConfig` section here CANNOT be reindented. This has something to do wi

    -
    3.3.2.31.4. SwayOSD
    +
    3.3.2.32.4. SwayOSD
    { lib, pkgs, config, ... }:
    @@ -17761,7 +19173,7 @@ The `extraConfig` section here CANNOT be reindented. This has something to do wi
     
    -
    3.3.2.31.5. yubikey-touch-detector
    +
    3.3.2.32.5. yubikey-touch-detector
    { lib, config, pkgs, ... }:
    @@ -17800,9 +19212,9 @@ The `extraConfig` section here CANNOT be reindented. This has something to do wi
     
    -
    -
    3.3.2.31.6. blueman-applet
    -
    +
    +
    3.3.2.32.6. blueman-applet
    +
    { lib, config, ... }:
     {
    @@ -17815,9 +19227,9 @@ The `extraConfig` section here CANNOT be reindented. This has something to do wi
     
    -
    -
    3.3.2.31.7. network-manager-applet
    -
    +
    +
    3.3.2.32.7. network-manager-applet
    +
    { lib, config, ... }:
     {
    @@ -17831,9 +19243,9 @@ The `extraConfig` section here CANNOT be reindented. This has something to do wi
     
    -
    -
    3.3.2.31.8. obsidian service for tray
    -
    +
    +
    3.3.2.32.8. obsidian service for tray
    +
    { lib, config, ... }:
     {
    @@ -17866,9 +19278,9 @@ The `extraConfig` section here CANNOT be reindented. This has something to do wi
     
    -
    -
    3.3.2.31.9. anki service for tray
    -
    +
    +
    3.3.2.32.9. anki service for tray
    +

    Sets up a systemd user service for anki that does not stall the shutdown process. Note that the outcommented ExecStart does not work because the home-manager anki package builds a separate anki package that - I think - cannot be referenced as no such expression exists in the module.

    @@ -17914,9 +19326,9 @@ Sets up a systemd user service for anki that does not stall the shutdown process
    -
    -
    3.3.2.31.10. element service for tray
    -
    +
    +
    3.3.2.32.10. element service for tray
    +
    { lib, config, pkgs, ... }:
     {
    @@ -17949,9 +19361,9 @@ Sets up a systemd user service for anki that does not stall the shutdown process
     
    -
    -
    3.3.2.31.11. vesktop service for tray
    -
    +
    +
    3.3.2.32.11. vesktop service for tray
    +
    { lib, config, pkgs, ... }:
     {
    @@ -17984,9 +19396,9 @@ Sets up a systemd user service for anki that does not stall the shutdown process
     
    -
    -
    3.3.2.31.12. syncthing service for tray
    -
    +
    +
    3.3.2.32.12. syncthing service for tray
    +
    { lib, config, pkgs, ... }:
     {
    @@ -18114,7 +19526,7 @@ Sets up a systemd user service for anki that does not stall the shutdown process
     
    -
    3.3.2.32. Sway
    +
    3.3.2.33. Sway

    I am currently using SwayFX, which adds some nice effects to sway, like rounded corners and hiding the separator between title and content of a window. @@ -18558,7 +19970,7 @@ Currently, I am too lazy to explain every option here, but most of it is very se

    -
    3.3.2.33. Niri
    +
    3.3.2.34. Niri
    { config, pkgs, lib, vars, ... }:
    @@ -18778,7 +20190,7 @@ Currently, I am too lazy to explain every option here, but most of it is very se
     
    -
    3.3.2.34. Kanshi
    +
    3.3.2.35. Kanshi
    { self, lib, pkgs, config, ... }:
    @@ -18888,7 +20300,7 @@ Currently, I am too lazy to explain every option here, but most of it is very se
     
    -
    3.3.2.35. gpg-agent
    +
    3.3.2.36. gpg-agent

    Settings that are needed for the gpg-agent. Also we are enabling emacs support for unlocking my Yubikey here. @@ -18972,7 +20384,7 @@ in

    -
    3.3.2.36. gammastep
    +
    3.3.2.37. gammastep

    This service changes the screen hue at night. I am not sure if that really does something, but I like the color anyways. @@ -18998,7 +20410,7 @@ in

    -
    3.3.2.37. Spicetify
    +
    3.3.2.38. Spicetify
    { inputs, lib, config, pkgs, ... }:
    @@ -19028,9 +20440,9 @@ in
     
    -
    -
    3.3.2.38. Obsidian
    -
    +
    +
    3.3.2.39. Obsidian
    +
    { lib, config, pkgs, nixosConfig ? config, ... }:
     let
    @@ -19189,9 +20601,9 @@ in
     
    -
    -
    3.3.2.39. Anki
    -
    +
    +
    3.3.2.40. Anki
    +
    { lib, config, pkgs, globals, inputs, nixosConfig ? config, ... }:
     let
    @@ -19263,9 +20675,9 @@ in
     
    -
    -
    3.3.2.40. Element-desktop
    -
    +
    +
    3.3.2.41. Element-desktop
    +
    { lib, config, ... }:
     let
    @@ -19300,9 +20712,9 @@ in
     
    -
    -
    3.3.2.41. Hexchat
    -
    +
    +
    3.3.2.42. Hexchat
    +
    { lib, config, nixosConfig ? config, ... }:
     let
    @@ -19325,9 +20737,9 @@ in
     
    -
    -
    3.3.2.42. obs-studio
    -
    +
    +
    3.3.2.43. obs-studio
    +
    { lib, config, ... }:
     let
    @@ -19346,9 +20758,9 @@ in
     
    -
    -
    3.3.2.43. spotify-player
    -
    +
    +
    3.3.2.44. spotify-player
    +
    { lib, config, ... }:
     let
    @@ -19367,9 +20779,9 @@ in
     
    -
    -
    3.3.2.44. vesktop
    -
    +
    +
    3.3.2.45. vesktop
    +
    { lib, pkgs, config, ... }:
     let
    @@ -19455,9 +20867,9 @@ in
     
    -
    -
    3.3.2.45. batsignal
    -
    +
    +
    3.3.2.46. batsignal
    +
    { lib, config, ... }:
     let
    @@ -19488,9 +20900,9 @@ in
     
    -
    -
    3.3.2.46. autotiling
    -
    +
    +
    3.3.2.47. autotiling
    +
    { lib, config, ... }:
     let
    @@ -19510,9 +20922,9 @@ in
     
    -
    -
    3.3.2.47. swayidle
    -
    +
    +
    3.3.2.48. swayidle
    +
    { lib, config, pkgs, ... }:
     let
    @@ -19552,9 +20964,9 @@ in
     
    -
    -
    3.3.2.48. swaylock
    -
    +
    +
    3.3.2.49. swaylock
    +
    { lib, config, pkgs, ... }:
     let
    @@ -19581,9 +20993,9 @@ in
     
    -
    -
    3.3.2.49. opkssh
    -
    +
    +
    3.3.2.50. opkssh
    +
    { lib, config, ... }:
     let
    @@ -19845,6 +21257,7 @@ in
               # openstackclient
     
               vscode
    +          dev.antigravity
     
               rustdesk-vbc
             ];
    @@ -20573,6 +21986,14 @@ TODO: check which of these can be replaced but builtin functions.
     
    { self, config, lib, ... }:
     {
       options.swarselsystems = {
    +    proxyHost = lib.mkOption {
    +      type = lib.types.str;
    +      default = "";
    +    };
    +    isCloud = lib.mkOption {
    +      type = lib.types.bool;
    +      default = false;
    +    };
         withHomeManager = lib.mkOption {
           type = lib.types.bool;
           default = true;
    @@ -20606,7 +22027,7 @@ TODO: check which of these can be replaced but builtin functions.
         isBtrfs = lib.mkEnableOption "use btrfs filesystem";
         sopsFile = lib.mkOption {
           type = lib.types.str;
    -      default = "${config.swarselsystems.flakePath}/secrets/${config.node.name}/secrets.yaml";
    +      default = "${if config.swarselsystems.isImpermanence then "/persist" else ""}${config.swarselsystems.flakePath}/secrets/${config.node.name}/secrets.yaml";
         };
         homeDir = lib.mkOption {
           type = lib.types.str;
    @@ -20907,8 +22328,41 @@ In short, the options defined here are passed to the modules systems using 
     
    +
    +

    3.4.3. Config Library (confLib)

    +
    +
    +
    { config, globals, ... }:
    +{
    +  _module.args = {
    +    confLib = rec {
    +
    +      addressDefault = if config.swarselsystems.proxyHost != config.node.name then globals.networks."${if config.swarselsystems.isCloud then config.node.name else "home"}-${config.swarselsystems.server.localNetwork}".hosts.${config.node.name}.ipv4 else "localhost";
    +
    +      domainDefault = service: config.repo.secrets.common.services.domains.${service};
    +      proxyDefault = config.swarselsystems.proxyHost;
    +
    +      gen = { name, user ? name, group ? name, dir ? null, port ? null, domain ? (domainDefault name), address ? addressDefault, proxy ? proxyDefault }: rec {
    +        servicePort = port;
    +        serviceName = name;
    +        serviceUser = user;
    +        serviceGroup = group;
    +        serviceDomain = domain;
    +        serviceDir = dir;
    +        serviceAddress = address;
    +        serviceProxy = proxy;
    +        proxyAddress4 = globals.hosts.${proxy}.wanAddress4;
    +        proxyAddress6 = globals.hosts.${proxy}.wanAddress6 or null;
    +      };
    +    };
    +  };
    +}
    +
    +
    +
    +
    -

    3.4.3. Packages

    +

    3.4.4. Packages

    This is the central station for self-defined packages. These are all referenced in default.nix. Wherever possible, I am keeping the shell version of these scripts in this file as well and then read it using builtin.readFile in the NixOS configurations. This lets me keep full control in this one file but also keep the separate files uncluttered. @@ -20919,9 +22373,9 @@ Note: The structure of generating the packages was changed in commit 2cf03

    -
    -

    3.4.4. Packages (flake)

    -
    +
    +

    3.4.5. Packages (flake)

    +
    { self, lib, pkgs, ... }:
     let
    @@ -20940,7 +22394,7 @@ mkPackages packageNames pkgs
     
    -
    3.4.4.1. pass-fuzzel
    +
    3.4.5.1. pass-fuzzel

    This app allows me, in conjunction with my Yubikey, to quickly enter passwords when the need arises. Normal and TOTP passwords are supported, and they can either be printed directly or copied to the clipboard. @@ -21013,9 +22467,9 @@ writeShellApplication {

    -
    -
    3.4.4.2. quickpass
    -
    +
    +
    3.4.5.2. quickpass
    +
    shopt -s nullglob globstar
     
    @@ -21045,7 +22499,7 @@ writeShellApplication {
     
    -
    3.4.4.3. cura5
    +
    3.4.5.3. cura5

    The version of cura used to be quite outdated in nixpkgs. I am fetching a newer AppImage here and use that instead. @@ -21088,7 +22542,7 @@ writeScriptBin "cura" ''

    -
    3.4.4.4. hm-specialisation
    +
    3.4.5.4. hm-specialisation

    This script allows for quick git home-manager specialisation switching. @@ -21114,7 +22568,7 @@ writeShellApplication {

    -
    3.4.4.5. cdw
    +
    3.4.5.5. cdw

    This script allows for quick git worktree switching. @@ -21138,7 +22592,7 @@ writeShellApplication {

    -
    3.4.4.6. cdb
    +
    3.4.5.6. cdb

    This script allows for quick git branch switching. @@ -21160,7 +22614,7 @@ writeShellApplication {

    -
    3.4.4.7. bak
    +
    3.4.5.7. bak

    This script lets me quickly backup files by appending .bak to the filename. @@ -21183,7 +22637,7 @@ writeShellApplication {

    -
    3.4.4.8. timer
    +
    3.4.5.8. timer

    This app starts a configuratble timer and uses TTS to say something once the timer runs out. @@ -21206,7 +22660,7 @@ writeShellApplication {

    -
    3.4.4.9. e
    +
    3.4.5.9. e

    This is a shorthand for calling emacsclient mostly. Also, it hides the kittyterm scratchpad window that I sometimes use for calling a command quickly, in case it is on the screen. After emacs closes, the kittyterm window is then shown again if it was visible earlier. @@ -21252,7 +22706,7 @@ writeShellApplication {

    -
    3.4.4.10. command-not-found
    +
    3.4.5.10. command-not-found

    The normal command-not-found.sh uses the outdated nix-shell commands as suggestions. This version supplies me with the more modern nixpkgs#<name> version. @@ -21298,7 +22752,7 @@ command_not_found_handler() {

    -
    3.4.4.11. swarselcheck
    +
    3.4.5.11. swarselcheck

    This app checks for different apps that I keep around in the scratchpad for quick viewing and hiding (messengers and music players mostly) and then behaves like the kittyterm hider that I described in e. @@ -21383,7 +22837,7 @@ writeShellApplication {

    -
    3.4.4.12. swarselcheck-niri
    +
    3.4.5.12. swarselcheck-niri
    while :; do
    @@ -21438,7 +22892,7 @@ writeShellApplication {
     
    -
    3.4.4.13. swarselzellij
    +
    3.4.5.13. swarselzellij
    # KITTIES=$(($(pgrep -P 1 kitty | wc -l) - 1))
    @@ -21465,7 +22919,7 @@ writeShellApplication {
     
    -
    3.4.4.14. waybarupdate
    +
    3.4.5.14. waybarupdate

    This scripts checks if there are uncommited changes in either my dotfile repo, my university repo, or my passfile repo. In that case a warning will be shown in waybar. @@ -21512,7 +22966,7 @@ writeShellApplication {

    -
    3.4.4.15. opacitytoggle
    +
    3.4.5.15. opacitytoggle

    This app quickly toggles between 5% and 0% transparency. @@ -21539,7 +22993,7 @@ writeShellApplication {

    -
    3.4.4.16. fs-diff
    +
    3.4.5.16. fs-diff

    This utility is used to compare the current state of the root directory with the blanket state that is stored in /root-blank (the snapshot that is restored on each reboot of an impermanence machine). Using this, I can find files that I will lose once I reboot - if there are important files in that list, I can then easily add them to the persist options. @@ -21580,7 +23034,7 @@ writeShellApplication {

    -
    3.4.4.17. github-notifications
    +
    3.4.5.17. github-notifications

    This utility checks if there are updated packages in nixpkgs-unstable. It does so by fully building the most recent configuration, which I do not love, but it has its merits once I am willing to switch to the newer version. @@ -21606,7 +23060,7 @@ writeShellApplication {

    -
    3.4.4.18. kanshare
    +
    3.4.5.18. kanshare

    This utility checks if there are updated packages in nixpkgs-unstable. It does so by fully building the most recent configuration, which I do not love, but it has its merits once I am willing to switch to the newer version. @@ -21630,7 +23084,7 @@ writeShellApplication {

    -
    3.4.4.19. swarsel-bootstrap
    +
    3.4.5.19. swarsel-bootstrap

    This program sets up a new NixOS host remotely. It also takes care of secret management on the new host. @@ -21647,6 +23101,8 @@ target_user="swarsel" ssh_port="22" persist_dir="" disk_encryption=0 +disk_encryption_args="" +no_disko_deps="false" temp=$(mktemp -d) function help_and_exit() { @@ -21666,6 +23122,7 @@ function help_and_exit() { echo " Default='${target_user}'." echo " --port <ssh_port> specify the ssh port to use for remote access. Default=${ssh_port}." echo " --debug Enable debug mode." + echo " --no-disko-deps Upload only disk script and not dependencies (for use on low ram)." echo " -h | --help Print this help." exit 0 } @@ -21719,14 +23176,14 @@ function update_sops_file() { SOPS_FILE=".sops.yaml" sed -i "{ - # Remove any * and & entries for this host - /[*&]$key_name/ d; - # Inject a new age: entry - # n matches the first line following age: and p prints it, then we transform it while reusing the spacing - /age:/{n; p; s/\(.*- \*\).*/\1$key_name/}; - # Inject a new hosts or user: entry - /&$key_type/{n; p; s/\(.*- &\).*/\1$key_name $key/} - }" $SOPS_FILE + # Remove any * and & entries for this host + /[*&]$key_name/ d; + # Inject a new age: entry + # n matches the first line following age: and p prints it, then we transform it while reusing the spacing + /age:/{n; p; s/\(.*- \*\).*/\1$key_name/}; + # Inject a new hosts or user: entry + /&$key_type/{n; p; s/\(.*- &\).*/\1$key_name $key/} + }" $SOPS_FILE green "Updating .sops.yaml" cd - } @@ -21753,6 +23210,9 @@ while [[ $# -gt 0 ]]; do shift ssh_port=$1 ;; + --no-disko-deps) + no_disko_deps="true" + ;; --debug) set -x ;; @@ -21770,6 +23230,12 @@ if [[ $target_arch == "" || $target_destination == "" || $target_hostname == "" help_and_exit fi +LOCKED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.node.lockFromBootstrapping)" +if [[ $LOCKED == "true" ]]; then + red "THIS SYSTEM IS LOCKED FROM BOOTSTRAPPING" + exit +fi + green "~SwarselSystems~ remote installer" green "Reading system information for $target_hostname ..." @@ -21780,6 +23246,11 @@ CRYPTED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.sw if [[ $CRYPTED == "true" ]]; then green "Encryption: ✓" disk_encryption=1 + disk_encryption_args=( + --disk-encryption-keys + /tmp/disko-password + /tmp/disko-password + ) else red "Encryption: X" disk_encryption=0 @@ -21872,7 +23343,14 @@ $scp_cmd root@"$target_destination":/mnt/etc/nixos/hardware-configuration.nix "$ # ------------------------ green "Deploying minimal NixOS installation on $target_destination" -nix run github:nix-community/nixos-anywhere/1.10.0 -- --ssh-port "$ssh_port" --extra-files "$temp" --flake ./install#"$target_hostname" root@"$target_destination" + +if [[ $no_disko_deps == "true" ]]; then + green "Building without disko dependencies (using custom kexec)" + nix run github:nix-community/nixos-anywhere/1.10.0 -- "${disk_encryption_args[@]}" --no-disko-deps --ssh-port "$ssh_port" --extra-files "$temp" --flake ./install#"$target_hostname" --kexec "$(nix build --print-out-paths .#packages."$target_arch".swarsel-kexec)/swarsel-kexec-$target_arch.tar.gz" root@"$target_destination" +else + green "Building with disko dependencies (using nixos-images kexec)" + nix run github:nix-community/nixos-anywhere/1.10.0 -- "${disk_encryption_args[@]}" --ssh-port "$ssh_port" --extra-files "$temp" --flake ./install#"$target_hostname" root@"$target_destination" +fi echo "Updating ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true @@ -22020,7 +23498,7 @@ writeShellApplication {

    -
    3.4.4.20. swarsel-rebuild
    +
    3.4.5.20. swarsel-rebuild
    set -eo pipefail
    @@ -22150,7 +23628,7 @@ writeShellApplication {
     
    -
    3.4.4.21. swarsel-install
    +
    3.4.5.21. swarsel-install

    Autoformatting always puts the EOF with indentation, which makes shfmt check fail. When editing this block, unindent them manually. @@ -22363,7 +23841,7 @@ writeShellApplication {

    -
    3.4.4.22. swarsel-postinstall
    +
    3.4.5.22. swarsel-postinstall
    set -eo pipefail
    @@ -22455,7 +23933,7 @@ writeShellApplication {
     
    -
    3.4.4.23. t2ts
    +
    3.4.5.23. t2ts
    { name, writeShellApplication, ... }:
    @@ -22473,7 +23951,7 @@ writeShellApplication {
     
    -
    3.4.4.24. ts2t
    +
    3.4.5.24. ts2t
    { name, writeShellApplication, ... }:
    @@ -22491,7 +23969,7 @@ writeShellApplication {
     
    -
    3.4.4.25. vershell
    +
    3.4.5.25. vershell
    { name, writeShellApplication, ... }:
    @@ -22509,7 +23987,7 @@ writeShellApplication {
     
    -
    3.4.4.26. eontimer
    +
    3.4.5.26. eontimer
    { lib
    @@ -22613,7 +24091,7 @@ python3.pkgs.buildPythonApplication rec {
     
    -
    3.4.4.27. project
    +
    3.4.5.27. project
    set -euo pipefail
    @@ -22637,7 +24115,7 @@ writeShellApplication {
     
    -
    3.4.4.28. fhs
    +
    3.4.5.28. fhs
    { name, pkgs, ... }:
    @@ -22656,7 +24134,7 @@ pkgs.buildFHSEnv (base // {
     
    -
    3.4.4.29. swarsel-displaypower
    +
    3.4.5.29. swarsel-displaypower

    A crude script to power on all displays that might be attached. Needed because sometimes displays do not awake from sleep. @@ -22681,7 +24159,7 @@ writeShellApplication {

    -
    3.4.4.30. swarsel-mgba
    +
    3.4.5.30. swarsel-mgba

    AppImage version of mgba in which the lua scripting works. @@ -22715,7 +24193,7 @@ appimageTools.wrapType2 {

    -
    3.4.4.31. swarsel-deploy
    +
    3.4.5.31. swarsel-deploy
    # heavily inspired from https://github.com/oddlama/nix-config/blob/d42cbde676001a7ad8a3cace156e050933a4dcc3/pkgs/deploy.nix
    @@ -22847,7 +24325,7 @@ writeShellApplication {
     
    -
    3.4.4.32. swarsel-build
    +
    3.4.5.32. swarsel-build
    { name, nix-output-monitor, writeShellApplication, ... }:
    @@ -22871,7 +24349,7 @@ writeShellApplication {
     
    -
    3.4.4.33. swarsel-instantiate
    +
    3.4.5.33. swarsel-instantiate

    This is a convenience function that calls nix-instantiate with a number of flags that I need in order to evaluate nix expressions in org-src blocks. @@ -22892,7 +24370,7 @@ writeShellApplication {

    -
    3.4.4.34. sshrm
    +
    3.4.5.34. sshrm

    This programs simply runs ssh-keygen on the last host that I tried to ssh into. I need this frequently when working with cloud-init usually. @@ -22924,9 +24402,9 @@ writeShellApplication {

    -
    -
    3.4.4.35. endme
    -
    +
    +
    3.4.5.35. endme
    +

    Sometimes my DE crashes after putting it to suspend - to be precise, it happens when I put it into suspend when I have multiple screens plugged in. I have never taken the time to debug the issue, but instead just switch to a different TTY and then use this script to kill the hanging session.

    @@ -22946,9 +24424,9 @@ writeShellApplication {
    -
    -
    3.4.4.36. git-replace
    -
    +
    +
    3.4.5.36. git-replace
    +

    This script allows for quick git replace of a string.

    @@ -23025,9 +24503,9 @@ writeShellApplication {
    -
    -

    3.4.5. Packages (config)

    -
    +
    +

    3.4.6. Packages (config)

    +
    { self, homeConfig, lib, pkgs, ... }:
     let
    @@ -23043,9 +24521,9 @@ mkPackages packageNames pkgs
     
    -
    -
    3.4.5.1. cdr
    -
    +
    +
    3.4.6.1. cdr
    +
    { name, homeConfig, writeShellApplication, fzf, ... }:
     
    @@ -23207,8 +24685,8 @@ in
     
    -
    -
    3.5.1.3. Optionals
    +
    +
    3.5.1.3. Optionals
    { lib, config, ... }:
    @@ -23413,8 +24891,8 @@ in
     
    -
    -
    3.5.1.9. Router
    +
    +
    3.5.1.9. Router
    { lib, config, ... }:
    @@ -23530,8 +25008,8 @@ in
     
    -
    -
    3.5.2.2. DGX Spark
    +
    +
    3.5.2.2. DGX Spark
    { lib, config, ... }:
    @@ -23544,6 +25022,7 @@ in
           atuin = lib.mkDefault true;
           autotiling = lib.mkDefault false;
           batsignal = lib.mkDefault false;
    +      bash = lib.mkDefault true;
           blueman-applet = lib.mkDefault true;
           desktop = lib.mkDefault false;
           direnv = lib.mkDefault true;
    @@ -24300,8 +25779,8 @@ This function was found here: 
    -
    4.2.1.9. Magit: List directories using vertico/consult
    +
    +
    4.2.1.9. Magit: List directories using vertico/consult
    @@ -26058,8 +27537,8 @@ Recently I have grown fond of holding presentations using Emacs :)
     
    -
    -
    4.4.1.11. Render markdown blocks as body to expand noweb blocks
    +
    +
    4.4.1.11. Render markdown blocks as body to expand noweb blocks
    (defun org-babel-execute:markdown (body params)
    @@ -27275,8 +28754,8 @@ This adds the simple utility of sending desktop notifications whenever a new mai
     
    -
    -
    4.4.39.3. Work: Signing Mails (S/MIME, smime)
    +
    +
    4.4.39.3. Work: Signing Mails (S/MIME, smime)
    -
    -

    5.1. General steps when setting up a new machine

    +
    +

    5.1. General steps when setting up a new machine

    These general steps are needed when setting up a new machine and do not fit into another block well: @@ -27577,8 +29056,8 @@ These general steps are needed when setting up a new machine and do not fit into - `systemd-cryptenroll --fido2-device=auto /dev/`

    -
    -

    5.2. Current patches and fixes

    +
    +

    5.2. Current patches and fixes

    These are current deviations from the standard settings that I take while some things are broken upstream @@ -28385,8 +29864,11 @@ dd DRIVE ISO: sync USER HOST: rsync -rltv --filter=':- .gitignore' -e "ssh -l {{USER}}" . {{USER}}@{{HOST}}:.dotfiles/ -bootstrap DEST CONFIG ARCH="x86_64-linux": - nix develop .#deploy --command zsh -c "swarsel-bootstrap -n {{CONFIG}} -d {{DEST}} -a {{ARCH}}" +secrets USER HOST: + rsync -rltv -e "ssh -l {{USER}}" /var/tmp/nix-import-encrypted/1000/ {{USER}}@{{HOST}}:/var/tmp/nix-import-encrypted/0 + +bootstrap DEST CONFIG ARCH="x86_64-linux" NODISKODEPS="": + nix develop .#deploy --command zsh -c "swarsel-bootstrap {{NODISKODEPS}} -n {{CONFIG}} -d {{DEST}} -a {{ARCH}}"

    @@ -29317,8 +30799,10 @@ See the above repository for updates as well as full license text. */ transform-origin: 0px calc(0px - var(--tab-min-height) - var(--tab-block-margin) * 2); transform: rotateX(89.9deg); } -#mainPopupSet:has(> [panelopen]:not(#ask-chat-shortcuts,#selection-shortcut-action-panel,#chat-shortcuts-options-panel,#tab-preview-panel)) ~ toolbox #urlbar[popover], -/* swarsel: removed :hover from below line */ + +:root[window-modal-open] #urlbar[popover], +#mainPopupSet:has(> [panelopen]:not(#ask-chat-shortcuts,#selection-shortcut-action-panel,#chat-shortcuts-options-panel,#tab-preview-panel), > #tab-group-editor > [panelopen]) ~ toolbox #urlbar[popover], + /* swarsel: removed :hover from below line */ #navigator-toolbox:is(:focus-within,[movingtab]) #urlbar[popover], #urlbar-container > #urlbar[popover]:is([focused],[open]){ pointer-events: auto; @@ -29326,9 +30810,11 @@ See the above repository for updates as well as full license text. */ transition-delay: 33ms; transform: rotateX(0deg); } -#mainPopupSet:has(> [panelopen]:not(#ask-chat-shortcuts,#selection-shortcut-action-panel,#chat-shortcuts-options-panel,#tab-preview-panel)) ~ toolbox, + +:root[window-modal-open] #navigator-toolbox, +#mainPopupSet:has(> [panelopen]:not(#ask-chat-shortcuts,#selection-shortcut-action-panel,#chat-shortcuts-options-panel,#tab-preview-panel), > #tab-group-editor > [panelopen]) ~ toolbox, #navigator-toolbox:has(#urlbar:is([open],[focus-within])), -/* swarsel: removed :hover from below line */ + /* swarsel: removed :hover from below line */ #navigator-toolbox:is(:focus-within,[movingtab]){ transition-delay: 33ms !important; transform: rotateX(0); @@ -29337,8 +30823,7 @@ See the above repository for updates as well as full license text. */ /* This makes things like OS menubar/taskbar show the toolbox when hovered in maximized windows. * Unfortunately it also means that other OS native surfaces (such as context menu on macos) * and other always-on-top applications will trigger toolbox to show up. */ -@media (-moz-bool-pref: "userchrome.autohide-toolbox.unhide-by-native-ui.enabled"), - -moz-pref("userchrome.autohide-toolbox.unhide-by-native-ui.enabled"){ +@media -moz-pref("userchrome.autohide-toolbox.unhide-by-native-ui.enabled"){ :root[sizemode="maximized"]:not(:hover){ #navigator-toolbox:not(:-moz-window-inactive), #urlbar[popover]:not(:-moz-window-inactive){ @@ -29368,13 +30853,9 @@ See the above repository for updates as well as full license text. */ padding-block: calc(min(4px,(var(--urlbar-container-height) - var(--urlbar-height)) / 2) + var(--urlbar-container-padding)) !important; } -/* Uncomment this if tabs toolbar is hidden with hide_tabs_toolbar.css */ - /*#titlebar{ margin-bottom: -9px }*/ - /* Uncomment the following for compatibility with tabs_on_bottom.css - this isn't well tested though */ /* #navigator-toolbox{ flex-direction: column; display: flex; } -#titlebar{ order: 2 } */
    @@ -30089,13 +31570,14 @@ Here lies defined the readme for GitHub and Forgejo: |🖥️ **winters** | ASRock J4105-ITX, 32GB RAM | Secondary homeserver and data storgae | |🖥️ **summers** | ASUS Z10PA-D8, 2* Intel Xeon E5-2650 v4, 128GB RAM | Main homeserver running microvms, data storage | |🖥️ **hintbooth** | HUNSN RM02, 8GB RAM | Router | - |☁️ **milkywell** | Oracle Cloud: VM.Standard.E2.1.Micro | Server for lightweight synchronization tasks | + |☁️ **milkywell** | Oracle Cloud: VM.Standard.E2.1.Micro | Authoritative DNS server | |☁️ **moonside** | Oracle Cloud: VM.Standard.A1.Flex, 4 OCPUs, 24GB RAM| Proxy for local services, some lightweight services | |☁️ **belchsfactory**| Oracle Cloud: VM.Standard.A1.Flex, 4 OCPUs, 24GB RAM| Hydra builder and nix binary cache | |☁️ **monkeycave** | Oracle Cloud: VM.Standard.A1.Flex, 4 OCPUs, 24GB RAM| Gaming server | |☁️ **eagleland** | Hetzner Cloud: CX23 | Mail server | |📱 **magicant** | Samsung Galaxy Z Flip 6 | Phone | |💿 **drugstore** | - | ISO installer configuration | + |💿 **brickroad** | - | Kexec tarball | |❔ **chaotheatre** | - | Demo config for checking out my configurtion | |❔ **toto** | - | Helper configuration for bootstrapping a new system | </details> @@ -30562,7 +32044,7 @@ similarly, there exists an version that starts from the right.