Files
moonix/hosts/desktop/default.nix
T
nevaforget d3cc03c7e0 fix(desktop): drop snapper, which never took a snapshot
The module wrote the configs and the timers, but nothing creates the
.snapshots subvolumes they need, so snapper-timeline failed every hour
with errno:2 and there was never a single snapshot to roll back to.

Removing it rather than fixing it: rollbacks of / are already covered by
NixOS generations, and snapshots of /home would have shared a disk with
/home. That answers "I deleted the wrong file" but not "the disk is
gone", and the second is the failure that actually occurred here.
2026-09-09 18:45:38 +02:00

164 lines
7.1 KiB
Nix

# ABOUTME: Host configuration for the desktop: 512G system disk, 1T disk for /home.
# ABOUTME: Disk layout comes from modules/disk.nix, nothing is generated on the machine.
{ config, lib, pkgs, ... }:
{
# Read off the machine with `ls -l /dev/disk/by-id/`: the 512G XPG is the
# system disk and carries /home as well. disko-install still overrides it with
# `--disk main <path>`, so check that against lsblk before installing — by-id
# names follow the drive, not the slot, and a replaced disk changes them.
#
# The 1T Crucial P1 (CT1000P1SSD8_2030E2BAC109) carried /home until 09.09.2026
# and is deliberately out of this layout. Its controller hits 90 °C under pure
# read load while the rest of the drive stays at 45, throttles from 1.5 GB/s to
# under a megabyte, and fell off the PCIe bus four times in four days
# (`controller is down, CSTS=0xffffffff`), forcing /home read-only. SMART is
# clean and P3CR013 is the final firmware, so there is nothing to repair. The
# disk stays in the M2_2 slot, but nothing here references it: no partition, no
# LUKS container, no mount.
moonarch.disk = {
enable = true;
device = "/dev/disk/by-id/nvme-XPG_GAMMIX_S11_Pro_2K322LAES7JG";
};
# The P1 from the comment above is back, but only for data whose loss costs
# nothing: a Steam library that can be downloaded again, and whatever else ends
# up not mattering. It stays deliberately outside moonarch.disk — nothing here
# partitions or formats it, and a rebuild must never touch what is on it.
#
# Every option below exists so that a dead or missing disk cannot hold up the
# boot, which is precisely what this one used to do. The container is opened
# after stage 1 rather than in the initrd, by a keyfile that itself sits on the
# encrypted system disk, and the filesystem is mounted only on first access. If
# the drive is gone, systemd gives up after five seconds and the machine
# carries on without it. idle-timeout unmounts it again once nothing uses it,
# which keeps it cold — and cold is when this drive works.
environment.etc.crypttab.text = ''
p1 UUID=0dee2385-7130-40c6-aa0c-a233e611b568 /var/keys/p1.key noauto,nofail
'';
fileSystems."/storage" = {
device = "/dev/mapper/p1";
fsType = "btrfs";
options = [
"subvol=storage"
"compress=zstd"
"noatime"
"noauto"
"nofail"
"x-systemd.automount"
"x-systemd.device-timeout=5"
"x-systemd.mount-timeout=10"
"x-systemd.idle-timeout=600"
];
};
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
boot.kernelPackages = pkgs.linuxPackages_zen;
boot.kernelParams = [ "quiet" ];
networking.hostName = "desktop";
networking.networkmanager.enable = true;
time.timeZone = "Europe/Berlin";
i18n.defaultLocale = "de_DE.UTF-8";
i18n.extraLocaleSettings = {
LC_ADDRESS = "de_DE.UTF-8";
LC_IDENTIFICATION = "de_DE.UTF-8";
LC_MEASUREMENT = "de_DE.UTF-8";
LC_MONETARY = "de_DE.UTF-8";
LC_NAME = "de_DE.UTF-8";
LC_NUMERIC = "de_DE.UTF-8";
LC_PAPER = "de_DE.UTF-8";
LC_TELEPHONE = "de_DE.UTF-8";
LC_TIME = "de_DE.UTF-8";
};
console.keyMap = "de";
services.xserver.xkb.layout = "de";
moonarch.user = "dkressler";
users.users.${config.moonarch.user} = {
isNormalUser = true;
# gamemode: the module creates the group but adds nobody. Without it
# gamemoded is denied the governor change on every game launch.
extraGroups = [ "networkmanager" "wheel" "video" "input" "plugdev" "docker" "gamemode" ];
shell = pkgs.zsh;
# Autologin gets past the greeter without a password, but swaylock
# authenticates through pam_unix and cannot unlock a screen for an account
# that has none. `mutableUsers` is at its default, so this applies when the
# account is created and `passwd` overrides it afterwards. Change it after
# the first boot — this value is in the repository.
initialPassword = "moonarch";
};
# LUKS already asked for a passphrase at boot, so the greeter would only ask
# for a second one. initial_session runs once per boot — the greeter comes
# back on logout, which is also where a session gets switched. greetd's
# restart option flips itself off when this is set.
services.greetd.settings.initial_session = {
command = "${pkgs.niri}/bin/niri-session";
user = config.moonarch.user;
};
# No snapper here. It was configured for / and /home and never took a single
# snapshot: the module writes the configs and the timers, but nobody creates
# the .snapshots subvolumes they need, so snapper-timeline failed every hour
# with errno:2 for months without anyone noticing. Rather than paper over that,
# note what it would and would not have bought: rollbacks of / are already
# covered by NixOS generations, and snapshots of /home share a disk with /home,
# so they answer "I deleted the wrong file" but not "the disk is gone" — which
# is the failure that actually happened here on 09.09.2026. The second question
# needs a copy off this machine and is still unanswered.
# No nixos-hardware profile applies to a self-built desktop, so the firmware
# this machine needs is enabled here instead.
hardware.enableRedistributableFirmware = true;
# The nixos-hardware profile derives this from enableRedistributableFirmware
# on the ThinkPad; here nothing does, so without this line the CPU runs on the
# microcode in its BIOS.
hardware.cpu.amd.updateMicrocode = true;
# The GPU is AMD, so amdgpu and Mesa cover it and there is nothing to declare:
# the kernel module is in the default initrd and Mesa comes with the graphics
# stack. An NVIDIA card would have needed videoDrivers and hardware.nvidia.
services.fstrim.enable = true;
# modules/services.nix turns fwupd on for every host. Lenovo publishes to the
# LVFS, so it earns its place on the ThinkPad; desktop mainboard vendors
# mostly do not, which leaves a daemon with nothing to update. mkForce because
# the shared module sets it unconditionally.
services.fwupd.enable = lib.mkForce false;
# --- Applications, this machine only ---
#
# Steam comes as a module rather than a package: it wraps the binary in an FHS
# environment and turns on 32-bit graphics for the drivers, which the package
# alone would not do.
programs.steam.enable = true;
# The module, not the package: gamemoded needs cap_sys_nice for renice and a
# pkexec helper for the governor, so the module wraps the binary, creates the
# gamemode group and enables the user service. Games are started through
# `gamemoderun`.
programs.gamemode.enable = true;
# Lets audio applications ask for realtime scheduling, which Bitwig does. The
# rlimits the PipeWire module sets (rtprio 95, memlock) apply to members of
# the pipewire group only, and this account is not one.
security.rtkit.enable = true;
environment.systemPackages = [ pkgs.bitwig-studio ];
nix.settings.experimental-features = [ "nix-command" "flakes" ];
nixpkgs.config.allowUnfree = true;
# The release this machine is first installed with. It stays at this value
# for the life of the installation and is never raised by an update.
system.stateVersion = "26.11";
}