Compare commits

...

4 commits

Author SHA1 Message Date
Leon Schwarzäugl
ca35e7894d
feat[server]: add initial router config 2025-11-10 01:31:02 +01:00
Leon Schwarzäugl
30a97098af
feat[server]: preparations for router config 2025-11-10 01:30:56 +01:00
Leon Schwarzäugl
e1569ba472
fix: bootstrap script not working with nix-plugins 2025-11-10 01:23:50 +01:00
Leon Schwarzäugl
a5a1afed3d
feat: build configurations dynamically for arch 2025-11-10 01:19:13 +01:00
83 changed files with 1618 additions and 529 deletions

2
.github/README.md vendored
View file

@ -79,7 +79,7 @@
#### Remote deployment (recommended if you have at least one running system) #### Remote deployment (recommended if you have at least one running system)
0) Fork this repo, and write your own host config at `hosts/nixos/<YOUR_CONFIG_NAME>/default.nix` (you can use one of the other configurations as a template. Also see https://github.com/Swarsel/.dotfiles/tree/main/modules for a list of all additional options). At the very least, you should replace the `secrets/` directory with your own secrets and replace the SSH public keys with your own ones (otherwise I will come visit you!🔓❤️). I personally recommend to use the literate configuration and `org-babel-tangle-file` in Emacs, but you can also simply edit the separate `.nix` files. 0) Fork this repo, and write your own host config at `hosts/nixos/<YOUR_ARCHITECTURE>/<YOUR_CONFIG_NAME>/default.nix` (you can use one of the other configurations as a template. Also see https://github.com/Swarsel/.dotfiles/tree/main/modules for a list of all additional options). At the very least, you should replace the `secrets/` directory with your own secrets and replace the SSH public keys with your own ones (otherwise I will come visit you!🔓❤️). I personally recommend to use the literate configuration and `org-babel-tangle-file` in Emacs, but you can also simply edit the separate `.nix` files.
1) Have a system with `nix` available booted (this does not need to be installed, i.e. you can use a NixOS installer image; a custom minimal installer ISO can be built by running `just iso` in the root of this repo) 1) Have a system with `nix` available booted (this does not need to be installed, i.e. you can use a NixOS installer image; a custom minimal installer ISO can be built by running `just iso` in the root of this repo)
2) Make sure that your Yubikey is plugged in or that you have your SSH key available (and configured) 2) Make sure that your Yubikey is plugged in or that you have your SSH key available (and configured)
3) Run `swarsel-bootstrap -n <CONFIGURATION_NAME> -d <TARGET_IP>` on your existing system. 3) Run `swarsel-bootstrap -n <CONFIGURATION_NAME> -d <TARGET_IP>` on your existing system.

View file

@ -62,7 +62,7 @@ creation_rules:
- *swarsel - *swarsel
age: age:
- *nbl - *nbl
- path_regex: hosts/nixos/pyramid/secrets/pii.nix.enc - path_regex: hosts/nixos/x86_64-linux/pyramid/secrets/pii.nix.enc
key_groups: key_groups:
- pgp: - pgp:
- *swarsel - *swarsel
@ -75,7 +75,7 @@ creation_rules:
- *swarsel - *swarsel
age: age:
- *moonside - *moonside
- path_regex: hosts/nixos/moonside/secrets/pii.nix.enc - path_regex: hosts/nixos/aarch64-linux/moonside/secrets/pii.nix.enc
key_groups: key_groups:
- pgp: - pgp:
- *swarsel - *swarsel
@ -88,7 +88,7 @@ creation_rules:
- *swarsel - *swarsel
age: age:
- *bakery - *bakery
- path_regex: hosts/nixos/bakery/secrets/pii.nix.enc - path_regex: hosts/nixos/x86_64-linux/bakery/secrets/pii.nix.enc
key_groups: key_groups:
- pgp: - pgp:
- *swarsel - *swarsel
@ -101,7 +101,7 @@ creation_rules:
- *swarsel - *swarsel
age: age:
- *winters - *winters
- path_regex: hosts/nixos/winters/secrets/pii.nix.enc - path_regex: hosts/nixos/x86_64-linux/winters/secrets/pii.nix.enc
key_groups: key_groups:
- pgp: - pgp:
- *swarsel - *swarsel
@ -115,14 +115,19 @@ creation_rules:
- *swarsel - *swarsel
age: age:
- *milkywell - *milkywell
- path_regex: hosts/nixos/milkywell/secrets/pii.nix.enc - path_regex: hosts/nixos/aarch64-linux/milkywell/secrets/pii.nix.enc
key_groups: key_groups:
- pgp: - pgp:
- *swarsel - *swarsel
age: age:
- *milkywell - *milkywell
- path_regex: hosts/nixos/summers/secrets/ - path_regex: hosts/nixos/x86_64-linux/summers/secrets/
key_groups:
- pgp:
- *swarsel
- path_regex: hosts/nixos/x86_64-linux/hintbooth/secrets/
key_groups: key_groups:
- pgp: - pgp:
- *swarsel - *swarsel

File diff suppressed because it is too large Load diff

View file

@ -3,6 +3,7 @@ set -eo pipefail
target_hostname="" target_hostname=""
target_destination="" target_destination=""
target_arch=""
target_user="swarsel" target_user="swarsel"
ssh_port="22" ssh_port="22"
persist_dir="" persist_dir=""
@ -18,6 +19,7 @@ function help_and_exit() {
echo "ARGS:" echo "ARGS:"
echo " -n <target_hostname> specify target_hostname of the target host to deploy the nixos config on." echo " -n <target_hostname> specify target_hostname of the target host to deploy the nixos config on."
echo " -d <target_destination> specify ip or url to the target host." echo " -d <target_destination> specify ip or url to the target host."
echo " -a <targeit_arch> specify the architecture of the target host."
echo " target during install process." echo " target during install process."
echo echo
echo "OPTIONS:" echo "OPTIONS:"
@ -100,6 +102,10 @@ while [[ $# -gt 0 ]]; do
shift shift
target_destination=$1 target_destination=$1
;; ;;
-a)
shift
target_arch=$1
;;
-u) -u)
shift shift
target_user=$1 target_user=$1
@ -120,6 +126,11 @@ while [[ $# -gt 0 ]]; do
shift shift
done done
if [[ $target_arch == "" || $target_destination == "" || $target_hostname == "" ]]; then
red "error: target_arch, target_destination or target_hostname not set."
help_and_exit
fi
green "~SwarselSystems~ remote installer" green "~SwarselSystems~ remote installer"
green "Reading system information for $target_hostname ..." green "Reading system information for $target_hostname ..."
@ -174,6 +185,7 @@ if [ ! -d "$FLAKE" ]; then
fi fi
cd "$FLAKE" cd "$FLAKE"
rm install/flake.lock || true rm install/flake.lock || true
git_root=$(git rev-parse --show-toplevel) git_root=$(git rev-parse --show-toplevel)
# ------------------------ # ------------------------
@ -211,8 +223,12 @@ fi
green "Generating hardware-config.nix for $target_hostname and adding it to the nix-config." green "Generating hardware-config.nix for $target_hostname and adding it to the nix-config."
$ssh_root_cmd "nixos-generate-config --force --no-filesystems --root /mnt" $ssh_root_cmd "nixos-generate-config --force --no-filesystems --root /mnt"
mkdir -p "$FLAKE"/hosts/nixos/"$target_hostname" mkdir -p "$FLAKE"/hosts/nixos/"$target_arch"/"$target_hostname"
$scp_cmd root@"$target_destination":/mnt/etc/nixos/hardware-configuration.nix "${git_root}"/hosts/nixos/"$target_hostname"/hardware-configuration.nix $scp_cmd root@"$target_destination":/mnt/etc/nixos/hardware-configuration.nix "${git_root}"/hosts/nixos/"$target_arch"/"$target_hostname"/hardware-configuration.nix
# ------------------------
green "Generating hostkey for ssh initrd"
$ssh_root_cmd "mkdir -p /mnt/etc/secrets/initrd"
$ssh_root_cmd "ssh-keygen -t ed25519 -N "" -f /mnt/etc/secrets/initrd/ssh_host_ed25519_key"
# ------------------------ # ------------------------
green "Deploying minimal NixOS installation on $target_destination" green "Deploying minimal NixOS installation on $target_destination"
@ -277,7 +293,7 @@ if yes_or_no "Do you want to manually edit .sops.yaml now?"; then
fi fi
green "Updating all secrets files to reflect updates .sops.yaml" green "Updating all secrets files to reflect updates .sops.yaml"
sops updatekeys --yes --enable-local-keyservice "${git_root}"/secrets/*/secrets.yaml sops updatekeys --yes --enable-local-keyservice "${git_root}"/secrets/*/secrets.yaml
sops updatekeys --yes --enable-local-keyservice "${git_root}"/hosts/nixos/"$target_hostname"/secrets/pii.nix.enc sops updatekeys --yes --enable-local-keyservice "${git_root}"/hosts/nixos/"$target_arch"/"$target_hostname"/secrets/pii.nix.enc
# -------------------------- # --------------------------
green "Making ssh_host_ed25519_key available to home-manager for user $target_user" green "Making ssh_host_ed25519_key available to home-manager for user $target_user"
sed -i "/$target_hostname/d; /$target_destination/d" ~/.ssh/known_hosts sed -i "/$target_hostname/d; /$target_destination/d" ~/.ssh/known_hosts
@ -336,10 +352,10 @@ fi
green "NixOS was successfully installed!" green "NixOS was successfully installed!"
if yes_or_no "You can now commit and push the nix-config, which includes the hardware-configuration.nix for $target_hostname?"; then if yes_or_no "You can now commit and push the nix-config, which includes the hardware-configuration.nix for $target_hostname?"; then
cd "${git_root}" cd "${git_root}"
deadnix hosts/nixos/"$target_hostname"/hardware-configuration.nix -qe deadnix hosts/nixos/"$target_arch"/"$target_hostname"/hardware-configuration.nix -qe
nixpkgs--fmt hosts/nixos/"$target_hostname"/hardware-configuration.nix nixpkgs--fmt hosts/nixos/"$target_arch"/"$target_hostname"/hardware-configuration.nix
(.pre-commit-config.yaml mit run --all-files 2> /dev/null || true) && (.pre-commit-config.yaml mit run --all-files 2> /dev/null || true) &&
git add "$git_root/hosts/nixos/$target_hostname/hardware-configuration.nix" && git add "$git_root/hosts/nixos/$target_arch/$target_hostname/hardware-configuration.nix" &&
git add "$git_root/.sops.yaml" && git add "$git_root/.sops.yaml" &&
git add "$git_root/secrets" && git add "$git_root/secrets" &&
(git commit -m "feat: deployed $target_hostname" || true) && git push (git commit -m "feat: deployed $target_hostname" || true) && git push

View file

@ -3,6 +3,7 @@ set -eo pipefail
target_config="hotel" target_config="hotel"
target_hostname="hotel" target_hostname="hotel"
target_user="swarsel" target_user="swarsel"
target_arch=""
persist_dir="" persist_dir=""
target_disk="/dev/vda" target_disk="/dev/vda"
disk_encryption=0 disk_encryption=0
@ -20,6 +21,7 @@ function help_and_exit() {
echo " Default: /dev/vda" echo " Default: /dev/vda"
echo " -u <target_user> specify user to deploy for." echo " -u <target_user> specify user to deploy for."
echo " Default: swarsel" echo " Default: swarsel"
echo " -a <target_arch> specify target architecture."
echo " -h | --help Print this help." echo " -h | --help Print this help."
exit 0 exit 0
} }
@ -58,6 +60,10 @@ while [[ $# -gt 0 ]]; do
shift shift
target_disk=$1 target_disk=$1
;; ;;
-a)
shift
target_arch=$1
;;
-h | --help) help_and_exit ;; -h | --help) help_and_exit ;;
*) *)
echo "Invalid option detected." echo "Invalid option detected."
@ -73,6 +79,11 @@ function cleanup() {
} }
trap cleanup exit trap cleanup exit
if [[ $target_arch == "" || $target_hostname == "" ]]; then
red "error: target_arch or target_hostname not set."
help_and_exit
fi
green "~SwarselSystems~ local installer" green "~SwarselSystems~ local installer"
cd /home/"$target_user" cd /home/"$target_user"
@ -162,9 +173,9 @@ sudo cp -r /home/"$target_user"/.dotfiles /mnt/"$persist_dir"/home/"$target_user
sudo chown -R 1000:100 /mnt/"$persist_dir"/home/"$target_user" sudo chown -R 1000:100 /mnt/"$persist_dir"/home/"$target_user"
green "Generating hardware configuration ..." green "Generating hardware configuration ..."
sudo nixos-generate-config --root /mnt --no-filesystems --dir /home/"$target_user"/.dotfiles/hosts/nixos/"$target_config"/ sudo nixos-generate-config --root /mnt --no-filesystems --dir /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/
git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_config"/hardware-configuration.nix git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/hardware-configuration.nix
sudo mkdir -p /root/.local/share/nix/ sudo mkdir -p /root/.local/share/nix/
printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | sudo tee /root/.local/share/nix/trusted-settings.json > /dev/null printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | sudo tee /root/.local/share/nix/trusted-settings.json > /dev/null
green "Installing flake $target_config" green "Installing flake $target_config"

View file

@ -1,6 +1,7 @@
set -eo pipefail set -eo pipefail
target_config="hotel" target_config="hotel"
target_arch=""
target_user="swarsel" target_user="swarsel"
function help_and_exit() { function help_and_exit() {
@ -10,10 +11,11 @@ function help_and_exit() {
echo "USAGE: $0 [OPTIONS]" echo "USAGE: $0 [OPTIONS]"
echo echo
echo "ARGS:" echo "ARGS:"
echo " -n <target_config> specify nixos config to build." echo " -n <target_config> specify nixos config to build."
echo " Default: hotel" echo " Default: hotel"
echo " -u <target_user> specify user to deploy for." echo " -u <target_user> specify user to deploy for."
echo " Default: swarsel" echo " Default: swarsel"
echo " -a <target_arch> specify target architecture."
echo " -h | --help Print this help." echo " -h | --help Print this help."
exit 0 exit 0
} }
@ -43,6 +45,10 @@ while [[ $# -gt 0 ]]; do
shift shift
target_config=$1 target_config=$1
;; ;;
-a)
shift
target_arch=$1
;;
-u) -u)
shift shift
target_user=$1 target_user=$1
@ -56,6 +62,11 @@ while [[ $# -gt 0 ]]; do
shift shift
done done
if [[ $target_arch == "" ]]; then
red "error: target_arch not set."
help_and_exit
fi
cd /home/"$target_user" cd /home/"$target_user"
if [ ! -d /home/"$target_user"/.dotfiles ]; then if [ ! -d /home/"$target_user"/.dotfiles ]; then
@ -83,7 +94,7 @@ if [[ $local_keys != *"${pub_arr[1]}"* ]]; then
rm modules/home/common/mail.nix rm modules/home/common/mail.nix
rm modules/home/common/yubikey.nix rm modules/home/common/yubikey.nix
rm modules/nixos/server/restic.nix rm modules/nixos/server/restic.nix
rm hosts/nixos/milkywell/default.nix rm hosts/nixos/aarch64-linux/milkywell/default.nix
rm -rf modules/nixos/server rm -rf modules/nixos/server
rm -rf modules/home/server rm -rf modules/home/server
nix flake update vbc-nix nix flake update vbc-nix
@ -91,8 +102,8 @@ if [[ $local_keys != *"${pub_arr[1]}"* ]]; then
else else
green "Valid SSH key found! Continuing with installation" green "Valid SSH key found! Continuing with installation"
fi fi
sudo nixos-generate-config --dir /home/"$target_user"/.dotfiles/hosts/nixos/"$target_config"/ sudo nixos-generate-config --dir /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/
git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_config"/hardware-configuration.nix git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/hardware-configuration.nix
green "Installing flake $target_config" green "Installing flake $target_config"
sudo nixos-rebuild --show-trace --flake .#"$target_config" boot sudo nixos-rebuild --show-trace --flake .#"$target_config" boot

6
flake.lock generated
View file

@ -7815,11 +7815,11 @@
}, },
"nixpkgs-dev": { "nixpkgs-dev": {
"locked": { "locked": {
"lastModified": 1761589965, "lastModified": 1762578095,
"narHash": "sha256-ZtypYmGwo7wUOo88UKVAdUZCYCpvFM8O0bEmI7+NW5k=", "narHash": "sha256-uW5Ff1H/lVvsKcNXtU7COQifqnRQ5i/YTEPGQwundNQ=",
"owner": "Swarsel", "owner": "Swarsel",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "ed3254fbd834e5bfbf6bc9586d57307a92f1a269", "rev": "a99a76ccf7bfbb8c5d6129e6ff69413c6db55c1a",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -0,0 +1,29 @@
{ lib, minimal, ... }:
{
imports = [
./hardware-configuration.nix
./disk-config.nix
];
swarselsystems = {
info = "HUNSN RM02, 8GB RAM";
flakePath = "/root/.dotfiles";
isImpermanence = true;
isSecureBoot = true;
isCrypted = true;
isBtrfs = true;
isLinux = true;
isNixos = true;
rootDisk = "/dev/sda";
swapSize = "8G";
};
} // lib.optionalAttrs (!minimal) {
swarselprofiles = {
server = true;
router = false;
};
}

View file

@ -0,0 +1,24 @@
{ config, lib, modulesPath, ... }:
{
imports =
[
(modulesPath + "/installer/scan/not-detected.nix")
];
boot = {
initrd.availableKernelModules = [ "ahci" "xhci_pci" "usbhid" "usb_storage" "sd_mod" ];
initrd.kernelModules = [ ];
extraModulePackages = [ ];
};
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.enp3s0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

View file

@ -0,0 +1,16 @@
{
"data": "ENC[AES256_GCM,data:dXhWlutdXYLxq7pAWK77lK1mz1y/lh0nl4mHa/jf4ABaQxkB9or1/ceEGwzUoFZAP+EmCuz35UpGYuT4jdti/BPDFsg3273NjVxfPBdV3Mr75FpEG56tMZKafUwARtwsBGQcIduPUgymOxKxUzy5YJokbdFThAa9Y25OFKDwOtN33NSG5QT8tEtBOFzeUx5K+9Kt1YDFCgl8dOOFtA==,iv:wZ1VY7IcK2dFjgrGZrUg+Oz3id8DZKzVgPMkjBrp1GE=,tag:F0SH8w32ec09P3NaMLcuTA==,type:str]",
"sops": {
"lastmodified": "2025-11-09T23:30:30Z",
"mac": "ENC[AES256_GCM,data:odBcMskVn/ag12j/sDxqD7/8q3GD+LPfoRQ4UcwiFAdRWIRyLKdG3HUJzt1yEVQnpvaHHOq3QmGC34FPA+GT6zw6TC9EacibmigX5uT+n6hYdVgXy97T/nD9ITtq6gVy8VjWugKpqMwTDta1HV037DKTf7LDmrTUaFhzFmtzNyA=,iv:CjkjUwCzACzuUI/TceDeopRsT9xiIZxciGq7UeBEVTw=,tag:ySF9Dxha7it2F2g81NZ+EQ==,type:str]",
"pgp": [
{
"created_at": "2025-11-09T11:20:20Z",
"enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTARAAgiGGUn4Dhw6aB34J+332lw/CMPnZb3apThxgKjAVLKDz\neEeG+iD3iOJ3m+xg0KhgV5m2nykw0LXcXlErNIxnBmPm91DiQuW2Nzgz2J9FYF+J\nMHZ65JG+9nEt6dUplEKTBS492hiKrfD6a3BR/WFy9qrv0uY8DutAeUbkXVXqY+Sn\nxTTu2DK9Yy6lps2gmaZ1nJwLffaILyZuwYqMKtv1d1tEQFsBbkwh1chj0857nldD\n4t+bDYpMa1eFBQ/vi4YfMrw19Qq0xEWo7nKdT/pj8qAW9c4D7pHf7rm4t0T+H3tN\nfk1dJKuZuITXRrIth1zhq5bLepsIWtk/hG9fNKPbYj+xThhbCWEpH18FVVJsPCtv\nksZ3i70uz6FvyMYxyNANTMIxVa+SI+dhx6bCGQ/I9xFxK2Yju/yL6Gt4av3GhyjK\ncd8B5AlIKzxDvhWBMakjf+R/I63a7AlI9QliZhEFrpNOdcBu78ZvtKKplJ6fG8SZ\nExCFFf/qtqHtM0rvl8wyyVntD2r9WLKwDF7+tlygxbexqCaVs8CPtuiswOEGldc3\nZkG+zYsXSvBmyyfwrVYoIKRjJ1QiYys+EE5OdfI9kZ/I+kByiwr6PRHDnIkuc7jj\n8odeSq/KVMwS3d0u3c6qTPWbnSvAa6KM91dnMaXb0ws/B0eNE22USNk//KVfdKKF\nAgwDC9FRLmchgYQBD/99q4jpY7LnuV12/KxqZvbSHkBlO3HlBDYfmAYUn1gYS83T\ni+eGlWqHlXAwaqDnz5hGKe/yHRBVZjUO8Ic61ujHH28dPC++hMDkfq9sBH9mXeXA\nfovVEQJOiF65K40Lel9FAa9E5yjGSvcocqBrsh4usS6jTrFJmnat4poCnJDG+Ova\n7S2kD2FEwQxRRFlWX8I7nsmdxgATIIVhLgvCImJKAb2GEBmXx/Vpj6UTG5H+dvtP\niYtHxq0QOpeR47wNc5nUTaHTP0Lsj9hB4SS7rTdKHptXEtHCEznM7SEarNCt+MQY\nQd5O/x3cItJKADxV2JO2XPL96hqlX/e6+CWcsW89nAbuIID651b7ZWBw19F+62dt\nxlVrehcsYWLz+GuGBYysx+/0EVuZ422AEi/v9ft5YdigXrxq0ddJKRtFvcQFMh0G\n2w12fADrzX2ExzTWWc7FIwBmCr5XcwLVtmwU2bOD8mX36B7UPybBDsZ5J7/fr3TP\nYIz5ApQI5ewNsBhVoyJxSJQ6IoEBC5udrGNBMKOgZEYW+1MTWPojDU9eIg0Mew1D\n7PkXYEDrHBUccbaePLViUPcEeGkE7gB/FAWsIIfjRFzR8GDJpf/RnEK7G4mvPrIw\nlH8ARzgA93gtGOyx0DVOg+zIeplbARgZoIhyX3QCpsOTPz/CmBZIwMikRZfag9Je\nAfBikUXA2MBcIDAocQAKFILnFLyY7qgNKhvqhiCc+j04GmP7mjtAiZXP7lyUauRM\nt2PUcec90jfk0wsT1DXfeJKuWVa1hkv4/2Ejz5/PXa6ZQbrmBtZG9ZIDk2VveQ==\n=k0BA\n-----END PGP MESSAGE-----",
"fp": "4BE7925262289B476DBBC17B76FD3810215AE097"
}
],
"unencrypted_suffix": "_unencrypted",
"version": "3.11.0"
}
}

View file

@ -11,8 +11,6 @@
loader.efi.canTouchEfiVariables = true; loader.efi.canTouchEfiVariables = true;
}; };
# globals.hosts.${config.node.name}.ipv4 = config.repo.secrets.local.ipv4;
networking = { networking = {
inherit (config.repo.secrets.local) hostId; inherit (config.repo.secrets.local) hostId;
hostName = configName; hostName = configName;

View file

@ -0,0 +1,118 @@
{ lib, config, ... }:
let
type = "btrfs";
extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite
subvolumes = {
"/root" = {
mountpoint = "/";
mountOptions = [
"subvol=root"
"compress=zstd"
"noatime"
];
};
"/home" = lib.mkIf config.swarselsystems.isImpermanence {
mountpoint = "/home";
mountOptions = [
"subvol=home"
"compress=zstd"
"noatime"
];
};
"/persist" = lib.mkIf config.swarselsystems.isImpermanence {
mountpoint = "/persist";
mountOptions = [
"subvol=persist"
"compress=zstd"
"noatime"
];
};
"/log" = lib.mkIf config.swarselsystems.isImpermanence {
mountpoint = "/var/log";
mountOptions = [
"subvol=log"
"compress=zstd"
"noatime"
];
};
"/nix" = {
mountpoint = "/nix";
mountOptions = [
"subvol=nix"
"compress=zstd"
"noatime"
];
};
"/swap" = lib.mkIf config.swarselsystems.isSwap {
mountpoint = "/.swapvol";
swap.swapfile.size = config.swarselsystems.swapSize;
};
};
in
{
disko.devices = {
disk = {
disk0 = {
type = "disk";
device = config.swarselsystems.rootDisk;
content = {
type = "gpt";
partitions = {
ESP = {
priority = 1;
name = "ESP";
size = "512M";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "defaults" ];
};
};
root = lib.mkIf (!config.swarselsystems.isCrypted) {
size = "100%";
content = {
inherit type subvolumes extraArgs;
postCreateHook = lib.mkIf config.swarselsystems.isImpermanence ''
MNTPOINT=$(mktemp -d)
mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5
trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT
btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank
'';
};
};
luks = lib.mkIf config.swarselsystems.isCrypted {
size = "100%";
content = {
type = "luks";
name = "cryptroot";
passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh
settings = {
allowDiscards = true;
# https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36
crypttabExtraOpts = [
"fido2-device=auto"
"token-timeout=10"
];
};
content = {
inherit type subvolumes extraArgs;
postCreateHook = lib.mkIf config.swarselsystems.isImpermanence ''
MNTPOINT=$(mktemp -d)
mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5
trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT
btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank
'';
};
};
};
};
};
};
};
};
fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true;
fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true;
}

View file

@ -1,5 +1,5 @@
{ {
"data": "ENC[AES256_GCM,data:XTHUIhn7yVn2/EvZBSg1v+EU154Kj0hgvHbUdpnc2W4U+0UNBlqxRvVxw8XFm8uo1en2hXoS,iv:XeEzWY0UB/QqbxoIQJEOkWlaU5nyETl0Aki7iyRq/Y8=,tag:rcNiCc5a6+wLYAzX1pMxxQ==,type:str]", "data": "ENC[AES256_GCM,data:PFtZdHoWzYmrHio52kBZ7LDthUI+qAPBfCqkY/ubTIwVJoaZixXbuzJdJuA84YH5YBZ/umTYG/9Ocs4hNbCYoPcG6VdreIcqwVxD6PgCEtqtTK0qxOfBqdIXQ1Gl2EzyMuxQm3pFFEx1zzueJ3KvdZEZRtzvytLlw/pKkETLECAxqAoZ5fSVApzIczGI053046v7ItdulGLOZGc=,iv:0EhqmcDH8yFC78H2tuhGbu49ZzVaMtdvf/7XuNU9hyo=,tag:/8rHZKR6CLH7HNAaK5EDOg==,type:str]",
"sops": { "sops": {
"age": [ "age": [
{ {
@ -11,8 +11,8 @@
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNeGtTZ0ZSV0trWlQrS2dV\nSFo0dytGYXhRTjl6cDZrUU0wZ1IybDVRaFZrCmZmRmxJNmdwS0xodHdEOGU4bldU\nR1JScHAvZHhlVTBJbWExb0VpR0h2MXMKLS0tIDYwQmZpMjdYRmpBeXFNOXArN0h5\nVGN1THljeCtVV0hXenMyRVJkMjlHNEEKm+yZTT48nYr3H0Bd1OKw/CYk1kwnrBzk\nTgSQHsGXhmOyDag9cSZ4wAOmqtqSjA9bouFBuhl2lSbgpjnarvFaXQ==\n-----END AGE ENCRYPTED FILE-----\n" "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNeGtTZ0ZSV0trWlQrS2dV\nSFo0dytGYXhRTjl6cDZrUU0wZ1IybDVRaFZrCmZmRmxJNmdwS0xodHdEOGU4bldU\nR1JScHAvZHhlVTBJbWExb0VpR0h2MXMKLS0tIDYwQmZpMjdYRmpBeXFNOXArN0h5\nVGN1THljeCtVV0hXenMyRVJkMjlHNEEKm+yZTT48nYr3H0Bd1OKw/CYk1kwnrBzk\nTgSQHsGXhmOyDag9cSZ4wAOmqtqSjA9bouFBuhl2lSbgpjnarvFaXQ==\n-----END AGE ENCRYPTED FILE-----\n"
} }
], ],
"lastmodified": "2025-11-06T11:16:16Z", "lastmodified": "2025-11-09T23:30:06Z",
"mac": "ENC[AES256_GCM,data:rBE1qTiaLme63i23YL16qmDE6rcKaxwWwzzqgsv4SmKCBJonjiyUc4DyRU8JuCbTx6K9+4VtERJzTLlbXhvjXl27LRQtfbNSBXBIyTgdSz0Fo46lDdVUMFSdPDbU97XAx9P3eu425aspkJYxffOJ2lvqinAVuw9U6oBpot5jVaw=,iv:N3mp0DY80UVGa4Vf4ya+5B/9w8iTihAyg/XgStgtHAo=,tag:tKjnbFm0yFddj759OK5Mdw==,type:str]", "mac": "ENC[AES256_GCM,data:/af6vMgOLZ6bqLdwhmCg9lX+S1afi3HoKeVhrEgxtjrob3IIHMoD2YqP+PhXazGTyArBPEHxojZ9ew8SqedosID61nE8H45gMV6jz8g4hF9sm7c5CRavEk7Lgy4kO4Xw6LyUEO379RUa3OOrhKrOI2+zWf+NkCQf8Hy79Cc56Ds=,iv:BDuCygDtMYdYfd8p3xZSNN4ZaFiN9WbNRD+3LSluwlY=,tag:+S01XGwLZcCa9c8IDDjjGg==,type:str]",
"pgp": [ "pgp": [
{ {
"created_at": "2025-08-24T23:36:17Z", "created_at": "2025-08-24T23:36:17Z",

View file

@ -10,7 +10,11 @@
loader.efi.canTouchEfiVariables = true; loader.efi.canTouchEfiVariables = true;
}; };
globals.hosts.${config.node.name}.ipv4 = config.repo.secrets.local.ipv4; # globals.hosts.${config.node.name}.ipv4 = config.repo.secrets.local.ipv4;
# globals.networks.home.hosts.${config.node.name} = {
# ipv4 = config.repo.secrets.local.home-ipv4;
# mac = config.repo.secrets.local.home-mac;
# };
networking = { networking = {
inherit (config.repo.secrets.local) hostId; inherit (config.repo.secrets.local) hostId;

View file

@ -1,5 +1,5 @@
{ {
"data": "ENC[AES256_GCM,data:i8kqmycc80NLcOirK7D20hxsWWFGNMx5d1SDueaSTmymvTb0rNMFiRoLf44c9Bc5yBySg9zRNCJ8lyc1SZH5YAqIYGN8y4nzOTxyPxT1R+Igtzm49sBdp1dK6MVCW1/xIsjDE/niV19l9LTptN7neCIEuDjB22bSMRhfVOxOiSwd2FKBeH61XACFLAz3AuVC4a+FhqsBkmLOAg7SIG0xdsyi2tjuTOCiMci9eQk8q9XkmLQC3z6vBaIBxPErkIG/fyhNBYt0Hv+37b/TFVbBL9qnGK369Ln9EUm0IarInaq9haxE18DkI5bzlJH5hw4JNjMGFz8av6rOJT5oW52yPor1RBodwUtP6YDQCQsdINIbjmAM9C0HGBY31nyy07fVT+QDcNydjT1fEXLSJTseO5E/MrRCVBioorBpG+5kBBQhRMihGeT8htVGVQpiJC7peARRfSQTUqjNH/esWTPCk0xPOXgApgPIbXBIJFj4RiH2erzN1PKPpuGZfuqbEr63VXCp6t0jttZKDEEjob1ZJMKfiqRubaz+ycg/sxFb1p+l9O21ihW8jM9huiBpVTc+mHU0ENTSstC4uB5LG6HMqV9vmqrKP4OM13vifggpQ6K9VRXebpI/t4tdRETcwWIMo/LRCmhGO4o0+1tNG+ayVDVmY/ORJu/Nrl61TtmUXxGc74Vd1sea+60LuqDHdIEs06thxFLSCVXaxa70gTlQIlVSEJBz9yaAMm7Iw4CSvLbYTXrRg6P/jIZx7rGSyC7I/kFMAPsa2KYxUUkBNd8zSoHyf8paxbgocb3yNcMtHIyNYiOXaLgr56DasJKsXTdjnuic6PLBCd9+U9o9R4wdBw4CGHZ3+3P+LexImkK9InVTm3QD9gyWtgDe66jrQMJxicixtx6hKvP0P0nmjhE6UjhfMMYV2Qu7vx1APhE62KF9y+axIlKju4kYkRhC9BHi2FuZUCFkPiPd/RRWzBTuChnKud9TWTixBtzpBI39/5e3i8f55hcG0XkUT+rMolq/hCObIczq7M2TVrZK4vUGByHXi1Vljk+K2tUZLVGq+Vpa7JUfmyp/qdUBG5FFXBBLUmAA0yjR+XxTtuZ4+M7JdgoYlzXEN8AbyBTEfVps4HJVPfwWMZaXEWqc7fwSVNlkRpIGSkbF8+tzBd0M66FtjbC9hs1P/SwwUr/ZTwJW0D8EXDUOJo2VCGpGtzHZpg5wd7qPTKL20fLVrpdfKIMeBrPtpCkv2YAzSXClAMQqMJ1DtrFr9WNeTAv0ROwkfnGIYwFpDnK3Xy3Z9V1HlZY3K/UYybzb43Dvtl0qWcSmXxKWLK0rqe3r4sWKA/gpOi8UIyCssAv5At0JO2e0yBJv7tXi+WGNZIBEy559EYdnfHty2KZTR5M/PiP5t1PMbuzUkee3voybnAioCZfGsh5Ln04ZihUHbtbxocM4yieaqBd7nryO81b1ZARoZKbASaGMc7y65pgsA1MiNnbtGIZUwlNyg1q3iZxdtkG6qgG2vCY9Z6JNXXl6RoBmbDbCaIzvid8OXvK8z0z4t0BpYQCFVb3/sEAqweUnQffstEFB,iv:+cS1MmSlZWLdRt5Ey31y6WrDAudgjHxsUbfCBUK0/Sg=,tag:byOqNWWPQmlrDWQO1tRRJQ==,type:str]", "data": "ENC[AES256_GCM,data:4SiiMDgtS3KPoG/fuYnfzaxVycaQsSycTODMQQS9a4ICcZFY21LdKCRQs8N908ndBrdjMIHMhG6LDI1RVRs6m5EBZLYho3dzvf3YlpztnypaGrAkXfTnCuvP15vvAOgHnJYF3PQ41XcKoQ9yKRJGv3E/1lt2bkGkZsH43aDizz/BfRXpKKOezLkzumi6IYiwrVrdPHf0yQj7qeMBfPi9WBicf+/daonOOssa1JMqZ8B+Uy8tG0qi6JlL2eQa18njDfV7rcmGyQGUYBkVoc2E+YYrAUbB7KDYSwe3Gqzo75Ls6IjH8O0KemYnqPbOIPrlrAsGPen+ZAT6tdCQ9QCNwXlGLERRidVcSWjjk32VthlLzXGrhXoChidwui7ff8SwUXIf9OyV1E4wREdPJPBkOBVKOhaCEZfEavREHRTlftmE0KHi6k4CXKi2HPvOvOt4HvHALSFJCKkmrn+8THv01niHS0X3iQfIJCzPpXFCkKVYB+2t/NOPeB6qJsI3+eLpd7jhU9p4q6Ny/OmSpYRFgqqF4TXg+npYQm7L1bqSkpRqbzfQmS9MdEl/h79K2x2GYBmTOAR6fs7c7kUFiXoxrP56Sh3sLyTuhzD3VGJ6HxHFlaIXAi3tZ9VObSCa3zpLWv7j6e3vNp01Z0O0UfJ5ZNNHOe+IIyUtEAA9ywLxU+uRuCsBe7PZeT95WpfDkiQVY3LPXxFr92dE4w6Ex6CZyneUF3wOwDqxVi+J2FXAJkYXDi6uE3kyBhn77FsaEVx5H/GxxsT8cFXEa6EjhQ0/eQTw7DYZ11urgN7iNDKrhh4oPnkI9HRrIaqbtaW3H8Rzx01/JkkfOdhiXHxYILm4W6YnLt0kTPI+nNgUEX2/H5h12xXPCF4isK6oHe+DExbP+5Ccz0AOEueNMn0LxH/zhG/f6k7sdOs05PIC0p56v1yRrhYtaVemFdfSWI4dgaXpygR5h2YtrGDHKq8vlsafIa8olrjbgMMpeXjrnpDSC8MgQ55wLHAEIVWPdKmr74704gGKz7PL6L0DAqh8YMTIHaOdf5h520qqiFm0bJWttrPhi0LvHlZUsumgGJ+MqQdRpxbnjo3q8rY0pwyVNxCHieKdchjdCeH9+xhoMpVvjwudrbsycyeF2Bm/TY5emoSTKWq8ucnkpTqXUpuRpi6kaqQRZIMoSR4BjsfGDcNrT+SWqjVnkOOx5EL7B0cJUt9QGaWeSsTj3JK7InnhfyKr44f4e0T2RHjwarZoW9OnPFJnwnsvUarQ5U8LRdRfY0H74XoMdfpZhlTgV1sS37MdKjgakQzVRY5ANA3H4VmaTeJxjPelSnve/Vtkp3SPIuhacfBkMCkoDGPqjR8nmJ1vZdqM9RlLyZcNnZxqsQHT0/wqHSAImfZiLiTHIpkBucYOvt1/OuFrnUTz8XtHFZU6f3tMTM5pCZS5/X2nA+LXiW7+uoIcYpowPb5iVfkFc0T/rSWbqqZoR+kAWFllGK+k9h8brlGyKdwBWF45xWmpl4CSwvngzKKW14f3Ljlf7NyrcUXOxHfrL3wzIoYMFcqNWLh6D4qPt3cqJDihYzF4GYu73VJhUK6sn2GqZ/XCttfBd5MfrvSqLv4iHmrYC3oXl0JS+J7LuZudWIJSEDGhv1ZUdUKahKWsfMvmmVnk28AczdE/rBiAJ+9POeRmGYJ743PSua0k+tBIUbdQ+xkuruenII4pK37yd5H0Ic4ATtcVg0Bg4se5JBXmEoHodO5t2Vg8gUXVI+Xc,iv:C/7cgdkpNmOIeb8cdYI0rbyxebJLgpqIU8ezO+zRqCA=,tag:NywhkBzKpQrJ3H7ZKxvYgQ==,type:str]",
"sops": { "sops": {
"age": [ "age": [
{ {
@ -11,8 +11,8 @@
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNeGtTZ0ZSV0trWlQrS2dV\nSFo0dytGYXhRTjl6cDZrUU0wZ1IybDVRaFZrCmZmRmxJNmdwS0xodHdEOGU4bldU\nR1JScHAvZHhlVTBJbWExb0VpR0h2MXMKLS0tIDYwQmZpMjdYRmpBeXFNOXArN0h5\nVGN1THljeCtVV0hXenMyRVJkMjlHNEEKm+yZTT48nYr3H0Bd1OKw/CYk1kwnrBzk\nTgSQHsGXhmOyDag9cSZ4wAOmqtqSjA9bouFBuhl2lSbgpjnarvFaXQ==\n-----END AGE ENCRYPTED FILE-----\n" "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNeGtTZ0ZSV0trWlQrS2dV\nSFo0dytGYXhRTjl6cDZrUU0wZ1IybDVRaFZrCmZmRmxJNmdwS0xodHdEOGU4bldU\nR1JScHAvZHhlVTBJbWExb0VpR0h2MXMKLS0tIDYwQmZpMjdYRmpBeXFNOXArN0h5\nVGN1THljeCtVV0hXenMyRVJkMjlHNEEKm+yZTT48nYr3H0Bd1OKw/CYk1kwnrBzk\nTgSQHsGXhmOyDag9cSZ4wAOmqtqSjA9bouFBuhl2lSbgpjnarvFaXQ==\n-----END AGE ENCRYPTED FILE-----\n"
} }
], ],
"lastmodified": "2025-11-04T09:26:35Z", "lastmodified": "2025-11-09T23:29:33Z",
"mac": "ENC[AES256_GCM,data:T8GqsMxfFB9s1EOeLHNzxoz23FCOnlNsBsbvMxiLq7a78xt5Xw3dVN/IWfkyiCDwfSjo+fVx2yEd5tP/B3fSN7S8WJNSe5ZywLpal/RlsCzv7ARvbVCaBx22S4az97JsR1qQUcGSvoiTH5e/0t2tBtimGJ1witbvbiGkTBp8taw=,iv:Qs26cjeMLtRhTDO91yfBo93wUKJ9zVfUbJ8o6myHGUo=,tag:FbT8emz6q1QnXdxoX6hsYQ==,type:str]", "mac": "ENC[AES256_GCM,data:UU9a1Yg8Inmcht6gc2pTi3GpV945YAMdVN08Q2/yjg5850N3VhVcD0dsu/bn+4fOSvOiDtWzkoqq1PquRWJbfDjZJxl0aivU7UHN3st64nxIc/mKKZp7VwavMDTVDQScRlpaPZoC0zZ5CDQtBQisfY2AiDtfUVBKZLfuvI3Kjsc=,iv:RPcSwZHVlTo8laro1bCAaJT8KXXCtLHJk1iH4zaZbgk=,tag:qOhN4DNr+d1/34R6L78PLg==,type:str]",
"pgp": [ "pgp": [
{ {
"created_at": "2025-08-24T23:36:17Z", "created_at": "2025-08-24T23:36:17Z",

View file

@ -1,36 +1,32 @@
{ self, config, pkgs, lib, ... }: { self, config, pkgs, lib, ... }:
let let
pubKeys = lib.filesystem.listFilesRecursive "${self}/secrets/keys/ssh"; pubKeys = lib.filesystem.listFilesRecursive "${self}/secrets/keys/ssh";
stateVersion = lib.mkDefault "23.05";
homeFiles = {
".bash_history" = {
text = ''
swarsel-install -n hotel
'';
};
};
in in
{ {
config = { config = {
home-manager.users.root.home = { home-manager.users.root.home = {
stateVersion = "23.05"; inherit stateVersion;
file = { file = homeFiles;
".bash_history" = {
text = ''
swarsel-install -n hotel
'';
};
};
}; };
home-manager.users.swarsel = { home-manager.users.swarsel = {
home = { home = {
username = "swarsel"; username = "swarsel";
homeDirectory = lib.mkDefault "/home/swarsel"; homeDirectory = lib.mkDefault "/home/swarsel";
stateVersion = lib.mkDefault "23.05"; inherit stateVersion;
keyboard.layout = "us"; keyboard.layout = "us";
sessionVariables = { sessionVariables = {
FLAKE = "/home/swarsel/.dotfiles"; FLAKE = "/home/swarsel/.dotfiles";
}; };
file = { file = homeFiles;
".bash_history" = {
text = ''
swarsel-install -n hotel
'';
};
};
}; };
}; };
@ -48,10 +44,6 @@ in
nix = { nix = {
channel.enable = false; channel.enable = false;
package = pkgs.nixVersions.nix_2_28; package = pkgs.nixVersions.nix_2_28;
# extraOptions = ''
# plugin-files = ${pkgs.dev.nix-plugins}/lib/nix/plugins
# extra-builtins-file = ${../nix/extra-builtins.nix}
# '';
extraOptions = '' extraOptions = ''
plugin-files = ${pkgs.nix-plugins.overrideAttrs (o: { plugin-files = ${pkgs.nix-plugins.overrideAttrs (o: {
buildInputs = [config.nix.package pkgs.boost]; buildInputs = [config.nix.package pkgs.boost];
@ -103,6 +95,7 @@ in
environment.etc."issue".text = '' environment.etc."issue".text = ''
~SwarselSystems~ ~SwarselSystems~
IP of primary interface: \4 IP of primary interface: \4
These IPs were also found: \4{eth0} \4{eth1} \4{eth2} \4{eth3} \4{wlan0}
The Password for all users & root is 'setup'. The Password for all users & root is 'setup'.
Install the system remotely by running 'bootstrap -n <CONFIGURATION_NAME> -d <IP_FROM_ABOVE> ' on a machine with deployed secrets. Install the system remotely by running 'bootstrap -n <CONFIGURATION_NAME> -d <IP_FROM_ABOVE> ' on a machine with deployed secrets.
Alternatively, run 'swarsel-install -n <CONFIGURATION_NAME>' for a local install. For your convenience, an example call is in the bash history (press up on the keyboard to access). Alternatively, run 'swarsel-install -n <CONFIGURATION_NAME>' for a local install. For your convenience, an example call is in the bash history (press up on the keyboard to access).
@ -113,6 +106,7 @@ in
wireless.enable = false; wireless.enable = false;
# dhcpcd.runHook = "${pkgs.utillinux}/bin/agetty --reload"; # dhcpcd.runHook = "${pkgs.utillinux}/bin/agetty --reload";
networkmanager.enable = true; networkmanager.enable = true;
usePredictableInterfaceNames = false;
}; };
services.getty.autologinUser = lib.mkForce "root"; services.getty.autologinUser = lib.mkForce "root";
@ -139,6 +133,8 @@ in
programs.bash.shellAliases = { programs.bash.shellAliases = {
"swarsel-install" = "nix run github:Swarsel/.dotfiles#swarsel-install --"; "swarsel-install" = "nix run github:Swarsel/.dotfiles#swarsel-install --";
"swarsel-net-manufacturer" = "lspci -nn | grep -i 'network\|ethernet'";
"swarsel-kernel-module" = "lspci -k -d";
}; };
system.activationScripts.cache = { system.activationScripts.cache = {

View file

@ -10,12 +10,9 @@ check-trace:
update: update:
nix flake update nix flake update
iso: iso CONFIG="live-iso":
rm -rf result rm -rf result
nix build .#nixosConfigurations.iso.config.system.build.isoImage && ln -sf result/iso/*.iso latest.iso nix build --print-out-paths .#live-iso
iso-flake FLAKE SYSTEM="x86_64" FORMAT="iso":
nixos-generate --flake .#{{FLAKE}} -f {{FORMAT}} --system {{SYSTEM}}
iso-install DRIVE: iso iso-install DRIVE: iso
sudo dd if=$(eza --sort changed result/iso/*.iso | tail -n1) of={{DRIVE}} bs=4M status=progress oflag=sync sudo dd if=$(eza --sort changed result/iso/*.iso | tail -n1) of={{DRIVE}} bs=4M status=progress oflag=sync
@ -25,3 +22,6 @@ dd DRIVE ISO:
sync USER HOST: sync USER HOST:
rsync -rltv --filter=':- .gitignore' -e "ssh -l {{USER}}" . {{USER}}@{{HOST}}:.dotfiles/ rsync -rltv --filter=':- .gitignore' -e "ssh -l {{USER}}" . {{USER}}@{{HOST}}:.dotfiles/
bootstrap DEST CONFIG ARCH="x86_64-linux":
nix develop .#deploy --command zsh -c "swarsel-bootstrap -n {{CONFIG}} -d {{DEST}} -a {{ARCH}}"

View file

@ -4,6 +4,91 @@ let
mkOption mkOption
types types
; ;
networkOptions = netSubmod: {
cidrv4 = mkOption {
type = types.nullOr types.net.cidrv4;
description = "The CIDRv4 of this network";
default = null;
};
subnetMask4 = mkOption {
type = types.nullOr types.net.cidrv4;
description = "The dotted decimal form of the subnet mask of this network";
readOnly = true;
default = lib.swarselsystems.cidrToSubnetMask netSubmod.cidrv4;
};
cidrv6 = mkOption {
type = types.nullOr types.net.cidrv6;
description = "The CIDRv6 of this network";
default = null;
};
hosts = mkOption {
default = { };
type = types.attrsOf (
types.submodule (hostSubmod: {
options = {
id = mkOption {
type = types.int;
description = "The id of this host in the network";
};
mac = mkOption {
type = types.nullOr types.net.mac;
description = "The MAC of the interface on this host that belongs to this network.";
default = null;
};
ipv4 = mkOption {
type = types.nullOr types.net.ipv4;
description = "The IPv4 of this host in this network";
readOnly = true;
default =
if netSubmod.config.cidrv4 == null then
null
else
lib.net.cidr.host hostSubmod.config.id netSubmod.config.cidrv4;
};
ipv6 = mkOption {
type = types.nullOr types.net.ipv6;
description = "The IPv6 of this host in this network";
readOnly = true;
default =
if netSubmod.config.cidrv6 == null then
null
else
lib.net.cidr.host hostSubmod.config.id netSubmod.config.cidrv6;
};
cidrv4 = mkOption {
type = types.nullOr types.str; # FIXME: this is not types.net.cidr because it would zero out the host part
description = "The IPv4 of this host in this network, including CIDR mask";
readOnly = true;
default =
if netSubmod.config.cidrv4 == null then
null
else
lib.net.cidr.hostCidr hostSubmod.config.id netSubmod.config.cidrv4;
};
cidrv6 = mkOption {
type = types.nullOr types.str; # FIXME: this is not types.net.cidr because it would zero out the host part
description = "The IPv6 of this host in this network, including CIDR mask";
readOnly = true;
default =
if netSubmod.config.cidrv6 == null then
null
else
lib.net.cidr.hostCidr hostSubmod.config.id netSubmod.config.cidrv6;
};
};
})
);
};
};
in in
{ {
options = { options = {
@ -39,12 +124,44 @@ in
); );
}; };
networks = mkOption {
default = { };
type = types.attrsOf (
types.submodule (netSubmod: {
options = networkOptions netSubmod // {
vlans = mkOption {
default = { };
type = types.attrsOf (
types.submodule (vlanNetSubmod: {
options = networkOptions vlanNetSubmod // {
id = mkOption {
type = types.ints.between 1 4094;
description = "The VLAN id";
};
name = mkOption {
description = "The name of this VLAN";
default = vlanNetSubmod.config._module.args.name;
type = types.str;
};
};
})
);
};
};
})
);
};
hosts = mkOption { hosts = mkOption {
type = types.attrsOf ( type = types.attrsOf (
types.submodule { types.submodule {
options = { options = {
ipv4 = mkOption { defaultGateway4 = mkOption {
type = types.str; type = types.nullOr types.net.ipv4;
};
defaultGateway6 = mkOption {
type = types.nullOr types.net.ipv6;
}; };
}; };
} }

View file

@ -1,5 +1,5 @@
# largely based on https://github.com/oddlama/nix-config/blob/main/modules/secrets.nix # largely based on https://github.com/oddlama/nix-config/blob/main/modules/secrets.nix
{ config, inputs, lib, minimal, ... }: { config, inputs, lib, ... }:
let let
# If the given expression is a bare set, it will be wrapped in a function, # If the given expression is a bare set, it will be wrapped in a function,
# so that the imported file can always be applied to the inputs, similar to # so that the imported file can always be applied to the inputs, similar to
@ -65,7 +65,7 @@ in
let let
local = config.node.secretsDir + "/pii.nix.enc"; local = config.node.secretsDir + "/pii.nix.enc";
in in
(lib.optionalAttrs (lib.pathExists local && !minimal) { inherit local; }) // lib.optionalAttrs (!minimal) { (lib.optionalAttrs (lib.pathExists local) { inherit local; }) // lib.optionalAttrs true {
common = ../../../secrets/repo/pii.nix.enc; common = ../../../secrets/repo/pii.nix.enc;
}; };
}; };

View file

@ -5,7 +5,7 @@ let
servicePort = 27701; servicePort = 27701;
serviceName = "ankisync"; serviceName = "ankisync";
serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
ankiUser = globals.user.name; ankiUser = globals.user.name;
in in

View file

@ -3,7 +3,7 @@ let
servicePort = 8888; servicePort = 8888;
serviceName = "atuin"; serviceName = "atuin";
serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
in in
{ {
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";

View file

@ -0,0 +1,34 @@
{ self, lib, config, globals, ... }:
let
localIp = globals.networks.home.hosts.${config.node.name}.ipv4;
subnetMask = globals.networks.home.subnetMask4;
gatewayIp = globals.hosts.${config.node.name}.defaultGateway4;
in
{
options.swarselmodules.server.diskEncryption = lib.mkEnableOption "enable disk encryption config";
config = lib.mkIf (config.swarselmodules.server.diskEncryption && config.swarselsystems.isCrypted) {
boot.kernelParams = lib.mkIf (!config.swarselsystems.isLaptop) [ "ip=${localIp}::${gatewayIp}:${subnetMask}:${config.networking.hostName}::none" ];
boot.initrd = {
availableKernelModules = [ "r8169" ];
network = {
enable = true;
udhcpc.enable = lib.mkIf config.swarselsystems.isLaptop true;
flushBeforeStage2 = true;
ssh = {
enable = true;
port = 22;
authorizedKeyFiles = [
(self + /secrets/keys/ssh/yubikey.pub)
(self + /secrets/keys/ssh/magicant.pub)
];
hostKeys = [ "/etc/secrets/initrd/ssh_host_ed25519_key" ];
};
postCommands = ''
echo 'cryptsetup-askpass || echo "Unlock was successful; exiting SSH session" && exit 1' >> /root/.profile
'';
};
};
};
}

View file

@ -5,7 +5,7 @@ let
serviceGroup = serviceUser; serviceGroup = serviceUser;
serviceName = "firefly-iii"; serviceName = "firefly-iii";
serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
nginxGroup = "nginx"; nginxGroup = "nginx";

View file

@ -7,7 +7,7 @@ let
serviceGroup = serviceUser; serviceGroup = serviceUser;
serviceName = "forgejo"; serviceName = "forgejo";
serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
kanidmDomain = globals.services.kanidm.domain; kanidmDomain = globals.services.kanidm.domain;
in in

View file

@ -5,7 +5,7 @@ let
serviceUser = "freshrss"; serviceUser = "freshrss";
serviceGroup = serviceName; serviceGroup = serviceName;
serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
inherit (config.swarselsystems) sopsFile; inherit (config.swarselsystems) sopsFile;
in in

View file

@ -5,7 +5,7 @@ let
serviceName = "garage"; serviceName = "garage";
servicePort = 3900; servicePort = 3900;
serviceDomain = config.repo.secrets.common.services.domains."${serviceName}-${configName}"; serviceDomain = config.repo.secrets.common.services.domains."${serviceName}-${configName}";
serviceAddress = globals.hosts.${configName}.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
cfg = config.services.${serviceName}; cfg = config.services.${serviceName};
metadata_dir = "/var/lib/garage/meta"; metadata_dir = "/var/lib/garage/meta";

View file

@ -3,7 +3,7 @@ let
servicePort = 7745; servicePort = 7745;
serviceName = "homebox"; serviceName = "homebox";
serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
in in
{ {
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";

View file

@ -4,7 +4,7 @@ let
serviceUser = "immich"; serviceUser = "immich";
serviceName = "immich"; serviceName = "immich";
serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
in in
{ {
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";

View file

@ -4,7 +4,7 @@ let
serviceName = "jellyfin"; serviceName = "jellyfin";
serviceUser = "jellyfin"; serviceUser = "jellyfin";
serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
in in
{ {
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";

View file

@ -3,7 +3,7 @@ let
servicePort = 8088; servicePort = 8088;
serviceName = "jenkins"; serviceName = "jenkins";
serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
in in
{ {
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";

View file

@ -8,7 +8,7 @@ let
serviceGroup = serviceUser; serviceGroup = serviceUser;
serviceName = "kanidm"; serviceName = "kanidm";
serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
oauth2ProxyDomain = globals.services.oauth2Proxy.domain; oauth2ProxyDomain = globals.services.oauth2Proxy.domain;
immichDomain = globals.services.immich.domain; immichDomain = globals.services.immich.domain;

View file

@ -6,7 +6,7 @@ let
serviceName = "kavita"; serviceName = "kavita";
serviceUser = "kavita"; serviceUser = "kavita";
serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
in in
{ {
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";

View file

@ -6,7 +6,7 @@ let
servicePort = 2282; servicePort = 2282;
serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
serviceDir = "/Vault/data/koillection"; serviceDir = "/Vault/data/koillection";
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
postgresUser = config.systemd.services.postgresql.serviceConfig.User; # postgres postgresUser = config.systemd.services.postgresql.serviceConfig.User; # postgres
postgresPort = config.services.postgresql.settings.port; # 5432 postgresPort = config.services.postgresql.settings.port; # 5432

View file

@ -6,7 +6,7 @@ let
serviceName = "matrix"; serviceName = "matrix";
serviceDomain = config.repo.secrets.common.services.domains.matrix; serviceDomain = config.repo.secrets.common.services.domains.matrix;
serviceUser = "matrix-synapse"; serviceUser = "matrix-synapse";
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
federationPort = 8448; federationPort = 8448;
whatsappPort = 29318; whatsappPort = 29318;

View file

@ -5,7 +5,7 @@ let
serviceGroup = serviceUser; serviceGroup = serviceUser;
serviceName = "grafana"; serviceName = "grafana";
serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
prometheusPort = 9090; prometheusPort = 9090;
prometheusUser = "prometheus"; prometheusUser = "prometheus";

View file

@ -5,7 +5,7 @@ let
serviceUser = "navidrome"; serviceUser = "navidrome";
serviceGroup = serviceUser; serviceGroup = serviceUser;
serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
in in
{ {
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";

View file

@ -0,0 +1,26 @@
{ lib, config, ... }:
{
options.swarselmodules.server.network = lib.mkEnableOption "enable server network config";
config = lib.mkIf config.swarselmodules.server.network {
globals.networks.home.hosts.${config.node.name} = {
inherit (config.repo.secrets.local.networking.networks.home) id;
mac = config.repo.secrets.local.networking.networks.home.mac or null;
};
globals.hosts.${config.node.name} = {
inherit (config.repo.secrets.local.networking) defaultGateway4;
};
networking = {
inherit (config.repo.secrets.local.networking) hostId;
hostName = config.node.name;
nftables.enable = lib.mkDefault true;
enableIPv6 = lib.mkDefault true;
firewall = {
enable = lib.mkDefault true;
};
};
};
}

View file

@ -8,7 +8,7 @@ let
serviceGroup = serviceUser; serviceGroup = serviceUser;
serviceName = "nextcloud"; serviceName = "nextcloud";
serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
in in
{ {
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";

View file

@ -7,7 +7,7 @@ let
serviceGroup = serviceUser; serviceGroup = serviceUser;
serviceName = "paperless"; serviceName = "paperless";
serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
tikaPort = 9998; tikaPort = 9998;
gotenbergPort = 3002; gotenbergPort = 3002;

View file

@ -7,7 +7,7 @@ let
serviceUser = "radicale"; serviceUser = "radicale";
serviceGroup = serviceUser; serviceGroup = serviceUser;
serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
cfg = config.services.${serviceName}; cfg = config.services.${serviceName};
in in

View file

@ -0,0 +1,56 @@
{ lib, config, ... }:
let
serviceName = "router";
in
{
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
config = lib.mkIf config.swarselmodules.server.${serviceName} {
systemd.network = {
wait-online.anyInterface = true;
networks = {
"30-lan0" = {
matchConfig.Name = "lan0";
linkConfig.RequiredForOnline = "enslaved";
networkConfig = {
ConfigureWithoutCarrier = true;
};
};
"30-lan1" = {
matchConfig.Name = "lan1";
linkConfig.RequiredForOnline = "enslaved";
networkConfig = {
ConfigureWithoutCarrier = true;
};
};
"30-lan2" = {
matchConfig.Name = "lan2";
linkConfig.RequiredForOnline = "enslaved";
networkConfig = {
ConfigureWithoutCarrier = true;
};
};
"30-lan3" = {
matchConfig.Name = "lan3";
linkConfig.RequiredForOnline = "enslaved";
networkConfig = {
ConfigureWithoutCarrier = true;
};
};
"10-wan" = {
matchConfig.Name = "wan";
networkConfig = {
# start a DHCP Client for IPv4 Addressing/Routing
DHCP = "ipv4";
DNSOverTLS = true;
DNSSEC = true;
IPv6PrivacyExtensions = false;
IPForward = true;
};
# make routing on this interface a dependency for network-online.target
linkConfig.RequiredForOnline = "routable";
};
};
};
};
}

View file

@ -9,7 +9,7 @@ let
serviceUser = "snipeit"; serviceUser = "snipeit";
serviceGroup = serviceUser; serviceGroup = serviceUser;
serviceDomain = config.repo.secrets.common.services.domains.${serviceName}; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
mysqlPort = 3306; mysqlPort = 3306;
in in

View file

@ -7,7 +7,7 @@ let
serviceUser = "syncthing"; serviceUser = "syncthing";
serviceGroup = serviceUser; serviceGroup = serviceUser;
serviceName = "syncthing"; serviceName = "syncthing";
serviceAddress = globals.hosts.winters.ipv4; serviceAddress = globals.networks.home.hosts.${config.node.name}.ipv4;
specificServiceName = "syncthing-${configName}"; specificServiceName = "syncthing-${configName}";
cfg = config.services.${serviceName}; cfg = config.services.${serviceName};

View file

@ -46,114 +46,142 @@
}; };
}; };
devshells.default = devshells = {
let deploy =
nix-version = "2_30"; let
in nix-version = "2_28";
{ in
packages = [ {
(builtins.trace "alarm: pinned nix_${nix-version}" pkgs.nixVersions."nix_${nix-version}") packages = [
pkgs.git (builtins.trace "alarm: pinned nix_${nix-version}" pkgs.stable25_05.nixVersions."nix_${nix-version}")
pkgs.just pkgs.git
pkgs.age pkgs.just
pkgs.ssh-to-age pkgs.age
pkgs.sops pkgs.ssh-to-age
pkgs.nixpkgs-fmt pkgs.sops
self.packages.${system}.swarsel-build ];
self.packages.${system}.swarsel-deploy
(pkgs.symlinkJoin {
name = "home-manager";
buildInputs = [ pkgs.makeWrapper ];
paths = [ pkgs.home-manager ];
postBuild = ''
wrapProgram $out/bin/home-manager \
--append-flags '--flake .#$(hostname)'
'';
})
];
commands = [ env =
{ [
package = pkgs.statix; {
help = "Lint flake"; name = "NIX_CONFIG";
} value = ''
{ plugin-files = ${pkgs.stable25_05.nix-plugins.overrideAttrs (o: {
package = pkgs.deadnix; buildInputs = [pkgs.stable25_05.nixVersions."nix_${nix-version}" pkgs.stable25_05.boost];
help = "Check flake for dead code"; patches = (o.patches or []) ++ [./nix-plugins.patch];
} })}/lib/nix/plugins
{ extra-builtins-file = ${self + /nix/extra-builtins.nix}
package = pkgs.nix-tree; '';
help = "Interactively browse dependency graphs of Nix derivations"; }
} ];
{ };
package = pkgs.nvd; default =
help = "Diff two nix toplevels and show which packages were upgraded"; let
} nix-version = "2_30";
{ in
package = pkgs.nix-diff; {
help = "Explain why two Nix derivations differ"; packages = [
} (builtins.trace "alarm: pinned nix_${nix-version}" pkgs.nixVersions."nix_${nix-version}")
{ pkgs.git
package = pkgs.nix-output-monitor; pkgs.just
help = "Nix Output Monitor (a drop-in alternative for `nix` which shows a build graph)"; pkgs.age
name = "nom \"$@\""; pkgs.ssh-to-age
} pkgs.sops
{ pkgs.nixpkgs-fmt
name = "hm"; self.packages.${system}.swarsel-build
help = "Manage home-manager config"; self.packages.${system}.swarsel-deploy
command = "home-manager \"$@\""; (pkgs.symlinkJoin {
} name = "home-manager";
{ buildInputs = [ pkgs.makeWrapper ];
name = "fmt"; paths = [ pkgs.home-manager ];
help = "Format flake"; postBuild = ''
command = "nixpkgs-fmt --check \"$FLAKE\""; wrapProgram $out/bin/home-manager \
} --append-flags '--flake .#$(hostname)'
{
name = "sd";
help = "Build and deploy this nix config to nodes";
command = "swarsel-deploy \"$@\"";
}
{
name = "sl";
help = "Build and deploy a config to nodes";
command = "swarsel-deploy \${1} switch";
}
{
name = "sw";
help = "Build and switch to the host's config locally";
command = "swarsel-deploy $(hostname) switch";
}
{
name = "bld";
help = "Build a number of configurations";
command = "swarsel-build \"$@\"";
}
{
name = "c";
help = "Work with the flake git repository";
command = "git --git-dir=$FLAKE/.git --work-tree=$FLAKE/ \"$@\"";
}
];
devshell.startup.pre-commit-install.text = "pre-commit install";
env =
let
nix-plugins = pkgs.nix-plugins.override {
nixComponents = pkgs.nixVersions."nixComponents_${nix-version}";
};
in
[
{
# Additionally configure nix-plugins with our extra builtins file.
# We need this for our repo secrets.
name = "NIX_CONFIG";
value = ''
plugin-files = ${nix-plugins}/lib/nix/plugins
extra-builtins-file = ${self + /nix/extra-builtins.nix}
''; '';
})
];
commands = [
{
package = pkgs.statix;
help = "Lint flake";
}
{
package = pkgs.deadnix;
help = "Check flake for dead code";
}
{
package = pkgs.nix-tree;
help = "Interactively browse dependency graphs of Nix derivations";
}
{
package = pkgs.nvd;
help = "Diff two nix toplevels and show which packages were upgraded";
}
{
package = pkgs.nix-diff;
help = "Explain why two Nix derivations differ";
}
{
package = pkgs.nix-output-monitor;
help = "Nix Output Monitor (a drop-in alternative for `nix` which shows a build graph)";
name = "nom \"$@\"";
}
{
name = "hm";
help = "Manage home-manager config";
command = "home-manager \"$@\"";
}
{
name = "fmt";
help = "Format flake";
command = "nixpkgs-fmt --check \"$FLAKE\"";
}
{
name = "sd";
help = "Build and deploy this nix config to nodes";
command = "swarsel-deploy \"$@\"";
}
{
name = "sl";
help = "Build and deploy a config to nodes";
command = "swarsel-deploy \${1} switch";
}
{
name = "sw";
help = "Build and switch to the host's config locally";
command = "swarsel-deploy $(hostname) switch";
}
{
name = "bld";
help = "Build a number of configurations";
command = "swarsel-build \"$@\"";
}
{
name = "c";
help = "Work with the flake git repository";
command = "git --git-dir=$FLAKE/.git --work-tree=$FLAKE/ \"$@\"";
} }
]; ];
};
devshell.startup.pre-commit-install.text = "pre-commit install";
env =
let
nix-plugins = pkgs.nix-plugins.override {
nixComponents = pkgs.nixVersions."nixComponents_${nix-version}";
};
in
[
{
name = "NIX_CONFIG";
value = ''
plugin-files = ${nix-plugins}/lib/nix/plugins
extra-builtins-file = ${self + /nix/extra-builtins.nix}
'';
}
];
};
};
}; };
} }

View file

@ -6,24 +6,11 @@
inherit (outputs) lib homeLib; inherit (outputs) lib homeLib;
# lib = (inputs.nixpkgs.lib // inputs.home-manager.lib).extend (_: _: { swarselsystems = import "${self}/lib" { inherit self lib inputs outputs; inherit (inputs) systems; }; }); # lib = (inputs.nixpkgs.lib // inputs.home-manager.lib).extend (_: _: { swarselsystems = import "${self}/lib" { inherit self lib inputs outputs; inherit (inputs) systems; }; });
mkNixosHost = { minimal }: configName: mkNixosHost = { minimal }: configName: arch:
let
sys = "x86_64-linux";
# lib = config.pkgsPre.${sys}.lib // {
# inherit (inputs.home-manager.lib) hm;
# swarselsystems = self.outputs.swarselsystemsLib;
# };
# lib = config.pkgsPre.${sys}.lib // {
# inherit (inputs.home-manager.lib) hm;
# swarselsystems = self.outputs.swarselsystemsLib;
# };
inherit (config.pkgs.${sys}) lib;
in
inputs.nixpkgs.lib.nixosSystem { inputs.nixpkgs.lib.nixosSystem {
specialArgs = { specialArgs = {
inherit inputs outputs self minimal configName; inherit inputs outputs self minimal configName homeLib;
inherit lib homeLib; inherit (config.pkgs.${arch}) lib;
inherit (config) globals nodes; inherit (config) globals nodes;
}; };
modules = [ modules = [
@ -41,7 +28,7 @@
inputs.microvm.nixosModules.host inputs.microvm.nixosModules.host
inputs.microvm.nixosModules.microvm inputs.microvm.nixosModules.microvm
(inputs.nixos-extra-modules + "/modules/guests") (inputs.nixos-extra-modules + "/modules/guests")
"${self}/hosts/nixos/${configName}" "${self}/hosts/nixos/${arch}/${configName}"
"${self}/profiles/nixos" "${self}/profiles/nixos"
"${self}/modules/nixos" "${self}/modules/nixos"
{ {
@ -50,7 +37,7 @@
node = { node = {
name = lib.mkForce configName; name = lib.mkForce configName;
secretsDir = ../hosts/nixos/${configName}/secrets; secretsDir = ../hosts/nixos/${arch}/${configName}/secrets;
}; };
swarselprofiles = { swarselprofiles = {
@ -68,7 +55,7 @@
]; ];
}; };
mkDarwinHost = { minimal }: configName: mkDarwinHost = { minimal }: configName: arch:
inputs.nix-darwin.lib.darwinSystem { inputs.nix-darwin.lib.darwinSystem {
specialArgs = { specialArgs = {
inherit inputs lib outputs self minimal configName; inherit inputs lib outputs self minimal configName;
@ -82,75 +69,92 @@
# inputs.fw-fanctrl.nixosModules.default # inputs.fw-fanctrl.nixosModules.default
# inputs.nix-topology.nixosModules.default # inputs.nix-topology.nixosModules.default
inputs.home-manager.darwinModules.home-manager inputs.home-manager.darwinModules.home-manager
"${self}/hosts/darwin/${configName}" "${self}/hosts/darwin/${arch}/${configName}"
"${self}/modules/nixos/darwin" "${self}/modules/nixos/darwin"
# needed for infrastructure # needed for infrastructure
"${self}/modules/nixos/common/meta.nix" "${self}/modules/nixos/common/meta.nix"
"${self}/modules/nixos/common/globals.nix" "${self}/modules/nixos/common/globals.nix"
{ {
node.name = lib.mkForce configName; node.name = lib.mkForce configName;
node.secretsDir = ../hosts/darwin/${configName}/secrets; node.secretsDir = ../hosts/darwin/${arch}/${configName}/secrets;
} }
]; ];
}; };
mkHalfHost = configName: type: pkgs: { mkHalfHost = configName: type: arch:
${configName} = let
let systemFunc = if (type == "home") then inputs.home-manager.lib.homeManagerConfiguration else inputs.nix-on-droid.lib.nixOnDroidConfiguration;
systemFunc = if (type == "home") then inputs.home-manager.lib.homeManagerConfiguration else inputs.nix-on-droid.lib.nixOnDroidConfiguration; pkgs = lib.swarselsystems.pkgsFor.${arch};
in in
systemFunc systemFunc {
{ inherit pkgs;
inherit pkgs; extraSpecialArgs = {
extraSpecialArgs = { inherit inputs lib outputs self configName;
inherit inputs lib outputs self configName; inherit (config) globals nodes;
inherit (config) globals nodes; minimal = false;
minimal = false; };
}; modules = [
modules = [ inputs.stylix.homeModules.stylix
inputs.stylix.homeModules.stylix inputs.niri-flake.homeModules.niri
inputs.niri-flake.homeModules.niri inputs.nix-index-database.homeModules.nix-index
inputs.nix-index-database.homeModules.nix-index # inputs.sops-nix.homeManagerModules.sops
# inputs.sops-nix.homeManagerModules.sops inputs.spicetify-nix.homeManagerModules.default
inputs.spicetify-nix.homeManagerModules.default inputs.swarsel-nix.homeModules.default
inputs.swarsel-nix.homeModules.default "${self}/hosts/${type}/${arch}/${configName}"
"${self}/hosts/${type}/${configName}" "${self}/profiles/home"
"${self}/profiles/home" ];
]; };
};
}; linuxArches = [ "x86_64-linux" "aarch64-linux" ];
darwinArches = [ "x86_64-darwin" "aarch64-darwin" ];
mkArches = type: if (type == "nixos") then linuxArches else if (type == "darwin") then darwinArches else linuxArches ++ darwinArches;
readHostDirs = hostDir:
if builtins.pathExists hostDir then
builtins.attrNames
(
lib.filterAttrs (_: type: type == "directory")
(builtins.readDir hostDir)
) else [ ];
mkHalfHostsForArch = type: arch:
let
hostDir = "${self}/hosts/${type}/${arch}";
hosts = readHostDirs hostDir;
in
lib.genAttrs hosts (host: mkHalfHost host type arch);
mkHostsForArch = type: arch: minimal:
let
hostDir = "${self}/hosts/${type}/${arch}";
hosts = readHostDirs hostDir;
in
if (type == "nixos") then
lib.genAttrs hosts (host: mkNixosHost { inherit minimal; } host arch)
else if (type == "darwin") then
lib.genAttrs hosts (host: mkDarwinHost { inherit minimal; } host arch)
else { };
mkConfigurationsPerArch = type: minimal:
let
arches = mkArches type;
toMake = if (minimal == null) then (arch: _: mkHalfHostsForArch type arch) else (arch: _: mkHostsForArch type arch minimal);
in
lib.concatMapAttrs toMake
(lib.listToAttrs (map (a: { name = a; value = { }; }) arches));
halfConfigurationsPerArch = type: mkConfigurationsPerArch type null;
configurationsPerArch = type: minimal: mkConfigurationsPerArch type minimal;
mkHalfHostConfigs = hosts: type: pkgs: lib.foldl (acc: set: acc // set) { } (lib.map (name: mkHalfHost name type pkgs) hosts);
nixosHosts = builtins.attrNames (lib.filterAttrs (_: type: type == "directory") (builtins.readDir "${self}/hosts/nixos"));
darwinHosts = builtins.attrNames (lib.filterAttrs (_: type: type == "directory") (builtins.readDir "${self}/hosts/darwin"));
in in
{ {
nixosConfigurations = lib.genAttrs nixosHosts (mkNixosHost { nixosConfigurations = configurationsPerArch "nixos" false;
minimal = false; nixosConfigurationsMinimal = configurationsPerArch "nixos" true;
}); darwinConfigurations = configurationsPerArch "darwin" false;
nixosConfigurationsMinimal = lib.genAttrs nixosHosts (mkNixosHost { darwinConfigurationsMinimal = configurationsPerArch "darwin" true;
minimal = true; homeConfigurations = halfConfigurationsPerArch "home";
}); nixOnDroidConfigurations = halfConfigurationsPerArch "android";
darwinConfigurations = lib.genAttrs darwinHosts (mkDarwinHost {
minimal = false;
});
darwinConfigurationsMinimal = lib.genAttrs darwinHosts (mkDarwinHost {
minimal = true;
});
homeConfigurations =
let
inherit (lib.swarselsystems) pkgsFor readHosts;
in
mkHalfHostConfigs (readHosts "home") "home" pkgsFor.x86_64-linux
// mkHalfHostConfigs (readHosts "home") "home" pkgsFor.aarch64-linux;
nixOnDroidConfigurations =
let
inherit (lib.swarselsystems) pkgsFor readHosts;
in
mkHalfHostConfigs (readHosts "android") "android" pkgsFor.aarch64-linux;
guestConfigurations = lib.flip lib.concatMapAttrs config.nixosConfigurations ( guestConfigurations = lib.flip lib.concatMapAttrs config.nixosConfigurations (
_: node: _: node:

View file

@ -6,6 +6,22 @@ let
inherit (inputs.nixpkgs) lib; inherit (inputs.nixpkgs) lib;
in in
rec { rec {
cidrToSubnetMask = cidr:
let
prefixLength = lib.toInt (lib.last (lib.splitString "/" cidr));
bits = lib.genList (i: if i < prefixLength then 1 else 0) 32;
octets = lib.genList
(i:
let
octetBits = lib.sublist (i * 8) 8 bits;
octetValue = lib.foldl (acc: bit: acc * 2 + bit) 0 octetBits;
in
octetValue
) 4;
subnetMask = lib.concatStringsSep "." (map toString octets);
in
subnetMask;
mkIfElseList = p: yes: no: lib.mkMerge [ mkIfElseList = p: yes: no: lib.mkMerge [
(lib.mkIf p yes) (lib.mkIf p yes)
(lib.mkIf (!p) no) (lib.mkIf (!p) no)

View file

@ -15,6 +15,8 @@
boot = lib.mkDefault true; boot = lib.mkDefault true;
server = { server = {
general = lib.mkDefault true; general = lib.mkDefault true;
network = lib.mkDefault true;
diskEncryption = lib.mkDefault true;
packages = lib.mkDefault true; packages = lib.mkDefault true;
ssh = lib.mkDefault true; ssh = lib.mkDefault true;
nginx = lib.mkDefault true; nginx = lib.mkDefault true;

View file

@ -21,6 +21,7 @@
server = { server = {
ssh = lib.mkDefault true; ssh = lib.mkDefault true;
diskEncryption = lib.mkDefault true;
}; };
}; };

View file

@ -0,0 +1,12 @@
{ lib, config, ... }:
{
options.swarselprofiles.router = lib.mkEnableOption "enable the router profile";
config = lib.mkIf config.swarselprofiles.router {
swarselmodules = {
server = {
router = lib.mkDefault true;
};
};
};
}

View file

@ -1,5 +1,5 @@
{ {
"data": "ENC[AES256_GCM,data:8qexHpKJg6o1Fb9H50I3H25UOpNFs2sQl2hd3B2hdJRTjc96aVgTgI838Fnn7G6mFBpHqP0SFCU0/CP6SKqbhJ6SucrfpQN/RqZlSCxmuZi3sqv3voNd7/5JzY0D/5XUTfzHkeEA34HS0GcNLLY7m+QskfJdqGSMB5P++88xCNETqv+sRPVegm1ZGttj+tttesLkAcIU0556WiQhyIcpR4ZiO75NWRFerOmb4LxADR+bwBfesfGUfjflsqOSJll17N9SECSWE7o75Ojn+yde/EznK+zQlsCYvPp90d2xU6dpdRNtp9jrjvXvEVCmcwjIqIKXqurc2CU=,iv:xBYgbmjHwhbH+7WR5MLVysrChxr6rERo6WZuu07sUS0=,tag:vMoMu9mrrGRTA3oO2wsnWw==,type:str]", "data": "ENC[AES256_GCM,data:1nK/JO8sa+N6EXpyIHBnRapOXYbtM38jnNCf/j0wIOG+0uJvQEFc1e9gIFvuvmPUpUjh6XMuEKNxvLTjFlaLiypOX3yJVTn2fiyOWSm244wcye0GRPe+RWIi+1kEPrFDBEG2JFB+9iGSx0Vf2NfBPgaVFnr4Z2TTGH/kvxiTV6KYucWQNHh+jvVKZ6vAsCP2pFWp2yhpov9l5Tj6MwyK7E46Gn7DmCAtlZcA64Nht+99Zrrfuq8byan6w8RMFR830GJvdMAAD/Vsz/6aGQfHhpJwl4L8/4WwvhQq/DuU1umI1Q7r7FosXbos6g8wTWuM3ccD7V//tFDeVkaMKJzkLkQt0JbyzansijadTYjo0I1w15iH2nySBSIrsOJauBcw3XaP6NfAC3fN1lh/fDaj5HWud5v2ginWRfJNYalfMvTkXm2E5m8SXjanGJL1bHBle4TwEDNPT8+LFIJm8gf57rQRcRlh,iv:W3xvnTblM4Aa0dzDKiWqHM6B5zmu5ddk3D4tYAVNBiY=,tag:KelbYP9xbTmDaWiPrkS+Mw==,type:str]",
"sops": { "sops": {
"age": [ "age": [
{ {
@ -27,8 +27,8 @@
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBibGlMSU4vUEF5UlNVZzlr\nMTMyOFY2Zi8rZFdZT1JrelZEUUZkZHFvOFdzCjVPbVovaU9nZklJQWNZeDJZNm0r\nMXBIK2hsZEY0NElxTVVMWmN6WU1Ld28KLS0tIENaallkK05SMllia3prV25hZDR2\nZDBNU0dYYnJESG1JZGpvSGp1WW9UMVEKJgfdLp7BRXvyAekecNJiaBXmxSj1qNxx\nZeHceqEkfWV/PzX+RP4LHjXTQCLEOJijbKxDmxSsYq49hC9xjZASuw==\n-----END AGE ENCRYPTED FILE-----\n" "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBibGlMSU4vUEF5UlNVZzlr\nMTMyOFY2Zi8rZFdZT1JrelZEUUZkZHFvOFdzCjVPbVovaU9nZklJQWNZeDJZNm0r\nMXBIK2hsZEY0NElxTVVMWmN6WU1Ld28KLS0tIENaallkK05SMllia3prV25hZDR2\nZDBNU0dYYnJESG1JZGpvSGp1WW9UMVEKJgfdLp7BRXvyAekecNJiaBXmxSj1qNxx\nZeHceqEkfWV/PzX+RP4LHjXTQCLEOJijbKxDmxSsYq49hC9xjZASuw==\n-----END AGE ENCRYPTED FILE-----\n"
} }
], ],
"lastmodified": "2025-07-22T17:19:04Z", "lastmodified": "2025-11-09T22:41:57Z",
"mac": "ENC[AES256_GCM,data:r1h9ouXb8o8Vk3/l3SX6hxbPApMn4BcCIs52Jhv9s9RYURMGb9qqPipbX7yFIYDBMka2qJJ0BneJz2EI60nTxx+QqATImR2oot2U6iONrelgs+AL3We//xpHOVHSxQ9XMmeEOcVqXEU3u843jV1RElxarRCwB9yM6IWTPx2qNzA=,iv:bS571Ddgz6Fbhyxy2bL/087ZTD7egcvPoLXD9uF8aN0=,tag:HJBI6G6ivRHhJMXYrNhIKw==,type:str]", "mac": "ENC[AES256_GCM,data:iHmgHvT3yn5ayimvO+miRA3dA/0o4juBvBzWIXwtZyt5gSI4oJizMbRaX5coVJgeDdPsYaiQFqSnEPrPmrMIR16jdmscQLvz7X1gtdanMP++5q13jWOkiUHPC2nZy47M+36bzC2P/BHqKE782ERTGnD70VZO4a1lOa7pB32NutY=,iv:oOn9x/xf5g82GXdZ9fDxgEiUScXXfzSdEZccqFQLF4w=,tag:iEhx2Hm0yP6G/1w6cIgHIg==,type:str]",
"pgp": [ "pgp": [
{ {
"created_at": "2025-07-02T12:10:18Z", "created_at": "2025-07-02T12:10:18Z",
@ -37,6 +37,6 @@
} }
], ],
"unencrypted_suffix": "_unencrypted", "unencrypted_suffix": "_unencrypted",
"version": "3.10.2" "version": "3.11.0"
} }
} }