feat(nixos): consolidate hosts into a shared flake

Manage T450s, X1EG2 and Framework 13 from pinned NixOS inputs while retaining
machine-specific storage and hardware configuration.

Changes:

Shared Configuration:
- Extract common, KDE, desktop, development and Steam modules
- Share Emacs, VS Code, htop, DevOps tools and Docker across hosts
- Remove obsolete apps and global project language runtimes

Framework:
- Import the 11th-generation Intel hardware profile
- Enable Steam and ZFS with tookland/home mounted at /home
- Document manual ext4 root and ZFS installation steps
- Require installer-generated hardware configuration before installation

Validation:
- Evaluate both ThinkPads and Framework with test hardware
- Check Nix syntax, formatting and whitespace
This commit is contained in:
clw committed 2026-10-06 15:58:10 +01:00
commit 28e8bc938a
16 files changed
+922

No files matched your search

+100
View File
@@ -0,0 +1,100 @@
# Framework 13 installation
Target: Intel 11th-generation Core i5-1135G7. The flake imports
`nixos-hardware.nixosModules.framework-11th-gen-intel` for model-specific tuning
and enables firmware updates, KDE, shared development tools and Steam.
## Storage layout
| Partition | Filesystem | Use |
| --- | --- | --- |
| EFI system partition | FAT32, suggested 1 GiB | `/boot` |
| Linux root partition | ext4, suggested 128–160 GiB | `/`, including `/nix` and `/var` |
| Remaining space | ZFS pool `tookland` | `tookland/home` at `/home`; later VM/ISO datasets |
Adjust the root size for the drive capacity and your Nix store/container needs.
The ext4 and ZFS partitions have separate space budgets; unused ZFS space does
not automatically grow the ext4 partition. These instructions use unencrypted
filesystems; any disk-encryption setup must be chosen before formatting.
NixOS manages support, imports and mounts once the pool exists. This repo does
not automate disk partitioning or pool/dataset creation. Use the installer disk
utility to create this GPT layout. Formatting and pool creation erase the
selected partitions: check the actual drive with `lsblk` and use its persistent
`/dev/disk/by-id/…-partN` names. No commands here operate on a guessed device.
## Format and mount in the installer
Boot a current NixOS installer with ZFS support and network access. Substitute
the three partition paths below with the partitions you just created. The
literal placeholders will not work as device names.
```sh
sudo mkfs.fat -F 32 -n EFI "/dev/disk/by-id/REPLACE_WITH_EFI_PARTITION"
sudo mkfs.ext4 -L nixos-root "/dev/disk/by-id/REPLACE_WITH_ROOT_PARTITION"
sudo mount "/dev/disk/by-id/REPLACE_WITH_ROOT_PARTITION" /mnt
sudo mkdir -p /mnt/boot /mnt/home
sudo mount "/dev/disk/by-id/REPLACE_WITH_EFI_PARTITION" /mnt/boot
sudo modprobe zfs
sudo zpool create -o ashift=12 -o autotrim=on \
-O compression=lz4 -O acltype=posixacl -O xattr=sa -O relatime=on \
-m none -R /mnt tookland "/dev/disk/by-id/REPLACE_WITH_ZFS_PARTITION"
sudo zfs create -o mountpoint=legacy tookland/home
sudo mount -t zfs tookland/home /mnt/home
sudo zpool status tookland
sudo zfs list -o name,mountpoint
```
Do not format the ZFS partition with `mkfs`. `zpool create` initializes it.
The pool's root dataset has no mountpoint; `tookland/home` uses a legacy
mountpoint so the NixOS `fileSystems."/home"` declaration manages its mount.
`-R /mnt` is an installer-only alternate root, not a permanent `/mnt` mountpoint.
Neither the pool nor its datasets are recreated during a rebuild.
## Generate hardware configuration and install
Generate configuration **after** all three filesystems, including `/mnt/home`,
are mounted. This records your real hardware and filesystem layout.
```sh
sudo nixos-generate-config --root /mnt
# Obtain Git if it is not already available in the installer.
nix --extra-experimental-features 'nix-command flakes' shell nixpkgs#git
sudo git clone <repository-url> /mnt/etc/nixos-config
sudo cp /mnt/etc/nixos/hardware-configuration.nix \
/mnt/etc/nixos-config/hosts/framework/hardware-configuration.nix
sudo git -C /mnt/etc/nixos-config add hosts/framework/hardware-configuration.nix
sudo nixos-install --flake /mnt/etc/nixos-config#framework
sudo nixos-enter --root /mnt -c 'passwd clw'
```
Review the generated hardware file: `/` must be `ext4`, `/boot` must be `vfat`,
and `/home` must refer to `tookland/home` with `fsType = "zfs"`. Identical `/home`
declarations in the generated file and host configuration merge normally.
The installer-generated `configuration.nix` is not used by this flake.
Once installation and password setup are complete, leave any shell working
under `/mnt/home`, export the pool cleanly, and reboot:
```sh
sudo zpool export tookland
sudo reboot
```
NixOS imports `tookland` and mounts home before user activation. Its fixed host
ID is `fdc3ff7d`; retain it across reinstalls using this pool. Scrubs are enabled.
Create other datasets yourself with explicit mountpoints, for example
`zfs create -o mountpoint=/srv/isos tookland/isos`. Datasets with native
mountpoints are mounted by ZFS; those with `mountpoint=legacy` also need a
NixOS `fileSystems` declaration. Snapshot/backup policies are not configured.
References: [Framework hardware profile](https://github.com/NixOS/nixos-hardware/tree/master/framework/13-inch/11th-gen-intel),
[NixOS ZFS configuration](https://wiki.nixos.org/wiki/ZFS),
[OpenZFS pool creation](https://openzfs.github.io/openzfs-docs/man/master/8/zpool-create.8.html).
Validation: this host evaluates to a complete system derivation with a temporary
installer-style ext4/EFI fixture and a duplicate generated `/home` declaration.
Intel microcode, graphics, Steam and ZFS are enabled. Both existing hosts still
evaluate. The actual disk layout and generated hardware file must be supplied
on the Framework; no full build or disk operation was performed during checks.
+39
View File
@@ -0,0 +1,39 @@
{ ... }:
{
imports = [
./hardware-configuration.nix
../../modules/common.nix
../../modules/kde.nix
../../modules/development.nix
../../modules/gaming.nix
];
nixpkgs.hostPlatform = "x86_64-linux";
networking.hostName = "framework";
# Stable, unique ID required by ZFS; keep it unchanged after pool creation.
networking.hostId = "fdc3ff7d";
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
# Framework 13, Intel Core i5-1135G7. Hardware tuning comes from nixos-hardware.
services.fwupd.enable = true;
# Existing pool/dataset must be created in the installer; root stays ext4.
boot.supportedFilesystems = [ "zfs" ];
boot.zfs.extraPools = [ "tookland" ];
boot.zfs.forceImportRoot = false;
fileSystems."/home" = {
device = "tookland/home";
fsType = "zfs";
# Mount home before activation creates user directories.
neededForBoot = true;
};
services.zfs.autoScrub.enable = true;
# A simple laptop policy using Plasma's power management integration.
services.power-profiles-daemon.enable = true;
services.libinput.enable = true;
# First installation release; keep this unchanged after installation.
system.stateVersion = "26.05";
}
@@ -0,0 +1,12 @@
# Replace this entire file with /mnt/etc/nixos/hardware-configuration.nix
# after running: sudo nixos-generate-config --root /mnt
# No disks, UUIDs, CPU vendor, or GPU model are guessed here.
{ ... }:
{
assertions = [
{
assertion = false;
message = "Framework hardware configuration is missing. Run nixos-generate-config --root /mnt and replace hosts/framework/hardware-configuration.nix with the generated file.";
}
];
}
+71
View File
@@ -0,0 +1,71 @@
{ pkgs, unstable, ... }:
{
imports = [
./hardware-configuration.nix
../../modules/common.nix
../../modules/kde.nix
../../modules/development.nix
../../modules/desktop-apps.nix
../../modules/gaming.nix
];
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
boot.initrd.secrets = {
"/crypto_keyfile.bin" = null;
};
boot.initrd.luks.devices."luks-a9814d3c-ecfc-4aae-a5a9-976a55af4609".device =
"/dev/disk/by-uuid/a9814d3c-ecfc-4aae-a5a9-976a55af4609";
boot.initrd.luks.devices."luks-a9814d3c-ecfc-4aae-a5a9-976a55af4609".keyFile =
"/crypto_keyfile.bin";
boot.supportedFilesystems = [ "zfs" ];
boot.zfs.forceImportRoot = false;
networking.hostId = "561bd410";
boot.binfmt.registrations.appimage = {
wrapInterpreterInShell = false;
interpreter = "${pkgs.appimage-run}/bin/appimage-run";
recognitionType = "magic";
offset = 0;
mask = ''\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff'';
magicOrExtension = ''\x7fELF....AI\x02'';
};
networking.hostName = "samwise";
services.printing.drivers = [
pkgs.hplipWithPlugin
pkgs.cnijfilter2
];
services.tailscale.enable = true;
hardware.sane.enable = true;
environment.systemPackages = with pkgs; [
unstable.android-studio
unstable.anytype
unstable.easyeffects
unstable.element-desktop
ffmpeg
kdePackages.kcalc
mailspring
unstable.nextcloud-client
unstable.onedrive
postman
unstable.threema-desktop
unstable.vcmi
wine
unstable.zoom-us
];
services.openssh.enable = true;
networking.firewall.enable = false;
system.stateVersion = "23.05";
}
+42
View File
@@ -0,0 +1,42 @@
# Do not modify this file! It was generated by ‘nixos-generate-config’
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "xhci_pci" "ehci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" "rtsx_pci_sdmmc" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/aaa3f4d7-a3fe-42a0-ad9c-becd3bca2531";
fsType = "ext4";
};
boot.initrd.luks.devices."luks-7e29288b-0c13-4aa6-827c-7acd692f7f91".device = "/dev/disk/by-uuid/7e29288b-0c13-4aa6-827c-7acd692f7f91";
fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/1353-1FB4";
fsType = "vfat";
};
swapDevices =
[ { device = "/dev/disk/by-uuid/4dfd4a6e-118d-4138-9c65-be32bbf37092"; }
];
# 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.enp0s25.useDHCP = lib.mkDefault true;
# networking.interfaces.wlp3s0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}
+172
View File
@@ -0,0 +1,172 @@
{
config,
lib,
pkgs,
unstable,
...
}:
{
imports = [
./hardware-configuration.nix
../../modules/common.nix
../../modules/kde.nix
../../modules/development.nix
../../modules/desktop-apps.nix
../../modules/gaming.nix
];
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
boot.initrd.luks.devices = {
"luks-rpool-nvme-WDS500G3X0C-00SJG0_2017B0802813-part2".device =
"/dev/disk/by-id/nvme-WDS500G3X0C-00SJG0_2017B0802813-part2";
};
boot.zfs.extraPools = [ "shire" ];
# Preserve the original root-pool import policy across the release upgrade.
boot.zfs.forceImportRoot = true;
services.zfs.autoScrub.enable = true;
networking.hostName = "bilbo";
hardware.graphics = {
enable = true;
enable32Bit = true;
extraPackages = with pkgs; [
intel-media-driver # LIBVA_DRIVER_NAME=iHD
intel-vaapi-driver # LIBVA_DRIVER_NAME=i965 (older but works better for Firefox/Chromium)
libvdpau-va-gl
];
};
environment.sessionVariables = {
LIBVA_DRIVER_NAME = "iHD";
}; # Force intel-media-driver
services.xserver.videoDrivers = [ "nvidia" ];
hardware.nvidia = {
modesetting.enable = true;
powerManagement.enable = false;
powerManagement.finegrained = true;
open = false;
nvidiaSettings = true;
package = config.boot.kernelPackages.nvidiaPackages.stable;
};
hardware.nvidia.prime = {
offload = {
enable = true;
enableOffloadCmd = true;
};
intelBusId = "PCI:0:2:0";
nvidiaBusId = "PCI:1:0:0";
};
services.tailscale.enable = true;
services.undervolt = {
enable = true;
coreOffset = -100;
};
virtualisation.libvirtd = {
enable = true;
qemu = {
package = pkgs.qemu_kvm;
runAsRoot = true;
swtpm.enable = true;
};
};
hardware.nvidia-container-toolkit = {
enable = true;
package = unstable.nvidia-container-toolkit;
};
environment.systemPackages = with pkgs; [
unstable.android-studio
android-tools
ffmpeg
gimp
adwaita-icon-theme
kdePackages.kcalc
lutris
unstable.mailspring
nextcloud-client
unstable.nvidia-container-toolkit
nvtopPackages.full
pinentry-qt
syncthing
thunderbird
unstable.threema-desktop
wineWow64Packages.waylandFull
zoom-us
];
fonts.packages = with pkgs; [
noto-fonts
noto-fonts-cjk-sans
noto-fonts-cjk-serif
];
services.sanoid = {
enable = true;
templates = {
production = {
autoprune = true;
autosnap = true;
hourly = 36;
daily = 30;
monthly = 3;
};
};
datasets = {
"rpool/home" = {
use_template = [ "production" ];
};
"shire/clw/projects" = {
use_template = [ "production" ];
};
"shire/clw/Documents" = {
use_template = [ "production" ];
};
};
};
services.syncthing = {
enable = true;
user = "clw";
dataDir = "/home/clw/Sync";
configDir = "/home/clw/.config/syncthing";
};
programs.steam = {
package = pkgs.steam.override {
extraPkgs = (
pkgs: with pkgs; [
gamemode
]
);
extraProfile =
let
gmLib = "${lib.getLib (pkgs.gamemode)}/lib";
in
''
export LD_LIBRARY_PATH="${gmLib}:$LD_LIBRARY_PATH"
'';
};
};
programs.gamemode.enable = true;
networking.firewall.enable = false;
system.stateVersion = "23.11";
users.users.clw.extraGroups = [
"libvirtd"
"kvm"
];
}
+46
View File
@@ -0,0 +1,46 @@
# Do not modify this file! It was generated by ‘nixos-generate-config’
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" "sdhci_pci" "battery" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "rpool/root";
fsType = "zfs";
};
fileSystems."/home" =
{ device = "rpool/home";
fsType = "zfs";
};
fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/BF51-953A";
fsType = "vfat";
};
swapDevices =
[ { device = "/dev/disk/by-uuid/a468fc29-ad58-474b-ac91-abc40d3567b3"; }
];
# 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.enp0s31f6.useDHCP = lib.mkDefault true;
# networking.interfaces.wlp82s0.useDHCP = lib.mkDefault true;
networking.hostId = "7330cb06";
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}