diff --git a/.sops.yaml b/.sops.yaml index 7314a89..ee31af7 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -21,6 +21,27 @@ keys: - &toto age16vzhcvz8tyxj8e0f47fy0z4p3dsg0ak4vl52ut3l07a0tz465cxslmhevl - &twothreetunnel age1g7atkxdlt4ymeh7v7aa2yzr2hq2qkvzrc4r49ugttm3n582ymv9qrmpk8d - &winters age1s0vssf9fey2l456hucppzx2x58xep279nsdcglvkqm30sr9ht37s8rvpza + - &summers-ankisync age1kyue7mfvzuxprjz2g6ulz2mxlr57rgzg6lfpnrqedkelehley5ls3enwsd + - &summers-atuin age1qpgj3ell93rzkpjq0ezs6t669ds3nyxx67pj50smx597pspz6fqs4jc6pt + - &summers-audio age1f63r2klnpfxmntswz5xydpa75ckgjqcs2yzkm0msqwqgz9aqgu0qwzr659 + - &summers-firefly age17328xwk0z3znalpmma5rvp0lt5ghn5p8xfvnrtdxwsw80dqysacqj9j37q + - &summers-forgejo age1qdzkn6v3xhrfjwe8jxz3945dhyyhevwal0narjtr8whf9y7nh3wsn524u5 + - &summers-freshrss age1etgfym5m8hn3hxs6cgg757zcv5zg5n22wq38fuq59n7qk7nef5uqyg6vvs + - &summers-homebox age17mugmkdw0y768a3huuf37r45eff9apyknxvwk3agg6xzsjmqp96q57tcty + - &summers-immich age16gf76uustmyyksm3t56zcq9g6j8avy0wrngh8laknfq733s5welqedeg4x + - &summers-jellyfin age1fnvlmhzju0yq908xtgags0sy85q3tacl2sc3w3vdd3yfp27xv5aq06v948 + - &summers-kanidm age1s5gcxtatd9frwctzwg54fqycsx2sa73ll36k7qrpm9wwyknkldtst90gn4 + - &summers-kavita age1d89878cvt7wsa07ydwtexspku5gppwstrpnpph4ufx5pcd4fadyqgf6lvl + - &summers-koillection age1ayupuxlrkepyvjk7xwgrd0pvcj3tfcha688mcuc8ees2hg3g2ersd0q3nc + - &summers-matrix age1cq7wxnugpfvjk6dgqpfmc8vemzhkg75drkgeaqjd9fuylz5qh40slazr4u + - &summers-monitoring age1vn6ya0japzpgc256jg57fldsqe4udmq50sj5hmkywn7rxfnskevsx2q96u + - &summers-nextcloud age1t7zagjfddns4yltupk7nx8xps4gh7mupyz85uuys0wd22cxj5qsq2hw0p7 + - &summers-paperless age1rn0pxluh7m8dyeshek06d7scejqlrcewlk8xmyrwt5e5nev2dc2s3s78vq + - &summers-postgresql age12jh5836w3cmazec8ql652p9h3a3xn6quztztzqxg4n0kz7r96dnqqlhxxw + - &summers-radicale age1gxg2peektn8x36kk3nsgmeawl73e54kaadqd649ygwrv43kkvejq2cw64z + - &summers-storage age1kn34ny229gm0rg7wlcvxmcyjtz4gka6f2vd958fde6vmuzrxcvcsufra90 + - &summers-transmission age1y69f2elvmq39lc3t3ucq9y7wt675520n7rvug88qg368qsmmk47qvwrtny + creation_rules: - path_regex: secrets/repo/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -42,6 +63,26 @@ creation_rules: - *dgx - *hintbooth-adguardhome - *hintbooth-nginx + - *summers-ankisync + - *summers-atuin + - *summers-audio + - *summers-firefly + - *summers-forgejo + - *summers-freshrss + - *summers-homebox + - *summers-immich + - *summers-jellyfin + - *summers-kanidm + - *summers-kavita + - *summers-koillection + - *summers-matrix + - *summers-monitoring + - *summers-nextcloud + - *summers-paperless + - *summers-postgresql + - *summers-radicale + - *summers-storage + - *summers-transmission - path_regex: secrets/work/[^/]+\.(yaml|json|env|ini)$ key_groups: @@ -159,6 +200,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-ankisync - path_regex: hosts/nixos/x86_64-linux/summers/secrets/atuin/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -166,6 +208,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-atuin - path_regex: hosts/nixos/x86_64-linux/summers/secrets/audio/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -173,6 +216,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-audio - path_regex: hosts/nixos/x86_64-linux/summers/secrets/firefly/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -180,6 +224,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-firefly - path_regex: hosts/nixos/x86_64-linux/summers/secrets/forgejo/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -187,6 +232,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-forgejo - path_regex: hosts/nixos/x86_64-linux/summers/secrets/freshrss/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -194,6 +240,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-freshrss - path_regex: hosts/nixos/x86_64-linux/summers/secrets/homebox/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -201,6 +248,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-homebox - path_regex: hosts/nixos/x86_64-linux/summers/secrets/immich/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -208,6 +256,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-immich - path_regex: hosts/nixos/x86_64-linux/summers/secrets/jellyfin/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -215,6 +264,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-jellyfin - path_regex: hosts/nixos/x86_64-linux/summers/secrets/kanidm/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -222,6 +272,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-kanidm - path_regex: hosts/nixos/x86_64-linux/summers/secrets/kavita/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -229,6 +280,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-kavita - path_regex: hosts/nixos/x86_64-linux/summers/secrets/koillection/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -236,6 +288,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-koillection - path_regex: hosts/nixos/x86_64-linux/summers/secrets/matrix/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -243,6 +296,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-matrix - path_regex: hosts/nixos/x86_64-linux/summers/secrets/monitoring/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -250,6 +304,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-monitoring - path_regex: hosts/nixos/x86_64-linux/summers/secrets/nextcloud/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -257,6 +312,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-nextcloud - path_regex: hosts/nixos/x86_64-linux/summers/secrets/paperless/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -264,6 +320,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-paperless - path_regex: hosts/nixos/x86_64-linux/summers/secrets/postgresql/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -271,6 +328,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-postgresql - path_regex: hosts/nixos/x86_64-linux/summers/secrets/radicale/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -278,6 +336,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-radicale - path_regex: hosts/nixos/x86_64-linux/summers/secrets/storage/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -285,6 +344,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-storage - path_regex: hosts/nixos/x86_64-linux/summers/secrets/transmission/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: @@ -292,6 +352,7 @@ creation_rules: - *swarsel age: - *summers + - *summers-transmission - path_regex: hosts/darwin/x86_64-darwin/nbm-imba-166/secrets/[^/]+\.(yaml|json|env|ini|enc)$ key_groups: diff --git a/SwarselSystems.org b/SwarselSystems.org index c7be594..4383750 100644 --- a/SwarselSystems.org +++ b/SwarselSystems.org @@ -1721,6 +1721,7 @@ A short overview over each input and what it does: smallpkgs.url = "github:nixos/nixpkgs/08fcb0dcb59df0344652b38ea6326a2d8271baff?narHash=sha256-HXIQzULIG/MEUW2Q/Ss47oE3QrjxvpUX7gUl4Xp6lnc%3D&shallow=1"; nixpkgs-dev.url = "github:Swarsel/nixpkgs/main"; + nixpkgs-debug.url = "github:nixos/nixpkgs/master"; 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.11"; nixpkgs-stable24_05.url = "github:NixOS/nixpkgs/nixos-24.05"; @@ -2620,7 +2621,7 @@ Another note concerning [[https://flake.parts/][flake-parts]]: }; nswitch = mkDevice "Nintendo Switch" { - info = "Atmosphère 1.3.2 @ FW 19.0.1"; + info = "Atmosphere 1.3.2 @ FW 19.0.1"; image = "${self}/files/topology-images/nintendo-switch.png"; interfaces.eth1 = { }; }; @@ -4267,7 +4268,7 @@ This is my main server that I run at home. It handles most tasks that require bi :CUSTOM_ID: h:0fdefb4f-ce53-4caf-89ed-5d79646f70f0 :END: #+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/winters/hardware-configuration.nix - { lib, modulesPath, ... }: + { lib, config, modulesPath, ... }: { imports = diff --git a/flake.lock b/flake.lock index f579e9a..b264af1 100644 --- a/flake.lock +++ b/flake.lock @@ -1460,11 +1460,11 @@ "pre-commit-hooks": "pre-commit-hooks_2" }, "locked": { - "lastModified": 1757854196, - "narHash": "sha256-RDr3/JTpRyXSR1OOg+wzdOUmDL1Ke05OLV/xctbuQOw=", + "lastModified": 1767971910, + "narHash": "sha256-j8vLAUaH8oAU5TSprSGa81wx+roo89iG98mUAutsjb8=", "owner": "oddlama", "repo": "nixos-extra-modules", - "rev": "a584a970a05d0410dcb00e0ade684a0c0ce00c4b", + "rev": "672abff4255796950924b284b1a2b3dd37113bd2", "type": "github" }, "original": { @@ -1598,6 +1598,22 @@ "type": "github" } }, + "nixpkgs-bisect": { + "locked": { + "lastModified": 1768161245, + "narHash": "sha256-fSidazKIcZElti/a1SOmIwSXw6hXR2GLO/2XmkXgtX4=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "d2a6c7729bbe95f5770ccd4d15a38e5037984b04", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "master", + "repo": "nixpkgs", + "type": "github" + } + }, "nixpkgs-dev": { "locked": { "lastModified": 1767131767, @@ -1893,11 +1909,11 @@ }, "nixpkgs_14": { "locked": { - "lastModified": 1763966396, - "narHash": "sha256-6eeL1YPcY1MV3DDStIDIdy/zZCDKgHdkCmsrLJFiZf0=", + "lastModified": 1737885589, + "narHash": "sha256-Zf0hSrtzaM1DEz8//+Xs51k/wdSajticVrATqDrfQjg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "5ae3b07d8d6527c42f17c876e404993199144b6a", + "rev": "852ff1d9e153d8875a83602e03fdef8a63f0ecf8", "type": "github" }, "original": { @@ -2659,6 +2675,7 @@ "nixos-images": "nixos-images", "nixos-nftables-firewall": "nixos-nftables-firewall", "nixpkgs": "nixpkgs_18", + "nixpkgs-bisect": "nixpkgs-bisect", "nixpkgs-dev": "nixpkgs-dev", "nixpkgs-kernel": "nixpkgs-kernel", "nixpkgs-stable": "nixpkgs-stable_3", diff --git a/flake.nix b/flake.nix index f879860..29a5883 100644 --- a/flake.nix +++ b/flake.nix @@ -27,6 +27,7 @@ smallpkgs.url = "github:nixos/nixpkgs/08fcb0dcb59df0344652b38ea6326a2d8271baff?narHash=sha256-HXIQzULIG/MEUW2Q/Ss47oE3QrjxvpUX7gUl4Xp6lnc%3D&shallow=1"; nixpkgs-dev.url = "github:Swarsel/nixpkgs/main"; + nixpkgs-bisect.url = "github:nixos/nixpkgs/master"; 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.11"; nixpkgs-stable24_05.url = "github:NixOS/nixpkgs/nixos-24.05"; diff --git a/hosts/nixos/x86_64-linux/hintbooth/default.nix b/hosts/nixos/x86_64-linux/hintbooth/default.nix index 77fabd2..937ec67 100644 --- a/hosts/nixos/x86_64-linux/hintbooth/default.nix +++ b/hosts/nixos/x86_64-linux/hintbooth/default.nix @@ -68,8 +68,8 @@ guests = lib.mkIf (!minimal && config.swarselsystems.withMicroVMs) ( { } - // confLib.mkMicrovm "adguardhome" - // confLib.mkMicrovm "nginx" + // confLib.mkMicrovm "adguardhome" { } + // confLib.mkMicrovm "nginx" { } ); } diff --git a/hosts/nixos/x86_64-linux/hintbooth/guests/adguardhome/default.nix b/hosts/nixos/x86_64-linux/hintbooth/guests/adguardhome/default.nix index b10f730..eaf90f4 100644 --- a/hosts/nixos/x86_64-linux/hintbooth/guests/adguardhome/default.nix +++ b/hosts/nixos/x86_64-linux/hintbooth/guests/adguardhome/default.nix @@ -3,6 +3,7 @@ imports = [ "${self}/profiles/nixos/microvm" "${self}/modules/nixos" + "${self}/modules/nixos/optional/microvm-guest-shares.nix" ]; swarselsystems = { diff --git a/hosts/nixos/x86_64-linux/hintbooth/guests/nginx/default.nix b/hosts/nixos/x86_64-linux/hintbooth/guests/nginx/default.nix index 39656a1..aef38bd 100644 --- a/hosts/nixos/x86_64-linux/hintbooth/guests/nginx/default.nix +++ b/hosts/nixos/x86_64-linux/hintbooth/guests/nginx/default.nix @@ -6,6 +6,7 @@ in imports = [ "${self}/profiles/nixos/microvm" "${self}/modules/nixos" + "${self}/modules/nixos/optional/microvm-guest-shares.nix" ]; swarselsystems = { diff --git a/hosts/nixos/x86_64-linux/summers/default.nix b/hosts/nixos/x86_64-linux/summers/default.nix index ddc929d..ad093b0 100644 --- a/hosts/nixos/x86_64-linux/summers/default.nix +++ b/hosts/nixos/x86_64-linux/summers/default.nix @@ -1,4 +1,4 @@ -{ self, inputs, lib, minimal, ... }: +{ self, config, inputs, lib, minimal, confLib, ... }: { imports = [ @@ -39,7 +39,7 @@ writeGlobalNetworks = false; networkKernelModules = [ "igb" ]; rootDisk = "/dev/disk/by-id/ata-TS120GMTS420S_J024880123"; - withMicroVMs = false; + withMicroVMs = true; localVLANs = [ "services" "home" ]; # devices is only provided on interface for bmc initrdVLAN = "home"; server = { @@ -83,7 +83,7 @@ acme = false; # cert handled by proxy nfs = true; - kavita = true; + # kavita = true; restic = true; jellyfin = true; navidrome = true; @@ -109,29 +109,29 @@ opkssh = true; }; - # guests = lib.mkIf (!minimal && config.swarselsystems.withMicroVMs) ( - # { } - # // confLib.mkMicrovm "kavita" - # // confLib.mkMicrovm "jellyfin" - # // confLib.mkMicrovm "audio" - # // confLib.mkMicrovm "postgresql" - # // confLib.mkMicrovm "matrix" - # // confLib.mkMicrovm "nextcloud" - # // confLib.mkMicrovm "immich" - # // confLib.mkMicrovm "paperless" - # // confLib.mkMicrovm "transmission" - # // confLib.mkMicrovm "storage" - # // confLib.mkMicrovm "monitoring" - # // confLib.mkMicrovm "freshrss" - # // confLib.mkMicrovm "kanidm" - # // confLib.mkMicrovm "firefly" - # // confLib.mkMicrovm "koillection" - # // confLib.mkMicrovm "radicale" - # // confLib.mkMicrovm "atuin" - # // confLib.mkMicrovm "forgejo" - # // confLib.mkMicrovm "ankisync" - # // confLib.mkMicrovm "homebox" - # ); + guests = lib.mkIf (!minimal && config.swarselsystems.withMicroVMs) ( + { } + // confLib.mkMicrovm "kavita" { withZfs = true; } + // confLib.mkMicrovm "jellyfin" { withZfs = true; } + // confLib.mkMicrovm "audio" { withZfs = true; } + // confLib.mkMicrovm "postgresql" { withZfs = true; } + // confLib.mkMicrovm "matrix" { withZfs = true; } + // confLib.mkMicrovm "nextcloud" { withZfs = true; } + // confLib.mkMicrovm "immich" { withZfs = true; } + // confLib.mkMicrovm "paperless" { withZfs = true; } + // confLib.mkMicrovm "transmission" { withZfs = true; } + // confLib.mkMicrovm "storage" { withZfs = true; } + // confLib.mkMicrovm "monitoring" { withZfs = true; } + // confLib.mkMicrovm "freshrss" { withZfs = true; } + // confLib.mkMicrovm "kanidm" { withZfs = true; } + // confLib.mkMicrovm "firefly" { withZfs = true; } + // confLib.mkMicrovm "koillection" { withZfs = true; } + // confLib.mkMicrovm "radicale" { withZfs = true; } + // confLib.mkMicrovm "atuin" { withZfs = true; } + // confLib.mkMicrovm "forgejo" { withZfs = true; } + // confLib.mkMicrovm "ankisync" { withZfs = true; } + // confLib.mkMicrovm "homebox" { withZfs = true; } + ); networking.nftables.firewall.zones.untrusted.interfaces = [ "lan" "bmc" ]; diff --git a/hosts/nixos/x86_64-linux/summers/guests/ankisync/default.nix b/hosts/nixos/x86_64-linux/summers/guests/ankisync/default.nix index e46d3ee..84c16b1 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/ankisync/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/ankisync/default.nix @@ -27,7 +27,7 @@ } // lib.optionalAttrs (!minimal) { microvm = { - mem = 1024 * 2; + mem = 1024 * 1; vcpu = 1; }; @@ -36,7 +36,7 @@ }; swarselmodules.server = { - ankisync = true; + # ankisync = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/atuin/default.nix b/hosts/nixos/x86_64-linux/summers/guests/atuin/default.nix index 7d4eeea..6a0e601 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/atuin/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/atuin/default.nix @@ -36,7 +36,7 @@ }; swarselmodules.server = { - atuin = true; + # atuin = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/audio/default.nix b/hosts/nixos/x86_64-linux/summers/guests/audio/default.nix index 5f2ddd6..114e332 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/audio/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/audio/default.nix @@ -36,9 +36,9 @@ }; swarselmodules.server = { - navidrome = true; - spotifyd = true; - mpd = true; + # navidrome = true; + # spotifyd = true; + # mpd = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/firefly/default.nix b/hosts/nixos/x86_64-linux/summers/guests/firefly/default.nix index 592424a..461ebff 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/firefly/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/firefly/default.nix @@ -36,8 +36,9 @@ }; swarselmodules.server = { - firefly-iii = true; - nginx = true; + # firefly-iii = true; + # nginx = true; + # acme = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/forgejo/default.nix b/hosts/nixos/x86_64-linux/summers/guests/forgejo/default.nix index 8efd8f2..f19dc48 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/forgejo/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/forgejo/default.nix @@ -27,7 +27,7 @@ } // lib.optionalAttrs (!minimal) { microvm = { - mem = 1024 * 2; + mem = 1024 * 1; vcpu = 1; }; @@ -36,7 +36,7 @@ }; swarselmodules.server = { - forgejo = true; + # forgejo = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/freshrss/default.nix b/hosts/nixos/x86_64-linux/summers/guests/freshrss/default.nix index 0d43b72..bde8bbb 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/freshrss/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/freshrss/default.nix @@ -36,8 +36,9 @@ }; swarselmodules.server = { - freshrss = true; - nginx = true; + # freshrss = true; + # nginx = true; + # acme = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/homebox/default.nix b/hosts/nixos/x86_64-linux/summers/guests/homebox/default.nix index da4d446..062c0df 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/homebox/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/homebox/default.nix @@ -27,7 +27,7 @@ } // lib.optionalAttrs (!minimal) { microvm = { - mem = 1024 * 2; + mem = 1024 * 1; vcpu = 1; }; @@ -36,7 +36,7 @@ }; swarselmodules.server = { - homebox = true; + # homebox = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/immich/default.nix b/hosts/nixos/x86_64-linux/summers/guests/immich/default.nix index b2362e4..86a4814 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/immich/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/immich/default.nix @@ -36,7 +36,7 @@ }; swarselmodules.server = { - immich = true; + # immich = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/jellyfin/default.nix b/hosts/nixos/x86_64-linux/summers/guests/jellyfin/default.nix index 7b7701b..3f80bef 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/jellyfin/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/jellyfin/default.nix @@ -27,7 +27,7 @@ } // lib.optionalAttrs (!minimal) { microvm = { - mem = 1024 * 2; + mem = 1024 * 3; vcpu = 1; }; @@ -36,7 +36,7 @@ }; swarselmodules.server = { - jellyfin = true; + # jellyfin = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/kanidm/default.nix b/hosts/nixos/x86_64-linux/summers/guests/kanidm/default.nix index 7b0f882..c70f9df 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/kanidm/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/kanidm/default.nix @@ -36,7 +36,7 @@ }; swarselmodules.server = { - kanidm = true; + # kanidm = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/kavita/default.nix b/hosts/nixos/x86_64-linux/summers/guests/kavita/default.nix index 4c06623..4a3027b 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/kavita/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/kavita/default.nix @@ -29,6 +29,7 @@ microvm = { mem = 1024 * 1; vcpu = 1; + }; swarselprofiles = { @@ -36,7 +37,7 @@ }; swarselmodules.server = { - kavita = true; + # kavita = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/koillection/default.nix b/hosts/nixos/x86_64-linux/summers/guests/koillection/default.nix index 31a62fc..cbd5f2a 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/koillection/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/koillection/default.nix @@ -27,7 +27,7 @@ } // lib.optionalAttrs (!minimal) { microvm = { - mem = 1024 * 2; + mem = 1024 * 1; vcpu = 1; }; @@ -36,7 +36,7 @@ }; swarselmodules.server = { - koillection = true; + # koillection = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/matrix/default.nix b/hosts/nixos/x86_64-linux/summers/guests/matrix/default.nix index f406585..1575ad4 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/matrix/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/matrix/default.nix @@ -36,7 +36,7 @@ }; swarselmodules.server = { - matrix = true; + # matrix = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/monitoring/default.nix b/hosts/nixos/x86_64-linux/summers/guests/monitoring/default.nix index 71dea57..d015cb2 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/monitoring/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/monitoring/default.nix @@ -27,7 +27,7 @@ } // lib.optionalAttrs (!minimal) { microvm = { - mem = 1024 * 2; + mem = 1024 * 3; vcpu = 2; }; @@ -36,7 +36,7 @@ }; swarselmodules.server = { - grafana = true; + # grafana = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/nextcloud/default.nix b/hosts/nixos/x86_64-linux/summers/guests/nextcloud/default.nix index 09bc775..d8580b0 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/nextcloud/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/nextcloud/default.nix @@ -36,8 +36,9 @@ }; swarselmodules.server = { - nextcloud = true; - nginx = true; + # nextcloud = true; + # nginx = true; + # acme = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/paperless/default.nix b/hosts/nixos/x86_64-linux/summers/guests/paperless/default.nix index fc66f5c..74fe3a6 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/paperless/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/paperless/default.nix @@ -36,7 +36,7 @@ }; swarselmodules.server = { - paperless = true; + # paperless = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/postgresql/default.nix b/hosts/nixos/x86_64-linux/summers/guests/postgresql/default.nix index 663af81..f94f5f1 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/postgresql/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/postgresql/default.nix @@ -27,7 +27,7 @@ } // lib.optionalAttrs (!minimal) { microvm = { - mem = 1024 * 2; + mem = 1024 * 1; vcpu = 1; }; @@ -36,7 +36,7 @@ }; swarselmodules.server = { - postgresql = true; + # postgresql = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/radicale/default.nix b/hosts/nixos/x86_64-linux/summers/guests/radicale/default.nix index 3bb36f9..aa70516 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/radicale/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/radicale/default.nix @@ -27,7 +27,7 @@ } // lib.optionalAttrs (!minimal) { microvm = { - mem = 1024 * 2; + mem = 1024 * 1; vcpu = 1; }; @@ -36,7 +36,7 @@ }; swarselmodules.server = { - radicale = true; + # radicale = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/storage/default.nix b/hosts/nixos/x86_64-linux/summers/guests/storage/default.nix index cfd5fd5..b6da313 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/storage/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/storage/default.nix @@ -27,7 +27,7 @@ } // lib.optionalAttrs (!minimal) { microvm = { - mem = 1024 * 2; + mem = 1024 * 4; vcpu = 2; }; @@ -36,8 +36,8 @@ }; swarselmodules.server = { - nfs = true; - syncthing = true; + # nfs = true; + # syncthing = true; }; } diff --git a/hosts/nixos/x86_64-linux/summers/guests/transmission/default.nix b/hosts/nixos/x86_64-linux/summers/guests/transmission/default.nix index e5629b8..e4e7bd3 100644 --- a/hosts/nixos/x86_64-linux/summers/guests/transmission/default.nix +++ b/hosts/nixos/x86_64-linux/summers/guests/transmission/default.nix @@ -27,7 +27,7 @@ } // lib.optionalAttrs (!minimal) { microvm = { - mem = 1024 * 2; + mem = 1024 * 4; vcpu = 2; }; @@ -36,7 +36,7 @@ }; swarselmodules.server = { - transmission = true; + # transmission = true; }; } diff --git a/hosts/nixos/x86_64-linux/winters/hardware-configuration.nix b/hosts/nixos/x86_64-linux/winters/hardware-configuration.nix index 13a956d..3222d17 100644 --- a/hosts/nixos/x86_64-linux/winters/hardware-configuration.nix +++ b/hosts/nixos/x86_64-linux/winters/hardware-configuration.nix @@ -1,4 +1,4 @@ -{ lib, modulesPath, ... }: +{ lib, config, modulesPath, ... }: { imports = diff --git a/modules/nixos/common/pii.nix b/modules/nixos/common/pii.nix index 17d8130..d10ed18 100644 --- a/modules/nixos/common/pii.nix +++ b/modules/nixos/common/pii.nix @@ -1,5 +1,5 @@ # largely based on https://github.com/oddlama/nix-config/blob/main/modules/secrets.nix -{ config, inputs, lib, nodes, ... }: +{ config, inputs, lib, nodes, globals, ... }: let # If the given expression is a bare set, it will be wrapped in a function, # so that the imported file can always be applied to the inputs, similar to @@ -53,7 +53,7 @@ in secrets = lib.mkOption { readOnly = true; - default = lib.mapAttrs (_: x: importEncrypted x { inherit lib nodes inputs; inherit (inputs.topologyPrivate) topologyPrivate; }) config.repo.secretFiles; + default = lib.mapAttrs (_: x: importEncrypted x { inherit lib nodes globals inputs; inherit (inputs.topologyPrivate) topologyPrivate; }) config.repo.secretFiles; type = lib.types.unspecified; description = "Exposes the loaded repo secrets. This option is read-only."; }; diff --git a/modules/nixos/common/users.nix b/modules/nixos/common/users.nix index 52e389a..e6c11a4 100644 --- a/modules/nixos/common/users.nix +++ b/modules/nixos/common/users.nix @@ -13,6 +13,8 @@ }; "${config.swarselsystems.mainUser}" = { isNormalUser = true; + uid = 1000; + autoSubUidGidRange = false; description = "Leon S"; password = lib.mkIf (minimal || config.swarselsystems.isPublic) "setup"; hashedPasswordFile = lib.mkIf (!minimal && !config.swarselsystems.isPublic) config.sops.secrets.main-user-hashed-pw.path; diff --git a/modules/nixos/optional/microvm-guest-shares.nix b/modules/nixos/optional/microvm-guest-shares.nix new file mode 100644 index 0000000..f6ad083 --- /dev/null +++ b/modules/nixos/optional/microvm-guest-shares.nix @@ -0,0 +1,15 @@ +{ self, lib, config, inputs, microVMParent, nodes, ... }: +{ + config = { + microvm = { + shares = [ + { + tag = "persist"; + source = "${lib.optionalString nodes.${microVMParent}.config.swarselsystems.isImpermanence "/persist"}/microvms/${config.networking.hostName}"; + mountPoint = "/persist"; + proto = "virtiofs"; + } + ]; + }; + }; +} diff --git a/modules/nixos/optional/microvm-guest.nix b/modules/nixos/optional/microvm-guest.nix index 21c29ce..28c8c91 100644 --- a/modules/nixos/optional/microvm-guest.nix +++ b/modules/nixos/optional/microvm-guest.nix @@ -1,4 +1,4 @@ -{ self, lib, config, inputs, microVMParent, nodes, ... }: +{ self, lib, config, inputs, microVMParent, nodes, globals, confLib, ... }: { imports = [ inputs.disko.nixosModules.disko @@ -49,24 +49,16 @@ }; }; - microvm = { - shares = [ - { - tag = "persist"; - source = "${lib.optionalString nodes.${microVMParent}.config.swarselsystems.isImpermanence "/persist"}/microvms/${config.networking.hostName}"; - mountPoint = "/persist"; - proto = "virtiofs"; - } - ]; - # mount the writeable overlay so that we can use nix shells inside the microvm - volumes = [ - { - image = "/tmp/nix-store-overlay-${config.networking.hostName}.img"; - autoCreate = true; - mountPoint = config.microvm.writableStoreOverlay; - size = 1024; - } - ]; - }; + # microvm = { + # mount the writeable overlay so that we can use nix shells inside the microvm + # volumes = [ + # { + # image = "/tmp/nix-store-overlay-${config.networking.hostName}.img"; + # autoCreate = true; + # mountPoint = config.microvm.writableStoreOverlay; + # size = 1024; + # } + # ]; + # }; }; } diff --git a/modules/nixos/optional/microvm-host.nix b/modules/nixos/optional/microvm-host.nix index 073353c..5d5c503 100644 --- a/modules/nixos/optional/microvm-host.nix +++ b/modules/nixos/optional/microvm-host.nix @@ -1,4 +1,4 @@ -{ config, lib, ... }: +{ config, lib, confLib, ... }: { config = lib.mkIf (config.guests != { }) { @@ -17,5 +17,7 @@ (builtins.attrNames config.guests) ); + users.persistentIds.microvm = confLib.mkIds 999; + }; } diff --git a/modules/nixos/server/acme.nix b/modules/nixos/server/acme.nix index 1bbeaec..e36bdf2 100644 --- a/modules/nixos/server/acme.nix +++ b/modules/nixos/server/acme.nix @@ -1,4 +1,4 @@ -{ self, pkgs, lib, config, globals, ... }: +{ self, pkgs, lib, config, globals, confLib, ... }: let inherit (config.repo.secrets.common) dnsProvider dnsBase dnsMail; @@ -21,7 +21,10 @@ in ''; }; - users.groups.acme.members = lib.mkIf config.swarselmodules.server.nginx [ "nginx" ]; + users = { + persistentIds.acme = confLib.mkIds 967; + groups.acme.members = lib.mkIf config.swarselmodules.server.nginx [ "nginx" ]; + }; security.acme = { acceptTerms = true; diff --git a/modules/nixos/server/disk-encrypt.nix b/modules/nixos/server/disk-encrypt.nix index 8a8ea3e..d5dde08 100644 --- a/modules/nixos/server/disk-encrypt.nix +++ b/modules/nixos/server/disk-encrypt.nix @@ -45,9 +45,9 @@ in }; boot = lib.mkIf (!config.swarselsystems.isClient) { - kernelParams = lib.mkIf (!config.swarselsystems.isCloud && ((config.swarselsystems.localVLANs == [ ]) || isRouter)) [ - "ip=${localIp}::${gatewayIp}:${subnetMask}:${config.networking.hostName}::none" - ]; + # kernelParams = lib.mkIf (!config.swarselsystems.isCloud && ((config.swarselsystems.localVLANs == []) || isRouter)) [ + # "ip=${localIp}::${gatewayIp}:${subnetMask}:${config.networking.hostName}::none" + # ]; initrd = { secrets."/tmp${hostKeyPathBase}" = if minimal then (lib.mkForce generatedHostKey) else (lib.mkForce hostKeyPath); # need to mkForce this or it behaves stateful availableKernelModules = config.swarselsystems.networkKernelModules; diff --git a/modules/nixos/server/firefly-iii.nix b/modules/nixos/server/firefly-iii.nix index f1ed188..cf77b73 100644 --- a/modules/nixos/server/firefly-iii.nix +++ b/modules/nixos/server/firefly-iii.nix @@ -13,6 +13,9 @@ in config = lib.mkIf config.swarselmodules.server.${serviceName} { users = { + persistentIds = { + firefly-iii = confLib.mkIds 983; + }; groups.${serviceGroup} = { }; users.${serviceUser} = { group = lib.mkForce serviceGroup; diff --git a/modules/nixos/server/forgejo.nix b/modules/nixos/server/forgejo.nix index ea246b1..5ae8125 100644 --- a/modules/nixos/server/forgejo.nix +++ b/modules/nixos/server/forgejo.nix @@ -12,9 +12,14 @@ in # networking.firewall.allowedTCPPorts = [ servicePort ]; - users.users.${serviceUser} = { - group = serviceGroup; - isSystemUser = true; + users = { + persistentIds = { + forgejo = confLib.mkIds 985; + }; + users.${serviceUser} = { + group = serviceGroup; + isSystemUser = true; + }; }; users.groups.${serviceGroup} = { }; diff --git a/modules/nixos/server/freshrss.nix b/modules/nixos/server/freshrss.nix index dd764b4..df0a809 100644 --- a/modules/nixos/server/freshrss.nix +++ b/modules/nixos/server/freshrss.nix @@ -9,10 +9,15 @@ in options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { - users.users.${serviceUser} = { - extraGroups = [ "users" ]; - group = serviceGroup; - isSystemUser = true; + users = { + persistentIds = { + freshrss = confLib.mkIds 986; + }; + users.${serviceUser} = { + extraGroups = [ "users" ]; + group = serviceGroup; + isSystemUser = true; + }; }; users.groups.${serviceGroup} = { }; diff --git a/modules/nixos/server/homebox.nix b/modules/nixos/server/homebox.nix index 468ce7d..5325cce 100644 --- a/modules/nixos/server/homebox.nix +++ b/modules/nixos/server/homebox.nix @@ -13,6 +13,10 @@ in icon = "${self}/files/topology-images/${serviceName}.png"; }; + users.persistentIds = { + homebox = confLib.mkIds 981; + }; + globals = { networks = { ${webProxyIf}.hosts = lib.mkIf isProxied { @@ -29,14 +33,25 @@ in }; }; + systemd.services.homebox = { + environment = { + TMPDIR = "/var/lib/homebox/.tmp"; + }; + serviceConfig = { + # ReadWritePaths = "/var/lib/homebox"; + RuntimeDirectory = "homebox"; + BindPaths = "/run/homebox:/var/lib/homebox/.tmp"; + }; + }; + services.${serviceName} = { enable = true; - package = pkgs.dev.homebox; + package = pkgs.bisect.homebox; database.createLocally = true; settings = { HBOX_WEB_PORT = builtins.toString servicePort; HBOX_OPTIONS_ALLOW_REGISTRATION = "false"; - HBOX_STORAGE_CONN_STRING = "file:///Vault/data/homebox"; + HBOX_STORAGE_CONN_STRING = "file:///var/lib/homebox"; HBOX_STORAGE_PREFIX_PATH = ".data"; }; }; diff --git a/modules/nixos/server/id.nix b/modules/nixos/server/id.nix new file mode 100644 index 0000000..f6db715 --- /dev/null +++ b/modules/nixos/server/id.nix @@ -0,0 +1,103 @@ +{ lib, config, confLib, ... }: +let + inherit (lib) + concatLists + flip + mapAttrsToList + mkDefault + mkIf + mkOption + types + ; + + cfg = config.users.persistentIds; +in +{ + options = { + swarselmodules.server.ids = lib.mkEnableOption "enable persistent ids on server"; + users.persistentIds = mkOption { + default = { }; + description = '' + Maps a user or group name to its expected uid/gid values. If a user/group is + used on the system without specifying a uid/gid, this module will assign the + corresponding ids defined here, or show an error if the definition is missing. + ''; + type = types.attrsOf ( + types.submodule { + options = { + uid = mkOption { + type = types.nullOr types.int; + default = null; + description = "The uid to assign if it is missing in `users.users.`."; + }; + gid = mkOption { + type = types.nullOr types.int; + default = null; + description = "The gid to assign if it is missing in `users.groups.`."; + }; + }; + } + ); + }; + + users.users = mkOption { + type = types.attrsOf ( + types.submodule ( + { name, ... }: + { + config.uid = + let + persistentUid = cfg.${name}.uid or null; + in + mkIf (persistentUid != null) (mkDefault persistentUid); + } + ) + ); + }; + + users.groups = mkOption { + type = types.attrsOf ( + types.submodule ( + { name, ... }: + { + config.gid = + let + persistentGid = cfg.${name}.gid or null; + in + mkIf (persistentGid != null) (mkDefault persistentGid); + } + ) + ); + }; + }; + config = lib.mkIf config.swarselmodules.server.ids { + assertions = + concatLists + ( + flip mapAttrsToList config.users.users ( + name: user: [ + { + assertion = user.uid != null; + message = "non-persistent uid detected for '${name}', please assign one via `users.persistentIds`"; + } + { + assertion = !user.autoSubUidGidRange; + message = "non-persistent subUids/subGids detected for: ${name}"; + } + ] + ) + ) + ++ flip mapAttrsToList config.users.groups ( + name: group: { + assertion = group.gid != null; + message = "non-persistent gid detected for '${name}', please assign one via `users.persistentIds`"; + } + ); + users.persistentIds = { + systemd-coredump = confLib.mkIds 998; + systemd-oom = confLib.mkIds 997; + polkituser = confLib.mkIds 973; + nscd = confLib.mkIds 972; + }; + }; +} diff --git a/modules/nixos/server/immich.nix b/modules/nixos/server/immich.nix index bdbc739..568b516 100644 --- a/modules/nixos/server/immich.nix +++ b/modules/nixos/server/immich.nix @@ -7,8 +7,14 @@ in options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { - users.users.${serviceUser} = { - extraGroups = [ "video" "render" "users" ]; + users = { + persistentIds = { + immich = confLib.mkIds 989; + redis-immich = confLib.mkIds 977; + }; + users.${serviceUser} = { + extraGroups = [ "video" "render" "users" ]; + }; }; topology.self.services.${serviceName}.info = "https://${serviceDomain}"; diff --git a/modules/nixos/server/jellyfin.nix b/modules/nixos/server/jellyfin.nix index 4c2a972..fcd9910 100644 --- a/modules/nixos/server/jellyfin.nix +++ b/modules/nixos/server/jellyfin.nix @@ -7,10 +7,12 @@ in options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { - users.users.${serviceUser} = { - extraGroups = [ "video" "render" "users" ]; + users = { + persistentIds.jellyfin = confLib.mkIds 994; + users.${serviceUser} = { + extraGroups = [ "video" "render" "users" ]; + }; }; - # nixpkgs.config.packageOverrides = pkgs: { # intel-vaapi-driver = pkgs.intel-vaapi-driver.override { enableHybridCodec = true; }; # }; diff --git a/modules/nixos/server/kanidm.nix b/modules/nixos/server/kanidm.nix index bdf247b..17dd259 100644 --- a/modules/nixos/server/kanidm.nix +++ b/modules/nixos/server/kanidm.nix @@ -34,6 +34,9 @@ in users = { + persistentIds = { + kanidm = confLib.mkIds 984; + }; users.${serviceUser} = { group = serviceGroup; isSystemUser = true; diff --git a/modules/nixos/server/kavita.nix b/modules/nixos/server/kavita.nix index f952f49..ce6bf10 100644 --- a/modules/nixos/server/kavita.nix +++ b/modules/nixos/server/kavita.nix @@ -12,11 +12,14 @@ in calibre ]; - - users.users.${serviceUser} = { - extraGroups = [ "users" ]; + users = { + persistentIds.kavita = confLib.mkIds 995; + users.${serviceUser} = { + extraGroups = [ "users" ]; + }; }; + sops.secrets.kavita-token = { inherit sopsFile; owner = serviceUser; }; # networking.firewall.allowedTCPPorts = [ servicePort ]; diff --git a/modules/nixos/server/kea.nix b/modules/nixos/server/kea.nix index 93eee37..21c4228 100644 --- a/modules/nixos/server/kea.nix +++ b/modules/nixos/server/kea.nix @@ -82,6 +82,8 @@ in { directory = serviceDir; mode = "0700"; } ]; + users.persistentIds.kea = confLib.mkIds 968; + topology = { extractors.kea.enable = false; self.services.${serviceName} = { diff --git a/modules/nixos/server/matrix.nix b/modules/nixos/server/matrix.nix index a2a7aba..c77caa7 100644 --- a/modules/nixos/server/matrix.nix +++ b/modules/nixos/server/matrix.nix @@ -314,6 +314,11 @@ in # restart the bridges daily. this is done for the signal bridge mainly which stops carrying # messages out after a while. + users.persistentIds = { + mautrix-signal = confLib.mkIds 993; + mautrix-whatsapp = confLib.mkIds 992; + mautrix-telegram = confLib.mkIds 991; + }; nodes = let diff --git a/modules/nixos/server/monitoring.nix b/modules/nixos/server/monitoring.nix index 3e4e3b3..a74489e 100644 --- a/modules/nixos/server/monitoring.nix +++ b/modules/nixos/server/monitoring.nix @@ -42,6 +42,11 @@ in }; users = { + persistentIds = { + nextcloud-exporter = confLib.mkIds 988; + node-exporter = confLib.mkIds 987; + grafana = confLib.mkIds 974; + }; users = { nextcloud-exporter = { extraGroups = [ "nextcloud" ]; diff --git a/modules/nixos/server/nextcloud.nix b/modules/nixos/server/nextcloud.nix index 5b9bdda..c91e79a 100644 --- a/modules/nixos/server/nextcloud.nix +++ b/modules/nixos/server/nextcloud.nix @@ -16,6 +16,11 @@ in kanidm-nextcloud-client = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; }; + users.persistentIds = { + nextcloud = confLib.mkIds 990; + redis-nextcloud = confLib.mkIds 976; + }; + globals.services.${serviceName} = { domain = serviceDomain; inherit proxyAddress4 proxyAddress6 isHome serviceAddress; diff --git a/modules/nixos/server/nfs.nix b/modules/nixos/server/nfs.nix index 746a583..fb6a776 100644 --- a/modules/nixos/server/nfs.nix +++ b/modules/nixos/server/nfs.nix @@ -1,10 +1,15 @@ -{ lib, config, pkgs, globals, ... }: +{ lib, config, pkgs, globals, confLib, ... }: let nfsUser = globals.user.name; in { options.swarselmodules.server.nfs = lib.mkEnableOption "enable nfs on server"; config = lib.mkIf config.swarselmodules.server.nfs { + + users.persistentIds = { + avahi = confLib.mkIds 978; + }; + services = { # add a user with sudo smbpasswd -a samba = { diff --git a/modules/nixos/server/opkssh.nix b/modules/nixos/server/opkssh.nix index 178e3d7..597240d 100644 --- a/modules/nixos/server/opkssh.nix +++ b/modules/nixos/server/opkssh.nix @@ -11,6 +11,9 @@ in options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { + users.persistentIds = { + opksshuser = confLib.mkIds 980; + }; services.${serviceName} = { enable = true; diff --git a/modules/nixos/server/paperless.nix b/modules/nixos/server/paperless.nix index 0bd12f6..0d119a5 100644 --- a/modules/nixos/server/paperless.nix +++ b/modules/nixos/server/paperless.nix @@ -12,8 +12,13 @@ in options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { - users.users.${serviceUser} = { - extraGroups = [ "users" ]; + users = { + persistentIds = { + redis-paperless = confLib.mkIds 975; + }; + users.${serviceUser} = { + extraGroups = [ "users" ]; + }; }; sops.secrets = { diff --git a/modules/nixos/server/pipewire.nix b/modules/nixos/server/pipewire.nix index b6b315a..41a602d 100644 --- a/modules/nixos/server/pipewire.nix +++ b/modules/nixos/server/pipewire.nix @@ -1,9 +1,11 @@ -{ lib, config, ... }: +{ lib, config, confLib, ... }: { - config = lib.mkIf (config?swarselmodules.server.mpd || config?swarselmodules.server.navidrome) { + config = lib.mkIf (config.swarselmodules.server.mpd || config.swarselmodules.server.navidrome) { security.rtkit.enable = true; # this is required for pipewire real-time access + users.persistentIds.rtkit = confLib.mkIds 996; + services.pipewire = { enable = true; pulse.enable = true; diff --git a/modules/nixos/server/podman.nix b/modules/nixos/server/podman.nix index 192e0c3..0a27be5 100644 --- a/modules/nixos/server/podman.nix +++ b/modules/nixos/server/podman.nix @@ -1,4 +1,4 @@ -{ config, lib, ... }: +{ config, lib, confLib, ... }: let serviceName = "podman"; in @@ -6,6 +6,10 @@ in options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; config = lib.mkIf config.swarselmodules.server.${serviceName} { + users.persistentIds = { + podman = confLib.mkIds 969; + }; + virtualisation = { podman.enable = true; oci-containers.backend = "podman"; diff --git a/modules/nixos/server/radicale.nix b/modules/nixos/server/radicale.nix index ed09675..5953bdc 100644 --- a/modules/nixos/server/radicale.nix +++ b/modules/nixos/server/radicale.nix @@ -29,6 +29,10 @@ in }; }; + users.persistentIds = { + radicale = confLib.mkIds 982; + }; + topology.self.services.${serviceName}.info = "https://${serviceDomain}"; globals = { diff --git a/modules/nixos/server/restic.nix b/modules/nixos/server/restic.nix index cb5c046..2b0bd01 100644 --- a/modules/nixos/server/restic.nix +++ b/modules/nixos/server/restic.nix @@ -11,6 +11,10 @@ in paths = lib.mkOption { type = lib.types.listOf lib.types.str; }; + withPostgres = lib.mkOption { + type = lib.types.bool; + default = false; + }; }; config = lib.mkIf config.swarselmodules.server.restic { diff --git a/modules/nixos/server/ssh.nix b/modules/nixos/server/ssh.nix index 877552a..22a2204 100644 --- a/modules/nixos/server/ssh.nix +++ b/modules/nixos/server/ssh.nix @@ -1,4 +1,4 @@ -{ self, lib, config, withHomeManager, ... }: +{ self, lib, config, withHomeManager, confLib, ... }: { options.swarselmodules.server.ssh = lib.mkEnableOption "enable ssh on server"; config = lib.mkIf config.swarselmodules.server.ssh { @@ -21,17 +21,22 @@ } ]; }; - users.users = { - "${config.swarselsystems.mainUser}".openssh.authorizedKeys.keyFiles = lib.mkIf withHomeManager [ - (self + /secrets/public/ssh/yubikey.pub) - (self + /secrets/public/ssh/magicant.pub) - # (lib.mkIf config.swarselsystems.isBastionTarget (self + /secrets/public/ssh/jump.pub)) - ]; - root.openssh.authorizedKeys.keyFiles = [ - (self + /secrets/public/ssh/yubikey.pub) - (self + /secrets/public/ssh/magicant.pub) - # (lib.mkIf config.swarselsystems.isBastionTarget (self + /secrets/public/ssh/jump.pub)) - ]; + users = { + persistentIds = { + sshd = lib.mkIf config.swarselmodules.server.ids (confLib.mkIds 979); + }; + users = { + "${config.swarselsystems.mainUser}".openssh.authorizedKeys.keyFiles = lib.mkIf withHomeManager [ + (self + /secrets/public/ssh/yubikey.pub) + (self + /secrets/public/ssh/magicant.pub) + # (lib.mkIf config.swarselsystems.isBastionTarget (self + /secrets/public/ssh/jump.pub)) + ]; + root.openssh.authorizedKeys.keyFiles = [ + (self + /secrets/public/ssh/yubikey.pub) + (self + /secrets/public/ssh/magicant.pub) + # (lib.mkIf config.swarselsystems.isBastionTarget (self + /secrets/public/ssh/jump.pub)) + ]; + }; }; security.sudo.extraConfig = '' Defaults env_keep+=SSH_AUTH_SOCK diff --git a/modules/nixos/server/transmission.nix b/modules/nixos/server/transmission.nix index 8d53c9a..c3f8e4c 100644 --- a/modules/nixos/server/transmission.nix +++ b/modules/nixos/server/transmission.nix @@ -25,6 +25,10 @@ in # this user/group section is probably unneeded users = { + persistentIds = { + prowlarr = confLib.mkIds 971; + readarr = confLib.mkIds 970; + }; groups = { dockeruser = { gid = 1155; diff --git a/modules/shared/config-lib.nix b/modules/shared/config-lib.nix index 9f91ae2..4439036 100644 --- a/modules/shared/config-lib.nix +++ b/modules/shared/config-lib.nix @@ -53,44 +53,104 @@ in homeServiceAddress = lib.optionalString (config.swarselsystems.server.wireguard.interfaces ? wgHome) globals.networks."${config.swarselsystems.server.wireguard.interfaces.wgHome.serverNetConfigPrefix}-wgHome".hosts.${config.node.name}.ipv4; }; + mkIds = id: { + uid = id; + gid = id; + }; + + mkDeviceMac = id: + let + mod = n: d: n - (n / d) * d; + toHexByte = n: + let + hex = "0123456789abcdef"; + hi = n / 16; + lo = mod n 16; + in + builtins.substring hi 1 hex + + builtins.substring lo 1 hex; + + max = 16777215; # 256^3 - 1 + + b1 = id / (256 * 256); + r1 = mod id (256 * 256); + b2 = r1 / 256; + b3 = mod r1 256; + in + if + (id <= max) + then + (builtins.concatStringsSep ":" + (map toHexByte [ b1 b2 b3 ])) + else + (throw "Device MAC ID too large (max is 16777215)"); + mkMicrovm = if config.swarselsystems.withMicroVMs then - (guestName: { - ${guestName} = { - backend = "microvm"; - autostart = true; - modules = [ - (config.node.configDir + /guests/${guestName}/default.nix) - { - node.secretsDir = config.node.configDir + /secrets/${guestName}; - node.configDir = config.node.configDir + /guests/${guestName}; - networking.nftables.firewall = { - zones.untrusted.interfaces = lib.mkIf - ( - lib.length config.guests.${guestName}.networking.links == 1 - ) - config.guests.${guestName}.networking.links; + (guestName: + { enableStorage ? false + , withZfs ? false + , ... + }: + { + ${guestName} = { + backend = "microvm"; + autostart = true; + zfs = lib.mkIf withZfs { + # stateful config that should be backed up + "/state" = { + pool = "Vault"; + dataset = "guests/${guestName}/state"; }; - } - "${self}/modules/nixos/optional/microvm-guest.nix" - "${self}/modules/nixos/optional/systemd-networkd-base.nix" - ]; - microvm = { - system = config.node.arch; - baseMac = config.repo.secrets.local.networking.networks.lan.mac; - interfaces.vlan-services = { }; + # data that should be backed up + "/storage" = lib.mkIf enableStorage { + pool = "Vault"; + dataset = "guests/${guestName}/storage"; + }; + # other stuff that should only reside on disk, not backed up + "/persist" = { + pool = "Vault"; + dataset = "guests/${guestName}/persist"; + }; + }; + modules = [ + (config.node.configDir + /guests/${guestName}/default.nix) + { + node.secretsDir = config.node.configDir + /secrets/${guestName}; + node.configDir = config.node.configDir + /guests/${guestName}; + networking.nftables.firewall = { + zones.untrusted.interfaces = lib.mkIf + ( + lib.length config.guests.${guestName}.networking.links == 1 + ) + config.guests.${guestName}.networking.links; + }; + } + "${self}/modules/nixos/optional/microvm-guest.nix" + "${self}/modules/nixos/optional/systemd-networkd-base.nix" + ]; + microvm = { + system = config.node.arch; + baseMac = config.repo.secrets.local.networking.networks.lan.mac; + interfaces.vlan-services = { + mac = lib.mkForce "02:${lib.substring 3 5 config.guests.${guestName}.microvm.baseMac}:${mkDeviceMac globals.networks.home-lan.vlans.services.hosts."${config.node.name}-${guestName}".id}"; + + }; + }; + extraSpecialArgs = { + inherit (inputs.self) nodes; + inherit (inputs.self.pkgs.${config.node.arch}) lib; + inherit inputs outputs minimal; + inherit (inputs) self; + withHomeManager = false; + microVMParent = config.node.name; + globals = inputs.self.globals.${config.node.arch}; + }; }; - extraSpecialArgs = { - inherit (inputs.self) nodes; - inherit (inputs.self.pkgs.${config.node.arch}) lib; - inherit inputs outputs minimal; - inherit (inputs) self; - withHomeManager = false; - microVMParent = config.node.name; - globals = inputs.self.globals.${config.node.arch}; - }; - }; - }) else (_: { _ = { }; }); + }) else + (_: { + _ = { }; + }); genNginx = { serviceAddress diff --git a/profiles/nixos/localserver/default.nix b/profiles/nixos/localserver/default.nix index 7de318e..8ff0411 100644 --- a/profiles/nixos/localserver/default.nix +++ b/profiles/nixos/localserver/default.nix @@ -17,6 +17,7 @@ nftables = lib.mkDefault true; server = { general = lib.mkDefault true; + ids = lib.mkDefault true; network = lib.mkDefault true; diskEncryption = lib.mkDefault true; packages = lib.mkDefault true; diff --git a/profiles/nixos/microvm/default.nix b/profiles/nixos/microvm/default.nix index 689bbbf..226edc7 100644 --- a/profiles/nixos/microvm/default.nix +++ b/profiles/nixos/microvm/default.nix @@ -18,6 +18,7 @@ nftables = lib.mkDefault true; server = { general = lib.mkDefault true; + ids = lib.mkDefault true; packages = lib.mkDefault true; ssh = lib.mkDefault true; wireguard = lib.mkDefault true; diff --git a/secrets/repo/pii.nix.enc b/secrets/repo/pii.nix.enc index 7dbf7b6..f2d6444 100644 --- a/secrets/repo/pii.nix.enc +++ b/secrets/repo/pii.nix.enc @@ -1,5 +1,5 @@ { - "data": "ENC[AES256_GCM,data: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,iv:6cj17MfBuVgr3MEEOGcU7IhGnxJA3jhkduRzgK2IHjU=,tag:bOsZVs+51ojqIZA9V2Dk3w==,type:str]", + "data": "ENC[AES256_GCM,data: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,iv:uO2n6uM8pG16CzQoRGpqqRp9CpSALkzFGnVdgGSeMS0=,tag:yPHLjZ+spz2djJuzg11U9A==,type:str]", "sops": { "age": [ { @@ -63,8 +63,8 @@ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1RGpibkIreUVYNlA2TXUw\nNmZzdnFtNHNOQ21QTE5ycTZHaFU0U0d3RzFnClFXRGFlZnB1WjRBZW5WN1BSR3dK\nY0Q4R3FGdEQycDEranUzWFJyWWVwOWMKLS0tIHp1Rm0wdi94Tk9kM3crWUtjb2Vo\nSHU4ay9WenpGTTg5T2Y1TzVicHBPZWMKEpeP/SVorT881MiLvR+6O9lcc9Fn0VV9\n5PqcowYMKFFXBQ27qjoFBDSwmD0UxpUgJeMtMAL+QLMILZ+G/0EcGw==\n-----END AGE ENCRYPTED FILE-----\n" } ], - "lastmodified": "2026-01-09T13:03:32Z", - "mac": "ENC[AES256_GCM,data:1IPWZKNuDEObu7tuBZ5WiwWhx3srmudOiZFVFh27zfr7N5sGG2VAQGOCYgw8e8SuscUyyHRcw1uPuXGy0gB+ITX/kcClwJNqdT/ZvDvmP9zDAQMSAkwA+3xUBlobkabtj4+txtAc4xYleXIZN/22hpyeHJ1bOHaHNw+Zm2elk5Q=,iv:NL8trDkA+lMLnQqgrzsb31Tglvc6PtFky+vvSA6yIKY=,tag:S4BcowZWKscT2y1/OtZ86g==,type:str]", + "lastmodified": "2026-01-12T20:26:18Z", + "mac": "ENC[AES256_GCM,data:jIB7rrK4yYjLlqUdl10JfYg3qaAYbuePPjZoGCBCCaohFdTWJPDoJMg5EFMFrZIDVOeWDjYVh6bB+PvXiIvU39NrEymS/Gu50ehCG7Lls7a90K+NSZQhuHS1y91+93t8vOq3kPisN0fh0J9tJwphB/NbmgDrE5e/NQsA4FjOsWU=,iv:VITEc80bKA5ZXuy9iUz7NjobYvVDKXDWhnXFyFwy84c=,tag:POCbrUFiKcc0418v9njPNw==,type:str]", "pgp": [ { "created_at": "2026-01-10T00:52:57Z",