Compare commits

..

2 commits

Author SHA1 Message Date
Leon Schwarzäugl
21c1067572
feat: make yubikey pam work on all machines
Some checks failed
Flake check / Check flake (push) Has been cancelled
2025-07-14 04:15:14 +02:00
Leon Schwarzäugl
18a2a32bae
docs[flake]: more verbose documentation 2025-07-14 03:07:23 +02:00
9 changed files with 380 additions and 345 deletions

View file

@ -290,22 +290,23 @@ Here I give a brief overview over the hostmachines that I am using. This is held
:CUSTOM_ID: h:c7588c0d-2528-485d-b2df-04d6336428d7 :CUSTOM_ID: h:c7588c0d-2528-485d-b2df-04d6336428d7
:END: :END:
Handling the flake.nix file used to be a bit of a chore, since it felt like writing so much boilerplate code just to define new systems. The noweb-approach here makes this a little bit less painful. Handling the flake.nix file used to be a bit of a chore, since it felt like writing so much boilerplate code just to define new systems. For a while, I used noweb-ref in order to alleviate this problem (see [[#h:dae0c5bb-edb7-4fe4-ae31-9f8f064cc53c][Appendix A: Noweb-Ref blocks]], an example of the repository at that time would be =acc0ad6: Add several NixOS hosts on Proxmox and Oracle Cloud=.). However, the true answer laid in making use of builtin nix functionality.
These blocks are later inserted here: [[#h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b][flake.nix template]]. Adding new flake inputs is very easy, you just add them to [[#h:8a411ee2-a58e-4b5b-99bd-4ba772f8f0a2][Inputs & Inputs@Outputs]] first by name in the first source-block, and then the path in the second source-block. Any variables to be set for the host configuration are done in [[#h:df0072bc-853f-438f-bd85-bfc869501015][let]], and the specific setup is done in either [[#h:9c9b9e3b-8771-44fa-ba9e-5056ae809655][nixosConfigurations]] (for NixOS systems), [[#h:f881aa05-a670-48dd-a57b-2916abdcb692][homeConfigurations]] (for home-manager systems), or [[#h:5f6ef553-59f9-4239-b6f3-63d33b57f335][nixOnDroidConfigurations]] (for Nix on Android) and [[#h:f881aa05-a670-48dd-a57b-2916abdcb692][darwinConfigurations]] (for Darwin systems, also known as Macs). There also used to be a [[#h:6a08495a-8566-4bb5-9fac-b03df01f6c81][nixos-generators]] section that used to define a Proxmox LXC image when I was still using Proxmox as my main server. An example of the repository at that time would be =acc0ad6: Add several NixOS hosts on Proxmox and Oracle Cloud=. Nowadays, I use flake-parts to manage my flake. It allows me to conveniently split the actual flake into multiple files ("parts") using the following mechanism:
- =imports= are files pulled in to build the flake configuration (similar to the imports in the module system)
- =systems= defines the architectures that the flake should be provided for - I go here for the four "main" architectures, although true support is only provided for linux systems (see [[#h:6ed1a641-dba8-4e85-a62e-be93264df57a][Packages (pkgs)]] for the main reason)
** flake.nix skeleton ** flake.nix skeleton
:PROPERTIES: :PROPERTIES:
:CUSTOM_ID: h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b :CUSTOM_ID: h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b
:END: :END:
This sections puts together the =flake.nix= file from the [[#h:d39b8dfb-536d-414f-9fc0-7d67df48cee4][Noweb-Ref blocks]] section. This tangles the flake.nix file; This block only needs to be touched when updating the general structure of the flake. For everything else, see the respective noweb-ref block. In general, a nix flake consists of one or more inputs and several outputs. The inputs are used to define where nix should be looking for packages, modules, and more. The outputs generate expressions that can be used in .nix files as well as system configurations using these files.
In general, a nix flake consists of one or more inputs and several outputs. The inputs are used to define where nix should be looking for packages, options, and more. The outputs generate expressions that can be used in .nix files as well as system configurations using these files. In the start, I enable some public cache repositories. This saves some time during rebuilds because it avoids building as many packages from scratch - this is mainly important for community flakes like =emacs-overlay=, which basically would trigger a rebuild whenever updating the flake. The repository does of course not hold everything, but it lightens the pain. It would look cleaner if this were to be used only inside a nix configuration block of an actual system, but I want these caches to be used for e.g. app calls as well.
In the start, I enable some public cache repositories. This saves some time during rebuilds because it avoids building as many packages from scratch - this is mainly important for community flakes like =emacs-overlay=, which basically would trigger a rebuild whenever updating the flake. The repository does of course not hold everything, but it lightens the pain. In many flakes, you see a structure like this: =outputs = inputs@ [...]=, the =inputs@= makes it so that all inputs are automatically passed to the outputs and can be called as =inputs.<name>=, whereas explicit arguments may just be called by using =<name>=. For most flakes this is fully sufficient, as they do not need to be called often and it saves me maintainance effort with this file. In fact, I also used to make use of this mechanism. However, using flake-parts, all I really need for the outputs function is inputs, which is why my outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } { [...] ). Note that flake-parts must inherit these inputs and no other arguments are expected.
In =outputs = inputs@ [...]=, the =inputs@= makes it so that all inputs are automatically passed to the outputs and can be called as =inputs.<name>=, whereas explicit arguments may just be called by using =<name>=. For most flakes this is fully sufficient, as they do not need to be called often and it saves me maintainance effort with this file.
In this section I am creating some attributes that define general concepts of my configuration: In this section I am creating some attributes that define general concepts of my configuration:
@ -349,8 +350,6 @@ A short overview over each input and what it does:
This brings nix to android in an app that is similar to tmux! Of course most of the configuration does not apply to this, but it is still neat to have! This brings nix to android in an app that is similar to tmux! Of course most of the configuration does not apply to this, but it is still neat to have!
- [[https://github.com/NixOS/nixos-hardware][nixos-hardware]] - [[https://github.com/NixOS/nixos-hardware][nixos-hardware]]
Provides specific hardware setting for some hardware configurations. For example, this sets some better defaults for my Lenovo Thinkpad P14s Gen2. Provides specific hardware setting for some hardware configurations. For example, this sets some better defaults for my Lenovo Thinkpad P14s Gen2.
- [[https://github.com/thiagokokada/nix-alien][nix-alien]]
This is supposed to allow me to run unpatched libraries directly without a need for ELF patching or resorting to =steam-run=. However, I have not yet gotten this to work.
- [[https://github.com/nix-community/nixos-generators][nixos-generators]] - [[https://github.com/nix-community/nixos-generators][nixos-generators]]
Provides me with images that I can use to create LXCs on Proxmox. Provides me with images that I can use to create LXCs on Proxmox.
- [[https://github.com/Swarsel/nswitch-rcm-nix][nswitch-rcm-nix]] - [[https://github.com/Swarsel/nswitch-rcm-nix][nswitch-rcm-nix]]
@ -369,12 +368,12 @@ A short overview over each input and what it does:
After learning that MacOS systems can also be configured using nix, I managed to get access to an old MacBook for testing. This allows to set most general settings that can otherwise be set using the Mac GUI. After learning that MacOS systems can also be configured using nix, I managed to get access to an old MacBook for testing. This allows to set most general settings that can otherwise be set using the Mac GUI.
- [[https://github.com/cachix/git-hooks.nix][pre-commit-hooks]] - [[https://github.com/cachix/git-hooks.nix][pre-commit-hooks]]
Provides access to several checks that can be hooked to be run before several stages in the process. Provides access to several checks that can be hooked to be run before several stages in the process.
- nix-secrets
This is a private repository that I use for settings in modules that do not expose a =secretsFile= (or similar) option. An example is the =LastFM.ApiKey= option in [[#h:f347f3ad-5100-4c4f-8616-cfd7f8e14a72][navidrome]]:
=LastFM.ApiKey = builtins.readFile "${secretsDirectory}/navidrome/lastfm-secret";=
When setting this option normally, the password would normally be written world-readable not only in the nix store, but also in the configuration. Hence, I put such passwords into a private repository. This allows me to keep purity of the flake while keeping a level of security on these secrets.
- [[https://github.com/oddlama/nix-topology][nix-topology]] - [[https://github.com/oddlama/nix-topology][nix-topology]]
This automatically creates a topology diagram of my configuration. This automatically creates a topology diagram of my configuration.
- flake-parts
The aforementioned system that allows for more convenient flake crafting.
- devshell
This provides devshell support for flake-parts
#+begin_src nix :noweb yes :tangle flake.nix #+begin_src nix :noweb yes :tangle flake.nix
{ {
@ -422,9 +421,6 @@ When setting this option normally, the password would normally be written world-
nixos-hardware = { nixos-hardware = {
url = "github:NixOS/nixos-hardware/master"; url = "github:NixOS/nixos-hardware/master";
}; };
nix-alien = {
url = "github:thiagokokada/nix-alien";
};
nswitch-rcm-nix = { nswitch-rcm-nix = {
url = "github:Swarsel/nswitch-rcm-nix"; url = "github:Swarsel/nswitch-rcm-nix";
}; };
@ -493,11 +489,23 @@ When setting this option normally, the password would normally be written world-
:PROPERTIES: :PROPERTIES:
:CUSTOM_ID: h:23602ad9-91f6-4eba-943a-2308070fbaec :CUSTOM_ID: h:23602ad9-91f6-4eba-943a-2308070fbaec
:END: :END:
Here I define some extra files that are crucial for success in building my configurations. These are not pulled in by the flake directly, but I still feel like they should be mentioned at the flake level.
*** extra-builtins *** extra-builtins
:PROPERTIES: :PROPERTIES:
:CUSTOM_ID: h:87c7893e-e946-4fc0-8973-1ca27d15cf0e :CUSTOM_ID: h:87c7893e-e946-4fc0-8973-1ca27d15cf0e
:END: :END:
This file is used by [[https://github.com/shlevy/nix-plugins][nix-plugins]]. nix-plugins generally allows for the introduction of arbitrary functions into the =builtins= set. However, I do not want to allow just any function to be added there. Instead, I only add a single function called =sopsImportEncrypted=. This function is used in order to help me store PII (personally identifiable information) in my repo without having to resort to either:
- [[https://github.com/AGWA/git-crypt][git-crypt]]
- a separate repo containing my secrets
As for the second approach, I actually used this up to some point (see for example =7e11641: feat: add initial oauth2-proxy and freshrss oidc= as one of the lasts commits still using this system). However, it is quite bothersome to constantly have to keep two repositories up to date and in sync. Also, having a repo that every configuration relied upon that was also a private repo led to the problem that my demo configuration ([[#h:e1498bef-ec67-483d-bf02-76264e30be8e][ChaosTheatre (Demo Physical/VM)]]) would fail to build with that present, and I had to take several extra steps to make it buildable. Ever since deleting that dependency I also got rid of that problem. The whole system is inspired by [[https://oddlama.org/blog/evaluation-time-secrets-in-nix/][this blog article]] and large parts of it are adapted from [[https://github.com/oddlama/nix-config][oddlama's nix-config]].
The builtin that is added is a simple call to the =exec= function that calls a bash script. In order to keep some sanity, we are checking that we are actually calling it no an encryted nix file (even though there is no syntax check inside) and that the path given is a true nix path. Note that a string path will not be accepted, as that can have impurity implications.
#+begin_src nix-ts :tangle nix/extra-builtins.nix #+begin_src nix-ts :tangle nix/extra-builtins.nix
# adapted from https://github.com/oddlama/nix-config/blob/main/nix/extra-builtins.nix # adapted from https://github.com/oddlama/nix-config/blob/main/nix/extra-builtins.nix
{ exec, ... }: { exec, ... }:
@ -533,6 +541,8 @@ When setting this option normally, the password would normally be written world-
:CUSTOM_ID: h:315e6ef6-27d5-4cd8-85ff-053eabe60ddb :CUSTOM_ID: h:315e6ef6-27d5-4cd8-85ff-053eabe60ddb
:END: :END:
This is the file that manages the actual decryption of the files mentioned in [[#h:87c7893e-e946-4fc0-8973-1ca27d15cf0e][extra-builtins]]. We simply fetch the appropriate system age key from the ssh host key and then call =sops decrypt=. Since it would be a bother to decrypt these files on every build, I keep the result cached and only re-decrypt if it changes. Keeping it cached outside the nix store incurrs a theoretical bit of impurity. However, this is easier to manage and also nothing really relies on these files being present.
#+begin_src shell :tangle nix/sops-decrypt-and-cache.sh :shebang #!/usr/bin/env bash #+begin_src shell :tangle nix/sops-decrypt-and-cache.sh :shebang #!/usr/bin/env bash
# adapted from https://github.com/oddlama/nix-config/blob/main/nix/rage-decrypt-and-cache.sh # adapted from https://github.com/oddlama/nix-config/blob/main/nix/rage-decrypt-and-cache.sh
set -euo pipefail set -euo pipefail
@ -579,18 +589,25 @@ When setting this option normally, the password would normally be written world-
:CUSTOM_ID: h:f9b7ffba-b7e2-4554-9a35-ece0bf173e1c :CUSTOM_ID: h:f9b7ffba-b7e2-4554-9a35-ece0bf173e1c
:END: :END:
This section defines all functions of my own that I add to =lib=. These are used in all places over the config, with many of them being used in =flake.nix=. This section defines all functions of my own that I add to =lib=. These are used in all places over the config, however mainly in the files responsible for handling various imports.
A breakdown for the functions that have a non-obvious purpose:
- =pkgsFor=: This function reads all available systems from nixpkgs and generates pkgs for them. This is needed for my generation of home-manager and nix-on-droid systems in [[#h:5c5bf78a-9a66-436f-bd85-85871d9d402b][Hosts]].
- =nixpkgs.lib.genAttrs= is used to generate an attribute set (a dictionary-like structure) from a list of keys and a function that computes the values for those keys: =genAttrs ["a" "b" "c"] (x: "${x}-value")= will produce ={ a = "a-value"; b = "b-value"; c = "c-value"; }=.
- Also, in that function I am defining the =pkgs= that should be used when I reference =pkgs= in the actual configuration. I want to make sure that the correct system is used (keep in mind this is for home-manager configurations, which need that info! As a remark, you would not set this for a NixOS host), that I load my [[#h:7a059bd9-13f8-4005-b270-b41eeb6a4af2][Overlays]] (extra packages and modifications that I add to =pkgs=), as well as a setting that allows me to install unfree software. As a base package set I choose =nixpkgs= from my inputs (and so does nearly every configuration out there. Keep in mind however that you could use any package set here! =nixpkgs= however also comes with a lot of useful =lib= functions (that are not =builtins= to the nix language!))
- =mkTrueOption=: Defines a nixos module option that is by default enables (as opposed to =mkEnableOption= which are per default disabled).
- =mkStrong=: This function uses =nixpkgs.lib.mkOverride= in order to set a priority for an expression that is higher than setting an option normally (i.e. =option = value=;) which has priority 100, while being of lower priority than using =nixpkgs.lib.mkForce=, which has priority 50 (lower priority takes precedence). For completeness' sake, the priority set when using =nixpkgs.lib.mkDefault= is 1000 (a very low value).
- =forEachLinuxSystem=: performs the =pkgsFor= function for a set of =systems= (here: =x86_64-linux= and =aarch64-linux=). I need to use this in the [[#h:6ed1a641-dba8-4e85-a62e-be93264df57a][Packages (pkgs)]] section in order to avoid trying to build those packages for darwin systems.
- =readHosts=: Reads the names of directories under the =hosts/= folder for a particular system type
- =builtins.readDir= reads the name of items of a directory as attributes and their type as values. As an example =builtins.readDir ./hosts/nixos= ran on this flake yieled at some point the output ={ bakery = "directory"; chaostheatre = "directory"; milkywell = "directory"; moonside = "directory"; pyramid = "directory"; toto = "directory"; winters = "directory"; }=
- =nixpkgs.lib.attrNames= is used to aquire these attribute names (you might think of them as the "keys") from the output of =builtins.readDir=
- =readNix=: reads all files in a directory that are not =default.nix= (usually used to simply load everything from a folder and is called inside that respective =default.nix=).
- =mk[Modules,Profiles,Imports]=: These are used to help with importing files mostly:
- builtins.listToAttrs converts a list of name-value pairs into an attribute set. =builtins.listToAttrs [{ name = "foo"; value = 1; } { name = "bar"; value = 2; }]= for example returns ={ bar = 2; foo = 1; }=.
- =nixpkgs.lib.map= takes a function and applies the elements of a list upon them, e.g. =lib.map (x: x + 1) [1 2 3]= yields =[ 2 3 4 ]=. This is always used in =mkImports= to actually import the list of modules that are generated by the other =mk[...]= options.
A breakdown of each function:
The interesting part is in the start:
- first, I define =pkgsFor=. This function reads all available systems from nixpkgs and generates pkgs for them.
- next, =forEachSystem= is a function that can be called to declare an output for each such defined system.
- =forAllSystems= is a crude function that I use for expressions that depend on =system=, as the prior two attributes already consumed it at that stage. This is only really used to generate the checks in their own file.
- =mkFullHostConfigs= is the function that dynamically creates all definded hosts. The hosts are defined by placing a directory in =hosts/= under either the =nixos/= or =darwin/= directory. These directories are being read by =readHosts= and delivered to this funtion in the later call in [[#h:9c9b9e3b-8771-44fa-ba9e-5056ae809655][nixosConfigurations]] or [[#h:f881aa05-a670-48dd-a57b-2916abdcb692][darwinConfigurations]].
- =mkFullHost=:
This is a function that takes a hostname as well as a boolean whether it is NixOS or not, and returns a matching =nixosSystem= or =darwinSystem=. This function is only used for systems that can use both NixOS and home-manager options (darwin still counts here as it can use some NixOS options). This is used in mkFullHostConfigs. In more detail, it dynamically creates a nixosConfiguration host, setting its =speciaArgs= and =modules= attributes. The modules are populated based on whether this is a NixOS or darwin host. For the latter, I will only ever use machines that I get for testing from work, and for these my username is different, so I implemented an if-condition for it. This could be done more cleanly using variables, but some care needs to be taken with the home-manager imports and this approach works, so for now this is fine. Thanks to this function, the import sections of the host configs are pretty clean for most hosts.
=lib.optionals= evaluates to an empty list (=[]=) in case that the conditional is not met.
#+begin_src nix-ts :tangle nix/lib.nix #+begin_src nix-ts :tangle nix/lib.nix
{ self, inputs, ... }: { self, inputs, ... }:
@ -636,15 +653,12 @@ The interesting part is in the start:
mkStrong = lib.mkOverride 60; mkStrong = lib.mkOverride 60;
forEachSystem = f: lib.genAttrs (import systems) (system: f pkgsFor.${system}); # forEachSystem = f: lib.genAttrs (import systems) (system: f pkgsFor.${system});
forEachLinuxSystem = f: lib.genAttrs [ "x86_64-linux" "aarch64-linux" ] (system: f pkgsFor.${system}); forEachLinuxSystem = f: lib.genAttrs [ "x86_64-linux" "aarch64-linux" ] (system: f pkgsFor.${system});
readHosts = type: lib.attrNames (builtins.readDir "${self}/hosts/${type}"); readHosts = type: lib.attrNames (builtins.readDir "${self}/hosts/${type}");
readNix = type: lib.filter (name: name != "default.nix") (lib.attrNames (builtins.readDir "${self}/${type}")); readNix = type: lib.filter (name: name != "default.nix") (lib.attrNames (builtins.readDir "${self}/${type}"));
mkModules = names: type: builtins.listToAttrs (map mkModules = names: type: builtins.listToAttrs (map
(name: { (name: {
inherit name; inherit name;
@ -659,18 +673,7 @@ The interesting part is in the start:
}) })
names); names);
mkImports = names: baseDir: lib.map (name: "${self}/${baseDir}/${name}") names; mkImports = names: baseDir: lib.map (name: "${self}/${baseDir}/${name}") names;
eachMonitor = _: monitor: {
inherit (monitor) name;
value = builtins.removeAttrs monitor [ "workspace" "name" "output" ];
};
eachOutput = _: monitor: {
inherit (monitor) name;
value = builtins.removeAttrs monitor [ "mode" "name" "scale" "transform" "position" ];
};
}; };
in in
{ {
@ -687,7 +690,9 @@ The interesting part is in the start:
:CUSTOM_ID: h:6ed1a641-dba8-4e85-a62e-be93264df57a :CUSTOM_ID: h:6ed1a641-dba8-4e85-a62e-be93264df57a
:END: :END:
This does not use =perSystem= since some of my custom packages are not able to be built on darwin systems, and I was not yet interested in writing logic for handling that. This does not use =perSystem= from =flake-parts= since some of my custom packages are not able to be built on darwin systems, and I was not yet interested in writing logic for handling that. Instead I use =forEachLinuxSystem= as described in [[#h:f9b7ffba-b7e2-4554-9a35-ece0bf173e1c][Library functions]] in roder to only build this for linux hosts.
More information on the actual packages build can be found in [[#h:64a5cc16-6b16-4802-b421-c67ccef853e1][Packages]].
#+begin_src nix-ts :tangle nix/packages.nix #+begin_src nix-ts :tangle nix/packages.nix
{ self, ... }: { self, ... }:
@ -706,7 +711,16 @@ This does not use =perSystem= since some of my custom packages are not able to b
:CUSTOM_ID: h:af83893d-c0f9-4b45-b816-4849110d41b3 :CUSTOM_ID: h:af83893d-c0f9-4b45-b816-4849110d41b3
:END: :END:
The structure of =globals.nix.enc= requires a toplevel =globals=. This file is used to parse each =nixosConfiguration= present in this flake and scan them for options set under the =globals= attribute set. I use =lib.evalModules= to evaluate a mini module system that only consists of these globals options and then load them into the actual configuration by providing a =globals= output to the flake. This treads a dangerous ground of infinite recursions, which is why both the module system as well as the inherited attributes are kept to the minimal size. Each module has a globals option loaded from a module file which will be separately loaded by this mini-evaluation.
- =nixpkgs.lib.mapAttrsToList= converts an attribute set into a list by applying a given function to each name-value pair: =lib.mapAttrsToList (name: value: "${name} = ${value}) { a = "1"; b = "2"; }= yields the list =[ "a = 1" "b = 2" ]=. It is used on =config.nodes=.
- =nixpkgs.lib.flip= is used to reverse the function argument order of the =mapAttrsToList= call, so that we can give the attribute set (=config.nodes=) first. Alternatively, we could have written =lib.mapAttrsToList (name: cfg: [...]) config.nodes= but it would be harder to read since there would be a big block between the arguments.
- =nixpkgs.lib.concatLists=, as the name suggests, concatenates lists: =lib.concatLists [ [ 1 2 ] [ 3 4 ] [ 5 ] ]= yields =[ 1 2 3 4 5 ]=. =options.config._globalDefs= holds the =options.globals.definitions= for each node (which in turn basically holds the information that has been set for each node under the =globals= option), so the concatenated list will look something like =[ { services.kanidm.domain = "foo"; }; } { services.freshrss.domain = "bar"; } ]=.
- =nixpgks.lib.mkMerge= is used to merge these seperate attribute sets in the list into one big attribute set (the above attribute set example would become then ={ services = { kanidm.domain = "foo"; freshrss.domain = "bar"; }; }=. You can see how this can now be referenced as a "global" set.
I also have a file for global values that cannot be attributed to one =nixosConfiguration= alsone; the structure of this =globals.nix.enc= requires a toplevel =globals= - that means, =globals.nix.enc= has the structure ={ globals = [...] }=.
Lastly, in order make this actually available to my configurations, i use the =inherit (globalsSystem.config.globals) [...]= which produces the =globals= output which I will pass to the =specialArgs= of my =nixosConfigurations=, which is when I will be finally able to use these definitions in my config.
#+begin_src nix-ts :tangle nix/globals.nix #+begin_src nix-ts :tangle nix/globals.nix
# adapted from https://github.com/oddlama/nix-config/blob/main/nix/globals.nix # adapted from https://github.com/oddlama/nix-config/blob/main/nix/globals.nix
@ -778,6 +792,15 @@ The structure of =globals.nix.enc= requires a toplevel =globals=.
:CUSTOM_ID: h:5c5bf78a-9a66-436f-bd85-85871d9d402b :CUSTOM_ID: h:5c5bf78a-9a66-436f-bd85-85871d9d402b
:END: :END:
Here I define my hosts. Earlier (in [[#h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b][flake.nix skeleton]]), I told you how I used to use noweb-ref blocks to achieve this task. You see, a single =nixosConfiguration= uses =nixpkgs.lib.nixosSystem=, passing modules and arguments to define itself. I have automated this process by reading all directories in the =hosts/= directory and then applying =nixpkgs.lib.nixosSystem= as a function on these returns. I also provide a =nixosConfigurationsMinimal= output which is ingested by the flake in =install/flake.nix= to be used during the initial deployment of a new system (it basically just disables most modules).
- =mkNixosHost=: Very much akin to a simple call of =nixpkgs.lib.nixosSystem=, I simply define =specialArgs= and =modules= that I want to use for every configuration. Here, I load all the extra modules from my other input flakes. Also, I add the =globals= output from [[#h:af83893d-c0f9-4b45-b816-4849110d41b3][Globals]] and the =nodes= output that I define right here (it simply mirrors all "full" configurations - nixOS and darwin. I like to refer to home-manager only and nix-on-droid as a "half" configurations). It is also here that I set the node name for the configuration (I prefer this explicit call over referencing =networking.hostName= or such) and the directory that should be used for secrets of a configuration.
- =mkDarwinHost= works in the same way but for darwin machines.
- =mkFullHostConfigs= is the function that dynamically creates all definded hosts. The hosts are defined by placing a directory in =hosts/= under either the =nixos/= or =darwin/= directory. These directories are being read by =readHosts= and delivered to this funtion in the later call in [[#h:9c9b9e3b-8771-44fa-ba9e-5056ae809655][nixosConfigurations]] or [[#h:f881aa05-a670-48dd-a57b-2916abdcb692][darwinConfigurations]].
- =mkFullHost=:
This is a function that takes a hostname as well as a boolean whether it is NixOS or not, and returns a matching =nixosSystem= or =darwinSystem=. This function is only used for systems that can use both NixOS and home-manager options (darwin still counts here as it can use some NixOS options). This is used in mkFullHostConfigs. In more detail, it dynamically creates a nixosConfiguration host, setting its =speciaArgs= and =modules= attributes. The modules are populated based on whether this is a NixOS or darwin host. For the latter, I will only ever use machines that I get for testing from work, and for these my username is different, so I implemented an if-condition for it. This could be done more cleanly using variables, but some care needs to be taken with the home-manager imports and this approach works, so for now this is fine. Thanks to this function, the import sections of the host configs are pretty clean for most hosts.
#+begin_src nix-ts :tangle nix/hosts.nix #+begin_src nix-ts :tangle nix/hosts.nix
{ self, inputs, ... }: { self, inputs, ... }:
{ {
@ -5486,6 +5509,10 @@ Also, since I use a GPG key in sops, it seems that scdaemon creates an instance
#+begin_src nix-ts :tangle modules/nixos/client/hardwarecompatibility-yubikey.nix #+begin_src nix-ts :tangle modules/nixos/client/hardwarecompatibility-yubikey.nix
{ lib, config, pkgs, ... }: { lib, config, pkgs, ... }:
let
inherit (config.swarselsystems) mainUser;
inherit (config.repo.secrets.common.yubikeys) cfg1 cfg2;
in
{ {
options.swarselsystems.modules.yubikey = lib.mkEnableOption "yubikey config"; options.swarselsystems.modules.yubikey = lib.mkEnableOption "yubikey config";
config = lib.mkIf config.swarselsystems.modules.yubikey { config = lib.mkIf config.swarselsystems.modules.yubikey {
@ -5495,6 +5522,21 @@ Also, since I use a GPG key in sops, it seems that scdaemon creates an instance
hardware.gpgSmartcards.enable = true; hardware.gpgSmartcards.enable = true;
security.pam.u2f = {
enable = true;
control = "sufficient";
settings = {
interactive = false; # displays a prompt BEFORE asking for presence
cue = true; # prints a message that a touch is requrired
origin = "pam://${mainUser}"; # make the keys work on all machines
authfile = pkgs.writeText "u2f-mappings" (lib.concatStrings [
mainUser
cfg1
cfg2
]);
};
};
services.udev.packages = with pkgs; [ services.udev.packages = with pkgs; [
yubikey-personalization yubikey-personalization
]; ];
@ -12937,6 +12979,12 @@ Currently, I am too lazy to explain every option here, but most of it is very se
#+begin_src nix-ts :tangle modules/home/common/sway.nix #+begin_src nix-ts :tangle modules/home/common/sway.nix
{ self, config, lib, ... }: { self, config, lib, ... }:
let
eachOutput = _: monitor: {
inherit (monitor) name;
value = builtins.removeAttrs monitor [ "mode" "name" "scale" "transform" "position" ];
};
in
{ {
options.swarselsystems = { options.swarselsystems = {
modules.sway = lib.mkEnableOption "sway settings"; modules.sway = lib.mkEnableOption "sway settings";
@ -12992,15 +13040,15 @@ Currently, I am too lazy to explain every option here, but most of it is very se
swayfxConfig = lib.mkOption { swayfxConfig = lib.mkOption {
type = lib.types.str; type = lib.types.str;
default = " default = "
blur enable blur enable
blur_xray disable blur_xray disable
blur_passes 1 blur_passes 1
blur_radius 1 blur_radius 1
shadows enable shadows enable
corner_radius 2 corner_radius 2
titlebar_separator disable titlebar_separator disable
default_dim_inactive 0.02 default_dim_inactive 0.02
"; ";
internal = true; internal = true;
}; };
}; };
@ -13147,7 +13195,6 @@ Currently, I am too lazy to explain every option here, but most of it is very se
}; };
}; };
defaultWorkspace = "workspace 1:一"; defaultWorkspace = "workspace 1:一";
# output = lib.mapAttrs' lib.swarselsystems.eachMonitor monitors;
output = { output = {
"${config.swarselsystems.sharescreen}" = { "${config.swarselsystems.sharescreen}" = {
bg = "${self}/files/wallpaper/lenovowp.png ${config.stylix.imageScalingMode}"; bg = "${self}/files/wallpaper/lenovowp.png ${config.stylix.imageScalingMode}";
@ -13159,7 +13206,7 @@ Currently, I am too lazy to explain every option here, but most of it is very se
input = config.swarselsystems.standardinputs; input = config.swarselsystems.standardinputs;
workspaceOutputAssign = workspaceOutputAssign =
let let
workplaceSets = lib.mapAttrs' lib.swarselsystems.eachOutput config.swarselsystems.monitors; workplaceSets = lib.mapAttrs' eachOutput config.swarselsystems.monitors;
workplaceOutputs = map (key: lib.getAttr key workplaceSets) (lib.attrNames workplaceSets); workplaceOutputs = map (key: lib.getAttr key workplaceSets) (lib.attrNames workplaceSets);
in in
workplaceOutputs; workplaceOutputs;
@ -13308,36 +13355,36 @@ Currently, I am too lazy to explain every option here, but most of it is very se
swayfxSettings = config.swarselsystems.swayfxConfig; swayfxSettings = config.swarselsystems.swayfxConfig;
in in
" "
exec_always autotiling exec_always autotiling
set $exit \"exit: [s]leep, [l]ock, [p]oweroff, [r]eboot, [u]ser logout\" set $exit \"exit: [s]leep, [l]ock, [p]oweroff, [r]eboot, [u]ser logout\"
mode $exit { mode $exit {
bindsym --to-code { bindsym --to-code {
s exec \"systemctl suspend\", mode \"default\" s exec \"systemctl suspend\", mode \"default\"
h exec \"systemctl hibernate\", mode \"default\" h exec \"systemctl hibernate\", mode \"default\"
l exec \"swaylock --screenshots --clock --effect-blur 7x5 --effect-vignette 0.5:0.5 --fade-in 0.2 --daemonize\", mode \"default\ l exec \"swaylock --screenshots --clock --effect-blur 7x5 --effect-vignette 0.5:0.5 --fade-in 0.2 --daemonize\", mode \"default\
p exec \"systemctl poweroff\" p exec \"systemctl poweroff\"
r exec \"systemctl reboot\" r exec \"systemctl reboot\"
u exec \"swaymsg exit\" u exec \"swaymsg exit\"
Return mode \"default\" Return mode \"default\"
Escape mode \"default\" Escape mode \"default\"
${modifier}+Escape mode \"default\" ${modifier}+Escape mode \"default\"
}
} }
}
exec systemctl --user import-environment exec systemctl --user import-environment
exec swayidle -w exec swayidle -w
seat * hide_cursor 2000 seat * hide_cursor 2000
exec_always kill -1 $(pidof kanshi) exec_always kill -1 $(pidof kanshi)
bindswitch --locked lid:on exec kanshictl switch lidclosed bindswitch --locked lid:on exec kanshictl switch lidclosed
bindswitch --locked lid:off exec kanshictl switch lidopen bindswitch --locked lid:off exec kanshictl switch lidopen
${swayfxSettings} ${swayfxSettings}
"; ";
}; };
}; };
} }
@ -16574,7 +16621,7 @@ This holds modules that are to be used on most hosts. These are also the most im
general = lib.mkDefault true; general = lib.mkDefault true;
nixgl = lib.mkDefault true; nixgl = lib.mkDefault true;
sops = lib.mkDefault true; sops = lib.mkDefault true;
yubikey = lib.mkDefault true; yubikey = lib.mkDefault false;
ssh = lib.mkDefault true; ssh = lib.mkDefault true;
stylix = lib.mkDefault true; stylix = lib.mkDefault true;
desktop = lib.mkDefault true; desktop = lib.mkDefault true;

141
flake.lock generated
View file

@ -228,21 +228,6 @@
} }
}, },
"flake-compat_3": { "flake-compat_3": {
"locked": {
"lastModified": 1747046372,
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_4": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1696426674, "lastModified": 1696426674,
@ -258,7 +243,7 @@
"type": "github" "type": "github"
} }
}, },
"flake-compat_5": { "flake-compat_4": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1696426674, "lastModified": 1696426674,
@ -625,26 +610,6 @@
"type": "github" "type": "github"
} }
}, },
"nix-alien": {
"inputs": {
"flake-compat": "flake-compat_3",
"nix-index-database": "nix-index-database",
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1749976779,
"narHash": "sha256-Mjb4qsu+Fma1cXe1lGo0GqisvsiUeW0LfacziI7C7oM=",
"owner": "thiagokokada",
"repo": "nix-alien",
"rev": "f8716e36f8864e2f50663fde364ddd8dce5d937f",
"type": "github"
},
"original": {
"owner": "thiagokokada",
"repo": "nix-alien",
"type": "github"
}
},
"nix-darwin": { "nix-darwin": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@ -689,27 +654,6 @@
} }
}, },
"nix-index-database": { "nix-index-database": {
"inputs": {
"nixpkgs": [
"nix-alien",
"nixpkgs"
]
},
"locked": {
"lastModified": 1749960154,
"narHash": "sha256-EWlr9MZDd+GoGtZB4QsDzaLyaDQPGnRY03MFp6u2wSg=",
"owner": "nix-community",
"repo": "nix-index-database",
"rev": "424a40050cdc5f494ec45e46462d288f08c64475",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nix-index-database",
"type": "github"
}
},
"nix-index-database_2": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
@ -759,7 +703,7 @@
"inputs": { "inputs": {
"devshell": "devshell_2", "devshell": "devshell_2",
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"nixpkgs": "nixpkgs_3", "nixpkgs": "nixpkgs_2",
"pre-commit-hooks": "pre-commit-hooks" "pre-commit-hooks": "pre-commit-hooks"
}, },
"locked": { "locked": {
@ -779,7 +723,7 @@
"nixgl": { "nixgl": {
"inputs": { "inputs": {
"flake-utils": "flake-utils_2", "flake-utils": "flake-utils_2",
"nixpkgs": "nixpkgs_4" "nixpkgs": "nixpkgs_3"
}, },
"locked": { "locked": {
"lastModified": 1751696036, "lastModified": 1751696036,
@ -1019,39 +963,7 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_10": {
"locked": {
"lastModified": 1750865895,
"narHash": "sha256-p2dWAQcLVzquy9LxYCZPwyUdugw78Qv3ChvnX755qHA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "61c0f513911459945e2cb8bf333dc849f1b976ff",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": { "nixpkgs_2": {
"locked": {
"lastModified": 1749794982,
"narHash": "sha256-Kh9K4taXbVuaLC0IL+9HcfvxsSUx8dPB5s5weJcc9pc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "ee930f9755f58096ac6e8ca94a1887e0534e2d81",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": { "locked": {
"lastModified": 1730531603, "lastModified": 1730531603,
"narHash": "sha256-Dqg6si5CqIzm87sp57j5nTaeBbWhHFaVyG7V6L8k3lY=", "narHash": "sha256-Dqg6si5CqIzm87sp57j5nTaeBbWhHFaVyG7V6L8k3lY=",
@ -1067,7 +979,7 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_4": { "nixpkgs_3": {
"locked": { "locked": {
"lastModified": 1746378225, "lastModified": 1746378225,
"narHash": "sha256-OeRSuL8PUjIfL3Q0fTbNJD/fmv1R+K2JAOqWJd3Oceg=", "narHash": "sha256-OeRSuL8PUjIfL3Q0fTbNJD/fmv1R+K2JAOqWJd3Oceg=",
@ -1082,7 +994,7 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_5": { "nixpkgs_4": {
"locked": { "locked": {
"lastModified": 1751792365, "lastModified": 1751792365,
"narHash": "sha256-J1kI6oAj25IG4EdVlg2hQz8NZTBNYvIS0l4wpr9KcUo=", "narHash": "sha256-J1kI6oAj25IG4EdVlg2hQz8NZTBNYvIS0l4wpr9KcUo=",
@ -1098,7 +1010,7 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_6": { "nixpkgs_5": {
"locked": { "locked": {
"lastModified": 1720957393, "lastModified": 1720957393,
"narHash": "sha256-oedh2RwpjEa+TNxhg5Je9Ch6d3W1NKi7DbRO1ziHemA=", "narHash": "sha256-oedh2RwpjEa+TNxhg5Je9Ch6d3W1NKi7DbRO1ziHemA=",
@ -1114,7 +1026,7 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_7": { "nixpkgs_6": {
"locked": { "locked": {
"lastModified": 1751792365, "lastModified": 1751792365,
"narHash": "sha256-J1kI6oAj25IG4EdVlg2hQz8NZTBNYvIS0l4wpr9KcUo=", "narHash": "sha256-J1kI6oAj25IG4EdVlg2hQz8NZTBNYvIS0l4wpr9KcUo=",
@ -1130,7 +1042,7 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_8": { "nixpkgs_7": {
"locked": { "locked": {
"lastModified": 1744868846, "lastModified": 1744868846,
"narHash": "sha256-5RJTdUHDmj12Qsv7XOhuospjAjATNiTMElplWnJE9Hs=", "narHash": "sha256-5RJTdUHDmj12Qsv7XOhuospjAjATNiTMElplWnJE9Hs=",
@ -1146,7 +1058,7 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_9": { "nixpkgs_8": {
"locked": { "locked": {
"lastModified": 1748460289, "lastModified": 1748460289,
"narHash": "sha256-7doLyJBzCllvqX4gszYtmZUToxKvMUrg45EUWaUYmBg=", "narHash": "sha256-7doLyJBzCllvqX4gszYtmZUToxKvMUrg45EUWaUYmBg=",
@ -1162,6 +1074,22 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_9": {
"locked": {
"lastModified": 1750865895,
"narHash": "sha256-p2dWAQcLVzquy9LxYCZPwyUdugw78Qv3ChvnX755qHA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "61c0f513911459945e2cb8bf333dc849f1b976ff",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nmd": { "nmd": {
"flake": false, "flake": false,
"locked": { "locked": {
@ -1219,7 +1147,7 @@
"nswitch-rcm-nix": { "nswitch-rcm-nix": {
"inputs": { "inputs": {
"flake-parts": "flake-parts_3", "flake-parts": "flake-parts_3",
"nixpkgs": "nixpkgs_6" "nixpkgs": "nixpkgs_5"
}, },
"locked": { "locked": {
"lastModified": 1721304043, "lastModified": 1721304043,
@ -1238,7 +1166,7 @@
"nur": { "nur": {
"inputs": { "inputs": {
"flake-parts": "flake-parts_4", "flake-parts": "flake-parts_4",
"nixpkgs": "nixpkgs_7" "nixpkgs": "nixpkgs_6"
}, },
"locked": { "locked": {
"lastModified": 1751906969, "lastModified": 1751906969,
@ -1282,7 +1210,7 @@
}, },
"pre-commit-hooks": { "pre-commit-hooks": {
"inputs": { "inputs": {
"flake-compat": "flake-compat_4", "flake-compat": "flake-compat_3",
"gitignore": "gitignore_2", "gitignore": "gitignore_2",
"nixpkgs": [ "nixpkgs": [
"nix-topology", "nix-topology",
@ -1335,7 +1263,7 @@
}, },
"pre-commit-hooks_2": { "pre-commit-hooks_2": {
"inputs": { "inputs": {
"flake-compat": "flake-compat_5", "flake-compat": "flake-compat_4",
"gitignore": "gitignore_3", "gitignore": "gitignore_3",
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
@ -1365,15 +1293,14 @@
"home-manager": "home-manager", "home-manager": "home-manager",
"impermanence": "impermanence", "impermanence": "impermanence",
"lanzaboote": "lanzaboote", "lanzaboote": "lanzaboote",
"nix-alien": "nix-alien",
"nix-darwin": "nix-darwin", "nix-darwin": "nix-darwin",
"nix-index-database": "nix-index-database_2", "nix-index-database": "nix-index-database",
"nix-on-droid": "nix-on-droid", "nix-on-droid": "nix-on-droid",
"nix-topology": "nix-topology", "nix-topology": "nix-topology",
"nixgl": "nixgl", "nixgl": "nixgl",
"nixos-generators": "nixos-generators", "nixos-generators": "nixos-generators",
"nixos-hardware": "nixos-hardware", "nixos-hardware": "nixos-hardware",
"nixpkgs": "nixpkgs_5", "nixpkgs": "nixpkgs_4",
"nixpkgs-dev": "nixpkgs-dev", "nixpkgs-dev": "nixpkgs-dev",
"nixpkgs-kernel": "nixpkgs-kernel", "nixpkgs-kernel": "nixpkgs-kernel",
"nixpkgs-stable": "nixpkgs-stable_2", "nixpkgs-stable": "nixpkgs-stable_2",
@ -1449,7 +1376,7 @@
}, },
"sops-nix": { "sops-nix": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs_8" "nixpkgs": "nixpkgs_7"
}, },
"locked": { "locked": {
"lastModified": 1751606940, "lastModified": 1751606940,
@ -1474,7 +1401,7 @@
"firefox-gnome-theme": "firefox-gnome-theme", "firefox-gnome-theme": "firefox-gnome-theme",
"flake-parts": "flake-parts_5", "flake-parts": "flake-parts_5",
"gnome-shell": "gnome-shell", "gnome-shell": "gnome-shell",
"nixpkgs": "nixpkgs_9", "nixpkgs": "nixpkgs_8",
"nur": "nur_2", "nur": "nur_2",
"systems": "systems_3", "systems": "systems_3",
"tinted-foot": "tinted-foot", "tinted-foot": "tinted-foot",
@ -1716,7 +1643,7 @@
"inputs": { "inputs": {
"crane": "crane_2", "crane": "crane_2",
"flake-utils": "flake-utils_3", "flake-utils": "flake-utils_3",
"nixpkgs": "nixpkgs_10", "nixpkgs": "nixpkgs_9",
"rust-overlay": "rust-overlay_2" "rust-overlay": "rust-overlay_2"
}, },
"locked": { "locked": {

View file

@ -43,9 +43,6 @@
nixos-hardware = { nixos-hardware = {
url = "github:NixOS/nixos-hardware/master"; url = "github:NixOS/nixos-hardware/master";
}; };
nix-alien = {
url = "github:thiagokokada/nix-alien";
};
nswitch-rcm-nix = { nswitch-rcm-nix = {
url = "github:Swarsel/nswitch-rcm-nix"; url = "github:Swarsel/nswitch-rcm-nix";
}; };

View file

@ -3,7 +3,7 @@
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head> <head>
<!-- 2025-07-14 Mo 01:07 --> <!-- 2025-07-14 Mo 03:07 -->
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>SwarselSystems: NixOS + Emacs Configuration</title> <title>SwarselSystems: NixOS + Emacs Configuration</title>
@ -246,7 +246,7 @@
</li> </li>
<li><a href="#h:58dc6384-0d19-4f71-9043-4014bd033ba2">3.1.2. Physical hosts</a> <li><a href="#h:58dc6384-0d19-4f71-9043-4014bd033ba2">3.1.2. Physical hosts</a>
<ul> <ul>
<li><a href="#h:6c6e9261-dfa1-42d8-ab2a-8b7c227be6d9">3.1.2.1. nbl-imba-2 (Framework Laptop 16)</a> <li><a href="#h:6c6e9261-dfa1-42d8-ab2a-8b7c227be6d9">3.1.2.1. pyramid (Framework Laptop 16)</a>
<ul> <ul>
<li><a href="#h:567c0055-f5f7-4e53-8f13-d767d7166e9d">3.1.2.1.1. Main Configuration</a></li> <li><a href="#h:567c0055-f5f7-4e53-8f13-d767d7166e9d">3.1.2.1.1. Main Configuration</a></li>
<li><a href="#h:25115a54-c634-4896-9a41-254064ce9fcc">3.1.2.1.2. hardware-configuration</a></li> <li><a href="#h:25115a54-c634-4896-9a41-254064ce9fcc">3.1.2.1.2. hardware-configuration</a></li>
@ -266,7 +266,7 @@
<li><a href="#h:0fdefb4f-ce53-4caf-89ed-5d79646f70f0">3.1.2.3.2. hardware-configuration</a></li> <li><a href="#h:0fdefb4f-ce53-4caf-89ed-5d79646f70f0">3.1.2.3.2. hardware-configuration</a></li>
</ul> </ul>
</li> </li>
<li><a href="#h:28e1a7eb-356b-4015-83f7-9c552c8c0e9d">3.1.2.4. nbm-imba-166 (MacBook Pro)</a></li> <li><a href="#h:28e1a7eb-356b-4015-83f7-9c552c8c0e9d">3.1.2.4. machpizza (MacBook Pro)</a></li>
<li><a href="#h:729af373-37e7-4379-9a3d-b09792219415">3.1.2.5. Magicant (Phone)</a></li> <li><a href="#h:729af373-37e7-4379-9a3d-b09792219415">3.1.2.5. Magicant (Phone)</a></li>
</ul> </ul>
</li> </li>
@ -782,7 +782,7 @@
</div> </div>
</div> </div>
<p> <p>
<b>This file has 85605 words spanning 22598 lines and was last revised on 2025-07-14 01:07:45 +0200.</b> <b>This file has 87025 words spanning 22627 lines and was last revised on 2025-07-14 03:07:10 +0200.</b>
</p> </p>
<p> <p>
@ -835,7 +835,7 @@ This section defines my Emacs configuration. For a while, I considered to use ry
</p> </p>
<p> <p>
My emacs is built using the emacs-overlay nix flake, which builds a bleeding edge emacs on wayland (pgtk) with utilities like treesitter support. By executing the below source block, the current build setting can be updated at any time, and you can see my most up-to-date build options (last updated: 2025-07-14 01:07:45 +0200) My emacs is built using the emacs-overlay nix flake, which builds a bleeding edge emacs on wayland (pgtk) with utilities like treesitter support. By executing the below source block, the current build setting can be updated at any time, and you can see my most up-to-date build options (last updated: 2025-07-14 03:07:10 +0200)
</p></li> </p></li>
</ul> </ul>
@ -1071,16 +1071,17 @@ Here I give a brief overview over the hostmachines that I am using. This is held
<div class="org-src-container"> <div class="org-src-container">
<pre class="src src-markdown">| Name | Hardware | Use | <pre class="src src-markdown">| Name | Hardware | Use |
|--------------------|-----------------------------------------------------|------------------------------------------------------| |--------------------|-----------------------------------------------------|------------------------------------------------------|
|💻 **nbl-imba-2** | Framework Laptop 16, AMD 7940HS, RX 7700S, 64GB RAM | Work laptop | |💻 **pyramid** | Framework Laptop 16, AMD 7940HS, RX 7700S, 64GB RAM | Work laptop |
|💻 **nbm-imba-166** | MacBook Pro 2016 | MacOS Sandbox | |💻 **bakery** | Lenovo Ideapad 720S-13IKB | Personal lapto |
|💻 **machpizza** | MacBook Pro 2016 | MacOS sandbox |
|🖥️ **winters** | ASRock J4105-ITX, 32GB RAM | Main homeserver and data storgae | |🖥️ **winters** | ASRock J4105-ITX, 32GB RAM | Main homeserver and data storgae |
|🖥️ **milkywell** | Oracle Cloud: VM.Standard.E2.1.Micro | Server for lightweight synchronization tasks | |🖥️ **milkywell** | Oracle Cloud: VM.Standard.E2.1.Micro | Server for lightweight synchronization tasks |
|🖥️ **moonside** | Oracle Cloud: VM.Standard.A1.Flex, 4 OCPUs, 24GB RAM| Proxy for local services, some lightweight services | |🖥️ **moonside** | Oracle Cloud: VM.Standard.A1.Flex, 4 OCPUs, 24GB RAM| Proxy for local services, some lightweight services |
|📱 **magicant** | Samsung Galaxy Z Flip 6 | Phone | |📱 **magicant** | Samsung Galaxy Z Flip 6 | Phone |
|💿 **drugstore** | - | ISO installer configuration | |💿 **drugstore** | - | ISO installer configuration |
|❔ **chaotheatre** | - | Demo config for checking out my configurtion | |❔ **chaotheatre** | - | Demo config for checking out my configurtion |
|❔ **toto** | - | Helper configuration for bootstrapping a new system | |❔ **toto** | - | Helper configuration for bootstrapping a new system |
|🏠 **Treehouse** | - | Reference configuration for a home-manager only host | |🏠 **treehouse** | - | Reference configuration for a home-manager only host |
</pre> </pre>
</div> </div>
</div> </div>
@ -1141,30 +1142,31 @@ Here I give a brief overview over the hostmachines that I am using. This is held
<h2 id="h:c7588c0d-2528-485d-b2df-04d6336428d7"><span class="section-number-2">2.</span> flake.nix</h2> <h2 id="h:c7588c0d-2528-485d-b2df-04d6336428d7"><span class="section-number-2">2.</span> flake.nix</h2>
<div class="outline-text-2" id="text-h:c7588c0d-2528-485d-b2df-04d6336428d7"> <div class="outline-text-2" id="text-h:c7588c0d-2528-485d-b2df-04d6336428d7">
<p> <p>
Handling the flake.nix file used to be a bit of a chore, since it felt like writing so much boilerplate code just to define new systems. The noweb-approach here makes this a little bit less painful. Handling the flake.nix file used to be a bit of a chore, since it felt like writing so much boilerplate code just to define new systems. For a while, I used noweb-ref in order to alleviate this problem (see <a href="#h:dae0c5bb-edb7-4fe4-ae31-9f8f064cc53c">Appendix A: Noweb-Ref blocks</a>, an example of the repository at that time would be <code>acc0ad6: Add several NixOS hosts on Proxmox and Oracle Cloud</code>.). However, the true answer laid in making use of builtin nix functionality.
</p> </p>
<p> <p>
These blocks are later inserted here: <a href="#h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b">flake.nix template</a>. Adding new flake inputs is very easy, you just add them to [BROKEN LINK: h:8a411ee2-a58e-4b5b-99bd-4ba772f8f0a2] first by name in the first source-block, and then the path in the second source-block. Any variables to be set for the host configuration are done in [BROKEN LINK: h:df0072bc-853f-438f-bd85-bfc869501015], and the specific setup is done in either [BROKEN LINK: h:9c9b9e3b-8771-44fa-ba9e-5056ae809655] (for NixOS systems), [BROKEN LINK: h:f881aa05-a670-48dd-a57b-2916abdcb692] (for home-manager systems), or [BROKEN LINK: h:5f6ef553-59f9-4239-b6f3-63d33b57f335] (for Nix on Android) and [BROKEN LINK: h:f881aa05-a670-48dd-a57b-2916abdcb692] (for Darwin systems, also known as Macs). There also used to be a [BROKEN LINK: h:6a08495a-8566-4bb5-9fac-b03df01f6c81] section that used to define a Proxmox LXC image when I was still using Proxmox as my main server. An example of the repository at that time would be <code>acc0ad6: Add several NixOS hosts on Proxmox and Oracle Cloud</code>. Nowadays, I use flake-parts to manage my flake. It allows me to conveniently split the actual flake into multiple files ("parts") using the following mechanism:
</p> </p>
<ul class="org-ul">
<li><code>imports</code> are files pulled in to build the flake configuration (similar to the imports in the module system)</li>
<li><code>systems</code> defines the architectures that the flake should be provided for - I go here for the four "main" architectures, although true support is only provided for linux systems (see <a href="#h:6ed1a641-dba8-4e85-a62e-be93264df57a">Packages (pkgs)</a> for the main reason)</li>
</ul>
</div> </div>
<div id="outline-container-h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b" class="outline-3"> <div id="outline-container-h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b" class="outline-3">
<h3 id="h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b"><span class="section-number-3">2.1.</span> flake.nix skeleton</h3> <h3 id="h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b"><span class="section-number-3">2.1.</span> flake.nix skeleton</h3>
<div class="outline-text-3" id="text-h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b"> <div class="outline-text-3" id="text-h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b">
<p> <p>
This sections puts together the <code>flake.nix</code> file from the [BROKEN LINK: h:d39b8dfb-536d-414f-9fc0-7d67df48cee4] section. This tangles the flake.nix file; This block only needs to be touched when updating the general structure of the flake. For everything else, see the respective noweb-ref block. In general, a nix flake consists of one or more inputs and several outputs. The inputs are used to define where nix should be looking for packages, modules, and more. The outputs generate expressions that can be used in .nix files as well as system configurations using these files.
</p> </p>
<p> <p>
In general, a nix flake consists of one or more inputs and several outputs. The inputs are used to define where nix should be looking for packages, options, and more. The outputs generate expressions that can be used in .nix files as well as system configurations using these files. In the start, I enable some public cache repositories. This saves some time during rebuilds because it avoids building as many packages from scratch - this is mainly important for community flakes like <code>emacs-overlay</code>, which basically would trigger a rebuild whenever updating the flake. The repository does of course not hold everything, but it lightens the pain. It would look cleaner if this were to be used only inside a nix configuration block of an actual system, but I want these caches to be used for e.g. app calls as well.
</p> </p>
<p> <p>
In the start, I enable some public cache repositories. This saves some time during rebuilds because it avoids building as many packages from scratch - this is mainly important for community flakes like <code>emacs-overlay</code>, which basically would trigger a rebuild whenever updating the flake. The repository does of course not hold everything, but it lightens the pain. In many flakes, you see a structure like this: <code>outputs = inputs@ [...]</code>, the <code>inputs@</code> makes it so that all inputs are automatically passed to the outputs and can be called as <code>inputs.&lt;name&gt;</code>, whereas explicit arguments may just be called by using <code>&lt;name&gt;</code>. For most flakes this is fully sufficient, as they do not need to be called often and it saves me maintainance effort with this file. In fact, I also used to make use of this mechanism. However, using flake-parts, all I really need for the outputs function is inputs, which is why my outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } { [&#x2026;] ). Note that flake-parts must inherit these inputs and no other arguments are expected.
</p>
<p>
In <code>outputs = inputs@ [...]</code>, the <code>inputs@</code> makes it so that all inputs are automatically passed to the outputs and can be called as <code>inputs.&lt;name&gt;</code>, whereas explicit arguments may just be called by using <code>&lt;name&gt;</code>. For most flakes this is fully sufficient, as they do not need to be called often and it saves me maintainance effort with this file.
</p> </p>
<p> <p>
@ -1228,8 +1230,6 @@ Provides secure boot for NixOS. Needed for my Surface Pro 3.</li>
This brings nix to android in an app that is similar to tmux! Of course most of the configuration does not apply to this, but it is still neat to have!</li> This brings nix to android in an app that is similar to tmux! Of course most of the configuration does not apply to this, but it is still neat to have!</li>
<li><a href="https://github.com/NixOS/nixos-hardware">nixos-hardware</a> <li><a href="https://github.com/NixOS/nixos-hardware">nixos-hardware</a>
Provides specific hardware setting for some hardware configurations. For example, this sets some better defaults for my Lenovo Thinkpad P14s Gen2.</li> Provides specific hardware setting for some hardware configurations. For example, this sets some better defaults for my Lenovo Thinkpad P14s Gen2.</li>
<li><a href="https://github.com/thiagokokada/nix-alien">nix-alien</a>
This is supposed to allow me to run unpatched libraries directly without a need for ELF patching or resorting to <code>steam-run</code>. However, I have not yet gotten this to work.</li>
<li><a href="https://github.com/nix-community/nixos-generators">nixos-generators</a> <li><a href="https://github.com/nix-community/nixos-generators">nixos-generators</a>
Provides me with images that I can use to create LXCs on Proxmox.</li> Provides me with images that I can use to create LXCs on Proxmox.</li>
<li><a href="https://github.com/Swarsel/nswitch-rcm-nix">nswitch-rcm-nix</a> <li><a href="https://github.com/Swarsel/nswitch-rcm-nix">nswitch-rcm-nix</a>
@ -1248,16 +1248,12 @@ This provides access to the internal fans of Frameworks laptops. This is a bit m
After learning that MacOS systems can also be configured using nix, I managed to get access to an old MacBook for testing. This allows to set most general settings that can otherwise be set using the Mac GUI.</li> After learning that MacOS systems can also be configured using nix, I managed to get access to an old MacBook for testing. This allows to set most general settings that can otherwise be set using the Mac GUI.</li>
<li><a href="https://github.com/cachix/git-hooks.nix">pre-commit-hooks</a> <li><a href="https://github.com/cachix/git-hooks.nix">pre-commit-hooks</a>
Provides access to several checks that can be hooked to be run before several stages in the process.</li> Provides access to several checks that can be hooked to be run before several stages in the process.</li>
<li>nix-secrets
This is a private repository that I use for settings in modules that do not expose a <code>secretsFile</code> (or similar) option. An example is the <code>LastFM.ApiKey</code> option in <a href="#h:f347f3ad-5100-4c4f-8616-cfd7f8e14a72">navidrome</a>:
<code>LastFM.ApiKey = builtins.readFile "${secretsDirectory}/navidrome/lastfm-secret";</code></li>
</ul>
<p>
When setting this option normally, the password would normally be written world-readable not only in the nix store, but also in the configuration. Hence, I put such passwords into a private repository. This allows me to keep purity of the flake while keeping a level of security on these secrets.
</p>
<ul class="org-ul">
<li><a href="https://github.com/oddlama/nix-topology">nix-topology</a> <li><a href="https://github.com/oddlama/nix-topology">nix-topology</a>
This automatically creates a topology diagram of my configuration.</li> This automatically creates a topology diagram of my configuration.</li>
<li>flake-parts
The aforementioned system that allows for more convenient flake crafting.</li>
<li>devshell
This provides devshell support for flake-parts</li>
</ul> </ul>
<div class="org-src-container"> <div class="org-src-container">
@ -1306,9 +1302,6 @@ This automatically creates a topology diagram of my configuration.</li>
nixos-hardware = { nixos-hardware = {
url = "github:NixOS/nixos-hardware/master"; url = "github:NixOS/nixos-hardware/master";
}; };
nix-alien = {
url = "github:thiagokokada/nix-alien";
};
nswitch-rcm-nix = { nswitch-rcm-nix = {
url = "github:Swarsel/nswitch-rcm-nix"; url = "github:Swarsel/nswitch-rcm-nix";
}; };
@ -1379,10 +1372,32 @@ This automatically creates a topology diagram of my configuration.</li>
<div id="outline-container-h:23602ad9-91f6-4eba-943a-2308070fbaec" class="outline-3"> <div id="outline-container-h:23602ad9-91f6-4eba-943a-2308070fbaec" class="outline-3">
<h3 id="h:23602ad9-91f6-4eba-943a-2308070fbaec"><span class="section-number-3">2.2.</span> Auxiliary files</h3> <h3 id="h:23602ad9-91f6-4eba-943a-2308070fbaec"><span class="section-number-3">2.2.</span> Auxiliary files</h3>
<div class="outline-text-3" id="text-h:23602ad9-91f6-4eba-943a-2308070fbaec"> <div class="outline-text-3" id="text-h:23602ad9-91f6-4eba-943a-2308070fbaec">
<p>
Here I define some extra files that are crucial for success in building my configurations. These are not pulled in by the flake directly, but I still feel like they should be mentioned at the flake level.
</p>
</div> </div>
<div id="outline-container-h:87c7893e-e946-4fc0-8973-1ca27d15cf0e" class="outline-4"> <div id="outline-container-h:87c7893e-e946-4fc0-8973-1ca27d15cf0e" class="outline-4">
<h4 id="h:87c7893e-e946-4fc0-8973-1ca27d15cf0e"><span class="section-number-4">2.2.1.</span> extra-builtins</h4> <h4 id="h:87c7893e-e946-4fc0-8973-1ca27d15cf0e"><span class="section-number-4">2.2.1.</span> extra-builtins</h4>
<div class="outline-text-4" id="text-h:87c7893e-e946-4fc0-8973-1ca27d15cf0e"> <div class="outline-text-4" id="text-h:87c7893e-e946-4fc0-8973-1ca27d15cf0e">
<p>
This file is used by <a href="https://github.com/shlevy/nix-plugins">nix-plugins</a>. nix-plugins generally allows for the introduction of arbitrary functions into the <code>builtins</code> set. However, I do not want to allow just any function to be added there. Instead, I only add a single function called <code>sopsImportEncrypted</code>. This function is used in order to help me store PII (personally identifiable information) in my repo without having to resort to either:
</p>
<ul class="org-ul">
<li><a href="https://github.com/AGWA/git-crypt">git-crypt</a></li>
<li><p>
a separate repo containing my secrets
</p>
<p>
As for the second approach, I actually used this up to some point (see for example <code>7e11641: feat: add initial oauth2-proxy and freshrss oidc</code> as one of the lasts commits still using this system). However, it is quite bothersome to constantly have to keep two repositories up to date and in sync. Also, having a repo that every configuration relied upon that was also a private repo led to the problem that my demo configuration (<a href="#h:e1498bef-ec67-483d-bf02-76264e30be8e">ChaosTheatre (Demo Physical/VM)</a>) would fail to build with that present, and I had to take several extra steps to make it buildable. Ever since deleting that dependency I also got rid of that problem. The whole system is inspired by <a href="https://oddlama.org/blog/evaluation-time-secrets-in-nix/">this blog article</a> and large parts of it are adapted from <a href="https://github.com/oddlama/nix-config">oddlama's nix-config</a>.
</p></li>
</ul>
<p>
The builtin that is added is a simple call to the <code>exec</code> function that calls a bash script. In order to keep some sanity, we are checking that we are actually calling it no an encryted nix file (even though there is no syntax check inside) and that the path given is a true nix path. Note that a string path will not be accepted, as that can have impurity implications.
</p>
<div class="org-src-container"> <div class="org-src-container">
<pre class="src src-nix-ts"># adapted from https://github.com/oddlama/nix-config/blob/main/nix/extra-builtins.nix <pre class="src src-nix-ts"># adapted from https://github.com/oddlama/nix-config/blob/main/nix/extra-builtins.nix
{ exec, ... }: { exec, ... }:
@ -1419,6 +1434,10 @@ in
<div id="outline-container-h:315e6ef6-27d5-4cd8-85ff-053eabe60ddb" class="outline-4"> <div id="outline-container-h:315e6ef6-27d5-4cd8-85ff-053eabe60ddb" class="outline-4">
<h4 id="h:315e6ef6-27d5-4cd8-85ff-053eabe60ddb"><span class="section-number-4">2.2.2.</span> sops-decrypt-and-cache</h4> <h4 id="h:315e6ef6-27d5-4cd8-85ff-053eabe60ddb"><span class="section-number-4">2.2.2.</span> sops-decrypt-and-cache</h4>
<div class="outline-text-4" id="text-h:315e6ef6-27d5-4cd8-85ff-053eabe60ddb"> <div class="outline-text-4" id="text-h:315e6ef6-27d5-4cd8-85ff-053eabe60ddb">
<p>
This is the file that manages the actual decryption of the files mentioned in <a href="#h:87c7893e-e946-4fc0-8973-1ca27d15cf0e">extra-builtins</a>. We simply fetch the appropriate system age key from the ssh host key and then call <code>sops decrypt</code>. Since it would be a bother to decrypt these files on every build, I keep the result cached and only re-decrypt if it changes. Keeping it cached outside the nix store incurrs a theoretical bit of impurity. However, this is easier to manage and also nothing really relies on these files being present.
</p>
<div class="org-src-container"> <div class="org-src-container">
<pre class="src src-shell"># adapted from https://github.com/oddlama/nix-config/blob/main/nix/rage-decrypt-and-cache.sh <pre class="src src-shell"># adapted from https://github.com/oddlama/nix-config/blob/main/nix/rage-decrypt-and-cache.sh
set -euo pipefail set -euo pipefail
@ -1468,26 +1487,37 @@ fi
<h3 id="h:f9b7ffba-b7e2-4554-9a35-ece0bf173e1c"><span class="section-number-3">2.3.</span> Library functions</h3> <h3 id="h:f9b7ffba-b7e2-4554-9a35-ece0bf173e1c"><span class="section-number-3">2.3.</span> Library functions</h3>
<div class="outline-text-3" id="text-h:f9b7ffba-b7e2-4554-9a35-ece0bf173e1c"> <div class="outline-text-3" id="text-h:f9b7ffba-b7e2-4554-9a35-ece0bf173e1c">
<p> <p>
This section defines all functions of my own that I add to <code>lib</code>. These are used in all places over the config, with many of them being used in <code>flake.nix</code>. This section defines all functions of my own that I add to <code>lib</code>. These are used in all places over the config, however mainly in the files responsible for handling various imports.
</p> </p>
<p> <p>
A breakdown of each function: A breakdown for the functions that have a non-obvious purpose:
</p> </p>
<p>
The interesting part is in the start:
</p>
<ul class="org-ul"> <ul class="org-ul">
<li>first, I define <code>pkgsFor</code>. This function reads all available systems from nixpkgs and generates pkgs for them.</li> <li><code>pkgsFor</code>: This function reads all available systems from nixpkgs and generates pkgs for them. This is needed for my generation of home-manager and nix-on-droid systems in <a href="#h:5c5bf78a-9a66-436f-bd85-85871d9d402b">Hosts</a>.
<li>next, <code>forEachSystem</code> is a function that can be called to declare an output for each such defined system.</li> <ul class="org-ul">
<li><code>forAllSystems</code> is a crude function that I use for expressions that depend on <code>system</code>, as the prior two attributes already consumed it at that stage. This is only really used to generate the checks in their own file.</li> <li><code>nixpkgs.lib.genAttrs</code> is used to generate an attribute set (a dictionary-like structure) from a list of keys and a function that computes the values for those keys: <code>genAttrs ["a" "b" "c"] (x: "${x}-value")</code> will produce <code>{ a = "a-value"; b = "b-value"; c = "c-value"; }</code>.</li>
<li><code>mkFullHostConfigs</code> is the function that dynamically creates all definded hosts. The hosts are defined by placing a directory in <code>hosts/</code> under either the <code>nixos/</code> or <code>darwin/</code> directory. These directories are being read by <code>readHosts</code> and delivered to this funtion in the later call in [BROKEN LINK: h:9c9b9e3b-8771-44fa-ba9e-5056ae809655] or [BROKEN LINK: h:f881aa05-a670-48dd-a57b-2916abdcb692].</li> <li>Also, in that function I am defining the <code>pkgs</code> that should be used when I reference <code>pkgs</code> in the actual configuration. I want to make sure that the correct system is used (keep in mind this is for home-manager configurations, which need that info! As a remark, you would not set this for a NixOS host), that I load my <a href="#h:7a059bd9-13f8-4005-b270-b41eeb6a4af2">Overlays</a> (extra packages and modifications that I add to <code>pkgs</code>), as well as a setting that allows me to install unfree software. As a base package set I choose <code>nixpkgs</code> from my inputs (and so does nearly every configuration out there. Keep in mind however that you could use any package set here! <code>nixpkgs</code> however also comes with a lot of useful <code>lib</code> functions (that are not <code>builtins</code> to the nix language!))</li>
<li><code>mkFullHost</code>: </ul></li>
This is a function that takes a hostname as well as a boolean whether it is NixOS or not, and returns a matching <code>nixosSystem</code> or <code>darwinSystem</code>. This function is only used for systems that can use both NixOS and home-manager options (darwin still counts here as it can use some NixOS options). This is used in mkFullHostConfigs. In more detail, it dynamically creates a nixosConfiguration host, setting its <code>speciaArgs</code> and <code>modules</code> attributes. The modules are populated based on whether this is a NixOS or darwin host. For the latter, I will only ever use machines that I get for testing from work, and for these my username is different, so I implemented an if-condition for it. This could be done more cleanly using variables, but some care needs to be taken with the home-manager imports and this approach works, so for now this is fine. Thanks to this function, the import sections of the host configs are pretty clean for most hosts. <li><code>mkTrueOption</code>: Defines a nixos module option that is by default enables (as opposed to <code>mkEnableOption</code> which are per default disabled).</li>
<code>lib.optionals</code> evaluates to an empty list (<code>[]</code>) in case that the conditional is not met.</li> <li><code>mkStrong</code>: This function uses <code>nixpkgs.lib.mkOverride</code> in order to set a priority for an expression that is higher than setting an option normally (i.e. <code>option = value</code>;) which has priority 100, while being of lower priority than using <code>nixpkgs.lib.mkForce</code>, which has priority 50 (lower priority takes precedence). For completeness' sake, the priority set when using <code>nixpkgs.lib.mkDefault</code> is 1000 (a very low value).</li>
<li><code>forEachLinuxSystem</code>: performs the <code>pkgsFor</code> function for a set of <code>systems</code> (here: <code>x86_64-linux</code> and <code>aarch64-linux</code>). I need to use this in the <a href="#h:6ed1a641-dba8-4e85-a62e-be93264df57a">Packages (pkgs)</a> section in order to avoid trying to build those packages for darwin systems.</li>
<li><code>readHosts</code>: Reads the names of directories under the <code>hosts/</code> folder for a particular system type
<ul class="org-ul">
<li><code>builtins.readDir</code> reads the name of items of a directory as attributes and their type as values. As an example <code>builtins.readDir ./hosts/nixos</code> ran on this flake yieled at some point the output <code>{ bakery = "directory"; chaostheatre = "directory"; milkywell = "directory"; moonside = "directory"; pyramid = "directory"; toto = "directory"; winters = "directory"; }</code></li>
<li><code>nixpkgs.lib.attrNames</code> is used to aquire these attribute names (you might think of them as the "keys") from the output of <code>builtins.readDir</code></li>
</ul></li>
<li><code>readNix</code>: reads all files in a directory that are not <code>default.nix</code> (usually used to simply load everything from a folder and is called inside that respective <code>default.nix</code>).</li>
<li><code>mk[Modules,Profiles,Imports]</code>: These are used to help with importing files mostly:
<ul class="org-ul">
<li>builtins.listToAttrs converts a list of name-value pairs into an attribute set. <code>builtins.listToAttrs [{ name = "foo"; value = 1; } { name = "bar"; value = 2; }]</code> for example returns <code>{ bar = 2; foo = 1; }</code>.</li>
<li><code>nixpkgs.lib.map</code> takes a function and applies the elements of a list upon them, e.g. <code>lib.map (x: x + 1) [1 2 3]</code> yields <code>[ 2 3 4 ]</code>. This is always used in <code>mkImports</code> to actually import the list of modules that are generated by the other <code>mk[...]</code> options.</li>
</ul></li>
</ul> </ul>
<div class="org-src-container"> <div class="org-src-container">
<pre class="src src-nix-ts">{ self, inputs, ... }: <pre class="src src-nix-ts">{ self, inputs, ... }:
let let
@ -1532,15 +1562,12 @@ let
mkStrong = lib.mkOverride 60; mkStrong = lib.mkOverride 60;
forEachSystem = f: lib.genAttrs (import systems) (system: f pkgsFor.${system}); # forEachSystem = f: lib.genAttrs (import systems) (system: f pkgsFor.${system});
forEachLinuxSystem = f: lib.genAttrs [ "x86_64-linux" "aarch64-linux" ] (system: f pkgsFor.${system}); forEachLinuxSystem = f: lib.genAttrs [ "x86_64-linux" "aarch64-linux" ] (system: f pkgsFor.${system});
readHosts = type: lib.attrNames (builtins.readDir "${self}/hosts/${type}"); readHosts = type: lib.attrNames (builtins.readDir "${self}/hosts/${type}");
readNix = type: lib.filter (name: name != "default.nix") (lib.attrNames (builtins.readDir "${self}/${type}")); readNix = type: lib.filter (name: name != "default.nix") (lib.attrNames (builtins.readDir "${self}/${type}"));
mkModules = names: type: builtins.listToAttrs (map mkModules = names: type: builtins.listToAttrs (map
(name: { (name: {
inherit name; inherit name;
@ -1555,18 +1582,7 @@ let
}) })
names); names);
mkImports = names: baseDir: lib.map (name: "${self}/${baseDir}/${name}") names; mkImports = names: baseDir: lib.map (name: "${self}/${baseDir}/${name}") names;
eachMonitor = _: monitor: {
inherit (monitor) name;
value = builtins.removeAttrs monitor [ "workspace" "name" "output" ];
};
eachOutput = _: monitor: {
inherit (monitor) name;
value = builtins.removeAttrs monitor [ "mode" "name" "scale" "transform" "position" ];
};
}; };
in in
{ {
@ -1585,7 +1601,11 @@ in
<h3 id="h:6ed1a641-dba8-4e85-a62e-be93264df57a"><span class="section-number-3">2.4.</span> Packages (pkgs)</h3> <h3 id="h:6ed1a641-dba8-4e85-a62e-be93264df57a"><span class="section-number-3">2.4.</span> Packages (pkgs)</h3>
<div class="outline-text-3" id="text-h:6ed1a641-dba8-4e85-a62e-be93264df57a"> <div class="outline-text-3" id="text-h:6ed1a641-dba8-4e85-a62e-be93264df57a">
<p> <p>
This does not use <code>perSystem</code> since some of my custom packages are not able to be built on darwin systems, and I was not yet interested in writing logic for handling that. This does not use <code>perSystem</code> from <code>flake-parts</code> since some of my custom packages are not able to be built on darwin systems, and I was not yet interested in writing logic for handling that. Instead I use <code>forEachLinuxSystem</code> as described in <a href="#h:f9b7ffba-b7e2-4554-9a35-ece0bf173e1c">Library functions</a> in roder to only build this for linux hosts.
</p>
<p>
More information on the actual packages build can be found in <a href="#h:64a5cc16-6b16-4802-b421-c67ccef853e1">Packages</a>.
</p> </p>
<div class="org-src-container"> <div class="org-src-container">
@ -1607,7 +1627,22 @@ This does not use <code>perSystem</code> since some of my custom packages are no
<h3 id="h:af83893d-c0f9-4b45-b816-4849110d41b3"><span class="section-number-3">2.5.</span> Globals</h3> <h3 id="h:af83893d-c0f9-4b45-b816-4849110d41b3"><span class="section-number-3">2.5.</span> Globals</h3>
<div class="outline-text-3" id="text-h:af83893d-c0f9-4b45-b816-4849110d41b3"> <div class="outline-text-3" id="text-h:af83893d-c0f9-4b45-b816-4849110d41b3">
<p> <p>
The structure of <code>globals.nix.enc</code> requires a toplevel <code>globals</code>. This file is used to parse each <code>nixosConfiguration</code> present in this flake and scan them for options set under the <code>globals</code> attribute set. I use <code>lib.evalModules</code> to evaluate a mini module system that only consists of these globals options and then load them into the actual configuration by providing a <code>globals</code> output to the flake. This treads a dangerous ground of infinite recursions, which is why both the module system as well as the inherited attributes are kept to the minimal size. Each module has a globals option loaded from a module file which will be separately loaded by this mini-evaluation.
</p>
<ul class="org-ul">
<li><code>nixpkgs.lib.mapAttrsToList</code> converts an attribute set into a list by applying a given function to each name-value pair: <code>lib.mapAttrsToList (name: value: "${name} = ${value}) { a = "1"; b = "2"; }</code> yields the list <code>[ "a = 1" "b = 2" ]</code>. It is used on <code>config.nodes</code>.</li>
<li><code>nixpkgs.lib.flip</code> is used to reverse the function argument order of the <code>mapAttrsToList</code> call, so that we can give the attribute set (<code>config.nodes</code>) first. Alternatively, we could have written <code>lib.mapAttrsToList (name: cfg: [...]) config.nodes</code> but it would be harder to read since there would be a big block between the arguments.</li>
<li><code>nixpkgs.lib.concatLists</code>, as the name suggests, concatenates lists: <code>lib.concatLists [ [ 1 2 ] [ 3 4 ] [ 5 ] ]</code> yields <code>[ 1 2 3 4 5 ]</code>. <code>options.config._globalDefs</code> holds the <code>options.globals.definitions</code> for each node (which in turn basically holds the information that has been set for each node under the <code>globals</code> option), so the concatenated list will look something like <code>[ { services.kanidm.domain = "foo"; }; } { services.freshrss.domain = "bar"; } ]</code>.</li>
<li><code>nixpgks.lib.mkMerge</code> is used to merge these seperate attribute sets in the list into one big attribute set (the above attribute set example would become then <code>{ services = { kanidm.domain = "foo"; freshrss.domain = "bar"; }; }</code>. You can see how this can now be referenced as a "global" set.</li>
</ul>
<p>
I also have a file for global values that cannot be attributed to one <code>nixosConfiguration</code> alsone; the structure of this <code>globals.nix.enc</code> requires a toplevel <code>globals</code> - that means, <code>globals.nix.enc</code> has the structure <code>{ globals = [...] }</code>.
</p>
<p>
Lastly, in order make this actually available to my configurations, i use the <code>inherit (globalsSystem.config.globals) [...]</code> which produces the <code>globals</code> output which I will pass to the <code>specialArgs</code> of my <code>nixosConfigurations</code>, which is when I will be finally able to use these definitions in my config.
</p> </p>
<div class="org-src-container"> <div class="org-src-container">
@ -1680,6 +1715,19 @@ The structure of <code>globals.nix.enc</code> requires a toplevel <code>globals<
<div id="outline-container-h:5c5bf78a-9a66-436f-bd85-85871d9d402b" class="outline-3"> <div id="outline-container-h:5c5bf78a-9a66-436f-bd85-85871d9d402b" class="outline-3">
<h3 id="h:5c5bf78a-9a66-436f-bd85-85871d9d402b"><span class="section-number-3">2.6.</span> Hosts</h3> <h3 id="h:5c5bf78a-9a66-436f-bd85-85871d9d402b"><span class="section-number-3">2.6.</span> Hosts</h3>
<div class="outline-text-3" id="text-h:5c5bf78a-9a66-436f-bd85-85871d9d402b"> <div class="outline-text-3" id="text-h:5c5bf78a-9a66-436f-bd85-85871d9d402b">
<p>
Here I define my hosts. Earlier (in <a href="#h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b">flake.nix skeleton</a>), I told you how I used to use noweb-ref blocks to achieve this task. You see, a single <code>nixosConfiguration</code> uses <code>nixpkgs.lib.nixosSystem</code>, passing modules and arguments to define itself. I have automated this process by reading all directories in the <code>hosts/</code> directory and then applying <code>nixpkgs.lib.nixosSystem</code> as a function on these returns. I also provide a <code>nixosConfigurationsMinimal</code> output which is ingested by the flake in <code>install/flake.nix</code> to be used during the initial deployment of a new system (it basically just disables most modules).
</p>
<ul class="org-ul">
<li><code>mkNixosHost</code>: Very much akin to a simple call of <code>nixpkgs.lib.nixosSystem</code>, I simply define <code>specialArgs</code> and <code>modules</code> that I want to use for every configuration. Here, I load all the extra modules from my other input flakes. Also, I add the <code>globals</code> output from <a href="#h:af83893d-c0f9-4b45-b816-4849110d41b3">Globals</a> and the <code>nodes</code> output that I define right here (it simply mirrors all "full" configurations - nixOS and darwin. I like to refer to home-manager only and nix-on-droid as a "half" configurations). It is also here that I set the node name for the configuration (I prefer this explicit call over referencing <code>networking.hostName</code> or such) and the directory that should be used for secrets of a configuration.</li>
<li><code>mkDarwinHost</code> works in the same way but for darwin machines.</li>
<li><code>mkFullHostConfigs</code> is the function that dynamically creates all definded hosts. The hosts are defined by placing a directory in <code>hosts/</code> under either the <code>nixos/</code> or <code>darwin/</code> directory. These directories are being read by <code>readHosts</code> and delivered to this funtion in the later call in [BROKEN LINK: h:9c9b9e3b-8771-44fa-ba9e-5056ae809655] or [BROKEN LINK: h:f881aa05-a670-48dd-a57b-2916abdcb692].</li>
<li><code>mkFullHost</code>:
This is a function that takes a hostname as well as a boolean whether it is NixOS or not, and returns a matching <code>nixosSystem</code> or <code>darwinSystem</code>. This function is only used for systems that can use both NixOS and home-manager options (darwin still counts here as it can use some NixOS options). This is used in mkFullHostConfigs. In more detail, it dynamically creates a nixosConfiguration host, setting its <code>speciaArgs</code> and <code>modules</code> attributes. The modules are populated based on whether this is a NixOS or darwin host. For the latter, I will only ever use machines that I get for testing from work, and for these my username is different, so I implemented an if-condition for it. This could be done more cleanly using variables, but some care needs to be taken with the home-manager imports and this approach works, so for now this is fine. Thanks to this function, the import sections of the host configs are pretty clean for most hosts.</li>
</ul>
<div class="org-src-container"> <div class="org-src-container">
<pre class="src src-nix-ts">{ self, inputs, ... }: <pre class="src src-nix-ts">{ self, inputs, ... }:
{ {
@ -1910,7 +1958,7 @@ The structure of <code>globals.nix.enc</code> requires a toplevel <code>globals<
connections = { connections = {
eth2 = mkConnection "nswitch" "eth1"; eth2 = mkConnection "nswitch" "eth1";
eth7 = mkConnection "pc" "eth1"; eth7 = mkConnection "pc" "eth1";
eth8 = mkConnection "nbl-imba-2" "eth1"; eth8 = mkConnection "pyramid" "eth1";
}; };
}; };
@ -1926,7 +1974,7 @@ The structure of <code>globals.nix.enc</code> requires a toplevel <code>globals<
interfaces.eth1 = { }; interfaces.eth1 = { };
}; };
nbl-imba-2.interfaces.eth1 = { }; pyramid.interfaces.eth1 = { };
switch-bedroom = mkSwitch "Switch Bedroom" { switch-bedroom = mkSwitch "Switch Bedroom" {
info = "TL-SG1005D"; info = "TL-SG1005D";
@ -2641,7 +2689,7 @@ This is a list of all physical machines that I maintain.
</p> </p>
</div> </div>
<div id="outline-container-h:6c6e9261-dfa1-42d8-ab2a-8b7c227be6d9" class="outline-5"> <div id="outline-container-h:6c6e9261-dfa1-42d8-ab2a-8b7c227be6d9" class="outline-5">
<h5 id="h:6c6e9261-dfa1-42d8-ab2a-8b7c227be6d9"><span class="section-number-5">3.1.2.1.</span> nbl-imba-2 (Framework Laptop 16)</h5> <h5 id="h:6c6e9261-dfa1-42d8-ab2a-8b7c227be6d9"><span class="section-number-5">3.1.2.1.</span> pyramid (Framework Laptop 16)</h5>
<div class="outline-text-5" id="text-h:6c6e9261-dfa1-42d8-ab2a-8b7c227be6d9"> <div class="outline-text-5" id="text-h:6c6e9261-dfa1-42d8-ab2a-8b7c227be6d9">
<p> <p>
My work machine. Built for more security, this is the gold standard of my configurations at the moment. My work machine. Built for more security, this is the gold standard of my configurations at the moment.
@ -3271,7 +3319,7 @@ in
</div> </div>
</div> </div>
<div id="outline-container-h:28e1a7eb-356b-4015-83f7-9c552c8c0e9d" class="outline-5"> <div id="outline-container-h:28e1a7eb-356b-4015-83f7-9c552c8c0e9d" class="outline-5">
<h5 id="h:28e1a7eb-356b-4015-83f7-9c552c8c0e9d"><span class="section-number-5">3.1.2.4.</span> nbm-imba-166 (MacBook Pro)</h5> <h5 id="h:28e1a7eb-356b-4015-83f7-9c552c8c0e9d"><span class="section-number-5">3.1.2.4.</span> machpizza (MacBook Pro)</h5>
<div class="outline-text-5" id="text-h:28e1a7eb-356b-4015-83f7-9c552c8c0e9d"> <div class="outline-text-5" id="text-h:28e1a7eb-356b-4015-83f7-9c552c8c0e9d">
<p> <p>
A Mac notebook that I have received from work. I use this machine for getting accustomed to the Apple ecosystem as well as as a sandbox for nix-darwin configurations. A Mac notebook that I have received from work. I use this machine for getting accustomed to the Apple ecosystem as well as as a sandbox for nix-darwin configurations.
@ -14226,6 +14274,12 @@ Currently, I am too lazy to explain every option here, but most of it is very se
<div class="org-src-container"> <div class="org-src-container">
<pre class="src src-nix-ts">{ self, config, lib, ... }: <pre class="src src-nix-ts">{ self, config, lib, ... }:
let
eachOutput = _: monitor: {
inherit (monitor) name;
value = builtins.removeAttrs monitor [ "mode" "name" "scale" "transform" "position" ];
};
in
{ {
options.swarselsystems = { options.swarselsystems = {
modules.sway = lib.mkEnableOption "sway settings"; modules.sway = lib.mkEnableOption "sway settings";
@ -14281,15 +14335,15 @@ Currently, I am too lazy to explain every option here, but most of it is very se
swayfxConfig = lib.mkOption { swayfxConfig = lib.mkOption {
type = lib.types.str; type = lib.types.str;
default = " default = "
blur enable blur enable
blur_xray disable blur_xray disable
blur_passes 1 blur_passes 1
blur_radius 1 blur_radius 1
shadows enable shadows enable
corner_radius 2 corner_radius 2
titlebar_separator disable titlebar_separator disable
default_dim_inactive 0.02 default_dim_inactive 0.02
"; ";
internal = true; internal = true;
}; };
}; };
@ -14436,7 +14490,6 @@ Currently, I am too lazy to explain every option here, but most of it is very se
}; };
}; };
defaultWorkspace = "workspace 1:一"; defaultWorkspace = "workspace 1:一";
# output = lib.mapAttrs' lib.swarselsystems.eachMonitor monitors;
output = { output = {
"${config.swarselsystems.sharescreen}" = { "${config.swarselsystems.sharescreen}" = {
bg = "${self}/files/wallpaper/lenovowp.png ${config.stylix.imageScalingMode}"; bg = "${self}/files/wallpaper/lenovowp.png ${config.stylix.imageScalingMode}";
@ -14448,7 +14501,7 @@ Currently, I am too lazy to explain every option here, but most of it is very se
input = config.swarselsystems.standardinputs; input = config.swarselsystems.standardinputs;
workspaceOutputAssign = workspaceOutputAssign =
let let
workplaceSets = lib.mapAttrs' lib.swarselsystems.eachOutput config.swarselsystems.monitors; workplaceSets = lib.mapAttrs' eachOutput config.swarselsystems.monitors;
workplaceOutputs = map (key: lib.getAttr key workplaceSets) (lib.attrNames workplaceSets); workplaceOutputs = map (key: lib.getAttr key workplaceSets) (lib.attrNames workplaceSets);
in in
workplaceOutputs; workplaceOutputs;
@ -14597,36 +14650,36 @@ Currently, I am too lazy to explain every option here, but most of it is very se
swayfxSettings = config.swarselsystems.swayfxConfig; swayfxSettings = config.swarselsystems.swayfxConfig;
in in
" "
exec_always autotiling exec_always autotiling
set $exit \"exit: [s]leep, [l]ock, [p]oweroff, [r]eboot, [u]ser logout\" set $exit \"exit: [s]leep, [l]ock, [p]oweroff, [r]eboot, [u]ser logout\"
mode $exit { mode $exit {
bindsym --to-code { bindsym --to-code {
s exec \"systemctl suspend\", mode \"default\" s exec \"systemctl suspend\", mode \"default\"
h exec \"systemctl hibernate\", mode \"default\" h exec \"systemctl hibernate\", mode \"default\"
l exec \"swaylock --screenshots --clock --effect-blur 7x5 --effect-vignette 0.5:0.5 --fade-in 0.2 --daemonize\", mode \"default\ l exec \"swaylock --screenshots --clock --effect-blur 7x5 --effect-vignette 0.5:0.5 --fade-in 0.2 --daemonize\", mode \"default\
p exec \"systemctl poweroff\" p exec \"systemctl poweroff\"
r exec \"systemctl reboot\" r exec \"systemctl reboot\"
u exec \"swaymsg exit\" u exec \"swaymsg exit\"
Return mode \"default\" Return mode \"default\"
Escape mode \"default\" Escape mode \"default\"
${modifier}+Escape mode \"default\" ${modifier}+Escape mode \"default\"
}
} }
}
exec systemctl --user import-environment exec systemctl --user import-environment
exec swayidle -w exec swayidle -w
seat * hide_cursor 2000 seat * hide_cursor 2000
exec_always kill -1 $(pidof kanshi) exec_always kill -1 $(pidof kanshi)
bindswitch --locked lid:on exec kanshictl switch lidclosed bindswitch --locked lid:on exec kanshictl switch lidclosed
bindswitch --locked lid:off exec kanshictl switch lidopen bindswitch --locked lid:off exec kanshictl switch lidopen
${swayfxSettings} ${swayfxSettings}
"; ";
}; };
}; };
} }
@ -20440,8 +20493,8 @@ This adds a rudimentary nix-mode to Emacs. I have not really tried this out, as
(setq lsp-nix-nixd-server-path "nixd" (setq lsp-nix-nixd-server-path "nixd"
lsp-nix-nixd-formatting-command [ "nixpkgs-fmt" ] lsp-nix-nixd-formatting-command [ "nixpkgs-fmt" ]
lsp-nix-nixd-nixpkgs-expr "import (builtins.getFlake \"/home/swarsel/.dotfiles\").inputs.nixpkgs { }" lsp-nix-nixd-nixpkgs-expr "import (builtins.getFlake \"/home/swarsel/.dotfiles\").inputs.nixpkgs { }"
lsp-nix-nixd-nixos-options-expr "(builtins.getFlake \"/home/swarsel/.dotfiles\").nixosConfigurations.nbl-imba-2.options" lsp-nix-nixd-nixos-options-expr "(builtins.getFlake \"/home/swarsel/.dotfiles\").nixosConfigurations.pyramid.options"
lsp-nix-nixd-home-manager-options-expr "(builtins.getFlake \"/home/swarsel/.dotfiles\").nixosConfigurations.nbl-imba-2.options.home-manager.users.type.getSubOptions []" lsp-nix-nixd-home-manager-options-expr "(builtins.getFlake \"/home/swarsel/.dotfiles\").nixosConfigurations.pyramid.options.home-manager.users.type.getSubOptions []"
)) ))
(use-package nix-ts-mode (use-package nix-ts-mode
@ -20456,8 +20509,8 @@ This adds a rudimentary nix-mode to Emacs. I have not really tried this out, as
(setq lsp-nix-nixd-server-path "nixd" (setq lsp-nix-nixd-server-path "nixd"
lsp-nix-nixd-formatting-command [ "nixpkgs-fmt" ] lsp-nix-nixd-formatting-command [ "nixpkgs-fmt" ]
lsp-nix-nixd-nixpkgs-expr "import (builtins.getFlake \"/home/swarsel/.dotfiles\").inputs.nixpkgs { }" lsp-nix-nixd-nixpkgs-expr "import (builtins.getFlake \"/home/swarsel/.dotfiles\").inputs.nixpkgs { }"
lsp-nix-nixd-nixos-options-expr "(builtins.getFlake \"/home/swarsel/.dotfiles\").nixosConfigurations.nbl-imba-2.options" lsp-nix-nixd-nixos-options-expr "(builtins.getFlake \"/home/swarsel/.dotfiles\").nixosConfigurations.pyramid.options"
lsp-nix-nixd-home-manager-options-expr "(builtins.getFlake \"/home/swarsel/.dotfiles\").nixosConfigurations.nbl-imba-2.options.home-manager.users.type.getSubOptions []" lsp-nix-nixd-home-manager-options-expr "(builtins.getFlake \"/home/swarsel/.dotfiles\").nixosConfigurations.pyramid.options.home-manager.users.type.getSubOptions []"
)) ))
@ -24304,16 +24357,17 @@ Alternatively, to install this from any NixOS live ISO, run `nix run --experimen
| Name | Hardware | Use | | Name | Hardware | Use |
|--------------------|-----------------------------------------------------|------------------------------------------------------| |--------------------|-----------------------------------------------------|------------------------------------------------------|
|💻 **nbl-imba-2** | Framework Laptop 16, AMD 7940HS, RX 7700S, 64GB RAM | Work laptop | |💻 **pyramid** | Framework Laptop 16, AMD 7940HS, RX 7700S, 64GB RAM | Work laptop |
|💻 **nbm-imba-166** | MacBook Pro 2016 | MacOS Sandbox | |💻 **bakery** | Lenovo Ideapad 720S-13IKB | Personal lapto |
|💻 **machpizza** | MacBook Pro 2016 | MacOS sandbox |
|🖥️ **winters** | ASRock J4105-ITX, 32GB RAM | Main homeserver and data storgae | |🖥️ **winters** | ASRock J4105-ITX, 32GB RAM | Main homeserver and data storgae |
|🖥️ **milkywell** | Oracle Cloud: VM.Standard.E2.1.Micro | Server for lightweight synchronization tasks | |🖥️ **milkywell** | Oracle Cloud: VM.Standard.E2.1.Micro | Server for lightweight synchronization tasks |
|🖥️ **moonside** | Oracle Cloud: VM.Standard.A1.Flex, 4 OCPUs, 24GB RAM| Proxy for local services, some lightweight services | |🖥️ **moonside** | Oracle Cloud: VM.Standard.A1.Flex, 4 OCPUs, 24GB RAM| Proxy for local services, some lightweight services |
|📱 **magicant** | Samsung Galaxy Z Flip 6 | Phone | |📱 **magicant** | Samsung Galaxy Z Flip 6 | Phone |
|💿 **drugstore** | - | ISO installer configuration | |💿 **drugstore** | - | ISO installer configuration |
|❔ **chaotheatre** | - | Demo config for checking out my configurtion | |❔ **chaotheatre** | - | Demo config for checking out my configurtion |
|❔ **toto** | - | Helper configuration for bootstrapping a new system | |❔ **toto** | - | Helper configuration for bootstrapping a new system |
|🏠 **Treehouse** | - | Reference configuration for a home-manager only host | |🏠 **treehouse** | - | Reference configuration for a home-manager only host |
&lt;/details&gt; &lt;/details&gt;
## General Nix tips &amp; useful links ## General Nix tips &amp; useful links
@ -24442,7 +24496,7 @@ If you feel that I forgot to pay you tribute for code that I used in this reposi
</div> </div>
<div id="postamble" class="status"> <div id="postamble" class="status">
<p class="author">Author: Leon Schwarzäugl</p> <p class="author">Author: Leon Schwarzäugl</p>
<p class="date">Created: 2025-07-14 Mo 01:07</p> <p class="date">Created: 2025-07-14 Mo 03:07</p>
<p class="validation"><a href="https://validator.w3.org/check?uri=referer">Validate</a></p> <p class="validation"><a href="https://validator.w3.org/check?uri=referer">Validate</a></p>
</div> </div>
</body> </body>

View file

@ -1,4 +1,10 @@
{ self, config, lib, ... }: { self, config, lib, ... }:
let
eachOutput = _: monitor: {
inherit (monitor) name;
value = builtins.removeAttrs monitor [ "mode" "name" "scale" "transform" "position" ];
};
in
{ {
options.swarselsystems = { options.swarselsystems = {
modules.sway = lib.mkEnableOption "sway settings"; modules.sway = lib.mkEnableOption "sway settings";
@ -54,15 +60,15 @@
swayfxConfig = lib.mkOption { swayfxConfig = lib.mkOption {
type = lib.types.str; type = lib.types.str;
default = " default = "
blur enable blur enable
blur_xray disable blur_xray disable
blur_passes 1 blur_passes 1
blur_radius 1 blur_radius 1
shadows enable shadows enable
corner_radius 2 corner_radius 2
titlebar_separator disable titlebar_separator disable
default_dim_inactive 0.02 default_dim_inactive 0.02
"; ";
internal = true; internal = true;
}; };
}; };
@ -209,7 +215,6 @@
}; };
}; };
defaultWorkspace = "workspace 1:"; defaultWorkspace = "workspace 1:";
# output = lib.mapAttrs' lib.swarselsystems.eachMonitor monitors;
output = { output = {
"${config.swarselsystems.sharescreen}" = { "${config.swarselsystems.sharescreen}" = {
bg = "${self}/files/wallpaper/lenovowp.png ${config.stylix.imageScalingMode}"; bg = "${self}/files/wallpaper/lenovowp.png ${config.stylix.imageScalingMode}";
@ -221,7 +226,7 @@
input = config.swarselsystems.standardinputs; input = config.swarselsystems.standardinputs;
workspaceOutputAssign = workspaceOutputAssign =
let let
workplaceSets = lib.mapAttrs' lib.swarselsystems.eachOutput config.swarselsystems.monitors; workplaceSets = lib.mapAttrs' eachOutput config.swarselsystems.monitors;
workplaceOutputs = map (key: lib.getAttr key workplaceSets) (lib.attrNames workplaceSets); workplaceOutputs = map (key: lib.getAttr key workplaceSets) (lib.attrNames workplaceSets);
in in
workplaceOutputs; workplaceOutputs;
@ -370,36 +375,36 @@
swayfxSettings = config.swarselsystems.swayfxConfig; swayfxSettings = config.swarselsystems.swayfxConfig;
in in
" "
exec_always autotiling exec_always autotiling
set $exit \"exit: [s]leep, [l]ock, [p]oweroff, [r]eboot, [u]ser logout\" set $exit \"exit: [s]leep, [l]ock, [p]oweroff, [r]eboot, [u]ser logout\"
mode $exit { mode $exit {
bindsym --to-code { bindsym --to-code {
s exec \"systemctl suspend\", mode \"default\" s exec \"systemctl suspend\", mode \"default\"
h exec \"systemctl hibernate\", mode \"default\" h exec \"systemctl hibernate\", mode \"default\"
l exec \"swaylock --screenshots --clock --effect-blur 7x5 --effect-vignette 0.5:0.5 --fade-in 0.2 --daemonize\", mode \"default\ l exec \"swaylock --screenshots --clock --effect-blur 7x5 --effect-vignette 0.5:0.5 --fade-in 0.2 --daemonize\", mode \"default\
p exec \"systemctl poweroff\" p exec \"systemctl poweroff\"
r exec \"systemctl reboot\" r exec \"systemctl reboot\"
u exec \"swaymsg exit\" u exec \"swaymsg exit\"
Return mode \"default\" Return mode \"default\"
Escape mode \"default\" Escape mode \"default\"
${modifier}+Escape mode \"default\" ${modifier}+Escape mode \"default\"
}
} }
}
exec systemctl --user import-environment exec systemctl --user import-environment
exec swayidle -w exec swayidle -w
seat * hide_cursor 2000 seat * hide_cursor 2000
exec_always kill -1 $(pidof kanshi) exec_always kill -1 $(pidof kanshi)
bindswitch --locked lid:on exec kanshictl switch lidclosed bindswitch --locked lid:on exec kanshictl switch lidclosed
bindswitch --locked lid:off exec kanshictl switch lidopen bindswitch --locked lid:off exec kanshictl switch lidopen
${swayfxSettings} ${swayfxSettings}
"; ";
}; };
}; };
} }

View file

@ -1,4 +1,8 @@
{ lib, config, pkgs, ... }: { lib, config, pkgs, ... }:
let
inherit (config.swarselsystems) mainUser;
inherit (config.repo.secrets.common.yubikeys) cfg1 cfg2;
in
{ {
options.swarselsystems.modules.yubikey = lib.mkEnableOption "yubikey config"; options.swarselsystems.modules.yubikey = lib.mkEnableOption "yubikey config";
config = lib.mkIf config.swarselsystems.modules.yubikey { config = lib.mkIf config.swarselsystems.modules.yubikey {
@ -8,6 +12,21 @@
hardware.gpgSmartcards.enable = true; hardware.gpgSmartcards.enable = true;
security.pam.u2f = {
enable = true;
control = "sufficient";
settings = {
interactive = false; # displays a prompt BEFORE asking for presence
cue = true; # prints a message that a touch is requrired
origin = "pam://${mainUser}"; # make the keys work on all machines
authfile = pkgs.writeText "u2f-mappings" (lib.concatStrings [
mainUser
cfg1
cfg2
]);
};
};
services.udev.packages = with pkgs; [ services.udev.packages = with pkgs; [
yubikey-personalization yubikey-personalization
]; ];

View file

@ -41,15 +41,12 @@ let
mkStrong = lib.mkOverride 60; mkStrong = lib.mkOverride 60;
forEachSystem = f: lib.genAttrs (import systems) (system: f pkgsFor.${system}); # forEachSystem = f: lib.genAttrs (import systems) (system: f pkgsFor.${system});
forEachLinuxSystem = f: lib.genAttrs [ "x86_64-linux" "aarch64-linux" ] (system: f pkgsFor.${system}); forEachLinuxSystem = f: lib.genAttrs [ "x86_64-linux" "aarch64-linux" ] (system: f pkgsFor.${system});
readHosts = type: lib.attrNames (builtins.readDir "${self}/hosts/${type}"); readHosts = type: lib.attrNames (builtins.readDir "${self}/hosts/${type}");
readNix = type: lib.filter (name: name != "default.nix") (lib.attrNames (builtins.readDir "${self}/${type}")); readNix = type: lib.filter (name: name != "default.nix") (lib.attrNames (builtins.readDir "${self}/${type}"));
mkModules = names: type: builtins.listToAttrs (map mkModules = names: type: builtins.listToAttrs (map
(name: { (name: {
inherit name; inherit name;
@ -64,18 +61,7 @@ let
}) })
names); names);
mkImports = names: baseDir: lib.map (name: "${self}/${baseDir}/${name}") names; mkImports = names: baseDir: lib.map (name: "${self}/${baseDir}/${name}") names;
eachMonitor = _: monitor: {
inherit (monitor) name;
value = builtins.removeAttrs monitor [ "workspace" "name" "output" ];
};
eachOutput = _: monitor: {
inherit (monitor) name;
value = builtins.removeAttrs monitor [ "mode" "name" "scale" "transform" "position" ];
};
}; };
in in
{ {

View file

@ -8,7 +8,7 @@
general = lib.mkDefault true; general = lib.mkDefault true;
nixgl = lib.mkDefault true; nixgl = lib.mkDefault true;
sops = lib.mkDefault true; sops = lib.mkDefault true;
yubikey = lib.mkDefault true; yubikey = lib.mkDefault false;
ssh = lib.mkDefault true; ssh = lib.mkDefault true;
stylix = lib.mkDefault true; stylix = lib.mkDefault true;
desktop = lib.mkDefault true; desktop = lib.mkDefault true;

View file

@ -1,5 +1,5 @@
{ {
"data": "ENC[AES256_GCM,data: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,iv:i2EIMD409Y6wYhRwVjLtf30m2pR3JtFDqT+VnFBaTz8=,tag:03MllePz2dHzk5IW+DmvHw==,type:str]", "data": "ENC[AES256_GCM,data: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,iv:pEDV2WLEFisblx+XrhuoaNpxtk4Byj+jB/ixhsk3uPQ=,tag:T4xI5g6sIrIobuSuViG5+A==,type:str]",
"sops": { "sops": {
"age": [ "age": [
{ {
@ -27,8 +27,8 @@
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtU240VjVRZmJ5TGsrclJF\nRXRLbTRCZURtR0Z3d2E2eDNNeGRDODlXVEY4CllTeVFYbDJQWlRSS1RFLzAxSnlM\nZi9NU1c3cWo3YWRLcUJ2U2ZFWFBBVEEKLS0tIGtmZU9qSWdBT3RDeStaaFFDSWtk\ndkUzZXJwZUl4LzVxYXdidmxXRnNnclUKyAMZqCKSY/RQvTR4bbjLaPnGKwdBcHXc\nvtiVSrLdIdzMa6id/J07TJH5UesUmcp0wjU41MDa4aMBLy+cXhuBHA==\n-----END AGE ENCRYPTED FILE-----\n" "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtU240VjVRZmJ5TGsrclJF\nRXRLbTRCZURtR0Z3d2E2eDNNeGRDODlXVEY4CllTeVFYbDJQWlRSS1RFLzAxSnlM\nZi9NU1c3cWo3YWRLcUJ2U2ZFWFBBVEEKLS0tIGtmZU9qSWdBT3RDeStaaFFDSWtk\ndkUzZXJwZUl4LzVxYXdidmxXRnNnclUKyAMZqCKSY/RQvTR4bbjLaPnGKwdBcHXc\nvtiVSrLdIdzMa6id/J07TJH5UesUmcp0wjU41MDa4aMBLy+cXhuBHA==\n-----END AGE ENCRYPTED FILE-----\n"
} }
], ],
"lastmodified": "2025-07-05T11:16:37Z", "lastmodified": "2025-07-14T02:08:47Z",
"mac": "ENC[AES256_GCM,data:gdnY/T7kDdSzGR9FCrnMJdBhBgr3ruveVnMGnFFjydVeJeZCLkDYdGHxyoaywrJ/KQpx3OpIai/DwzDVQmNjNhC66cEE11xovLV37IzxXY2+2kFqeosIFMaAiA4vZuTBml9YbVMschGZypPwXn9rkjJxaFH0pVt3CJaNbaBn/tQ=,iv:LYHfq3rxkD1c4hvDl605Tp3OlQ4hSocSPnb2uynuc2g=,tag:Rtx8g+1CgIkrAcmsaI92KA==,type:str]", "mac": "ENC[AES256_GCM,data:ZT2q2cHleWw+h7JNzWi+UnFo7G72xMMjzkbr4Ixp09xT9jqHjeHRitRveoNyh8jcRSbWxVeYf1fpKEKPEAxqU77NORhD/QBFjQm1iG/UH/xkRNBTQ/kE+yp/6jlkyfJ/m8ulTSbegz2eQkko9HP9qG7+QMcESP6zE7ko8UFPXAY=,iv:AvQDzn9kQYj1cr6K/luFZkv2G1UAQT27cA9/pQMRJl0=,tag:uuH3aZSI644HrJXYR5I7UQ==,type:str]",
"pgp": [ "pgp": [
{ {
"created_at": "2025-06-13T20:13:06Z", "created_at": "2025-06-13T20:13:06Z",