Einmal NixOS und zurück

Einmal NixOS und zurück

Eigentlich wollte ich etwas ganz anderes machen: Einen Tiling Windowmanager wie Sway oder Hyprland ausprobieren. Irgendwie lief mir dann aber zum wiederholten Mal NixOS über den Weg, weswegen ich beide Erkundungen miteinander verbinden wollte. Sway und Co. habe ich als alter (und vielleicht etwas eingefahrener) KDE-User nach ersten Tests doch erst mal wieder hinten angestellt. Aber NixOS, das hat mich irgendwie erreicht.

In dem Artikel beschreibe ich (m)einen kleinen Streifzug durch NixOS, das den Ansatz einer deklarativen Systemkonfiguration verfolgt. NixOS soll dabei von Grund auf installiert und danach ein Desktop Environment (KDE Plasma) installiert werden.

Hinweis: Ich finde die Dokumentation von NixOS zwar umfassend, aber nicht wirklich stringent. Ich habe keine Ahnung wie ideomatisch mein Vorgehen ist, oder ob der gemeine NixOS-User manches anders machen würde. Da jedoch alles prima funktioniert hat, kann es nicht so falsch gewesen sein. Komplett ignoriert habe ich Flakes. Sorry dafür! Das war mir für den Einstieg einfach zu viel und wird evtl. gelegentlich nachgeholt.

Grundinstallation

Es gibt zwar einen grafischen Installer, für die volle Dröhnung habe ich mich allerdings für die manuelle Installation, also für das Minimal ISO Image entschieden. Ich habe mich nach der Installationsanleitung gerichtet. Außerdem wollte ich gerne ein verschlüsseltes System mit Btrfs haben, einfach um zu sehen ob das auch gut machbar ist. Dieser Wiki-Eintrag geht darauf ein. Für den Artikel hier fasse ich mein Vorgehen also nur kurz zusammen – für nähere Informationen sei auf die verlinkten Seiten verwiesen.

Nach dem Booten des Installer-ISOs

Nach dem Booten des Minimal ISO Image findet man sich also – ganz ähnlich wie bei einer Installation von Arch Linux – in einer Konsole wieder. Mit sudo -i kann man gleich mal root-Rechte erlangen und ggf. mit loadkeys de auf deutsches Tastaturlayout umstellen.

Partitionierung

Für mein Setup genügen zwei Partitionen: Eine kleine für die EFI-Bootpartition und eine große für Btrfs. Für letzteres werden später noch Subvolumes erstellt. Partitionstabelle erstellen und partitionieren kann man mit printf "label: gpt\n,1G,U\n,,L\n" | sfdisk /dev/vda in einem Aufwasch machen. Hier wird also eine GPT-Partitionstabelle erstellt und anschließend eine UEFI-konforme, kleine Partition sowie eine Linuxpartition, die den Rest der Festplatte einnimmt.

Die Bootpartition kann schonmal formatiert werden (Pfad zum Device ggf. anpassen!):

mkfs.vfat -n BOOT /dev/vda1

Verschlüsselung

Die Btrfs-Partition soll ja verschlüsselt werden, daher müssen wir die Partition erstmal mit cryptsetup vorbereiten:

cryptsetup --verify-passphrase -v luksFormat /dev/vda2

WARNING!
========
This will overwrite data on /dev/vda2 irrevocably.

Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/vda2: 
Verify passphrase: 
Key slot 0 created.
Command successful.

Mit cryptsetup open /dev/vda2 enc öffnen wir nun die Partition; sie ist nun unter /dev/mapper/enc verfügbar.

Einhängen der Partitionen

Jetzt können die Btrfs-Subvolumes erstellt werden. Natürlich sind hier ganz ausgefuchste Setups denkbar. Ich möchte im Wesentlichen gerne von /home ein Backup machen können, weswegen das auf jeden Fall ein eigenes Subvolume bekommt; ansonsten halte ich es eher einfach. Zusammengefasst:

mkfs.btrfs /dev/mapper/enc          # Dateisystem erstellen

mount -t btrfs /dev/mapper/enc /mnt # Btrfs-System nach /mnt mounten

# Erstellen der Subvolumes

btrfs subvolume create /mnt/@       # /

btrfs subvolume create /mnt/@home   # /home

btrfs subvolume create /mnt/@nix    # /nix 

Nachdem das gemacht ist, hängt man das Btrfs-Dateisystem mit umount /mnt zunächst aus und mounted dann nach /mnt wieder alles so, wie man es für die Installation haben möchte. Also zunächst @ als / und darin dann die anderen Subvolumes /home und /nix (und natürlich noch die Bootpartition):

mount -o subvol=@,compress=zstd,noatime /dev/mapper/enc /mnt 

mkdir /mnt/home

mount -o subvol=@home,compress=zstd,noatime /dev/mapper/enc /mnt/home

mkdir /mnt/nix

mount -o subvol=@nix,compress=zstd,noatime /dev/mapper/enc /mnt/nix

mkdir /mnt/boot

mount /dev/vda1 /mnt/boot

Let’s go

Jetzt wird es spannend. Das Kommando nixos-generate-config --root /mnt erstellt zwei Konfigurationsdateien:

  • /mnt/etc/nixos/hardware-configuration.nix
  • /mnt/etc/nixos/configuration.nix

Vor der Installation müssen wir noch schnell die zweite Datei anfassen, da nixos-generate-config keine Mountoptionen erkennt. Folgendes muss also in configuration.nix eingetragen werden:

fileSystems = {
  "/".options = [ "compress=zstd" "noatime" ];
  "/home".options = [ "compress=zstd" "noatime" ];
  "/nix".options = [ "compress=zstd" "noatime" ];
};

Außerdem kann man hier noch die Zeitzone (time.timeZone) korrigieren und die Lokalisierung einstellen (i18n.defaultLocale, keymap in console sowie services.xserver.xkb.layout).

Und jetzt geht’s los: nixos-install führt endlich die Installation aus. Dabei wird noch nach dem zukünftigen root-Passwort gefragt:

[…]
New password: 
Retype new password: 
passwd: password updated successfully
installation finished!

Das war’s! Ein reboot startet das System neu und nach Eingabe des Passworts für die Festplattenverschlüsselung begrüßt uns NixOS mit dem Login-Prompt:

NixOS Login Prompt

User einrichten, weitere Einstellungen

Um etwas sinnvolles zu machen, sollten wir erst mal einen User erstellen. Das macht man aber nicht etwa mit adduser o.ä., nein, wir machen das gleich mal entprechend dem Nix-Way. Hierfür muss auch wieder die Datei /etc/nixos/configuration editiert werden.

Ich habe hierfür die auskommentierte Vorgabe einfach angepasst:

users.users.martin = {
    isNormalUser = true;
    extraGroups = [ "wheel", "networkmanager" ]; # Enable ‘sudo’ for the user.
  #   packages = with pkgs; [
  #     tree
  #  ];
  };

Bei der Gelegenheit können wir auch gleich noch schauen, ob andere auskommentierte Einstellungen für uns sinnvoll sind. Ich habe z.B. noch den NetworkManager (networking.networkmanager.enable = true;), OpenSSH (services.openssh.enable = true;) sowie PipeWire (services.pipewire […]) aktiviert.

Unter environment.systemPackages kann man noch Programme auflisten, die systemweit installiert werden sollen. Für mich gehören da auf jeden Fall schon mal Helix und htop mit dazu:

environment.systemPackages = with pkgs; [
  helix
  htop
];

Natürlich gibt es noch vieles andere mehr, was man hier tun oder lassen lassen kann. Schlussendlich reicht ein nixos-rebuild switch um sich ein System entsprechend den getätigten Vorgaben bauen zu lassen. An der Stelle habe ich einen Reboot gemacht und mich unter dem neu erstellten User angemeldet. Vor dem Reboot habe ich ihm noch mit passwd martin das gewünschte Passwort vergeben.

Desktop Environment …

Das Tolle ist: Man kann jetzt nach Lust und Laune ausprobieren und herumbasteln (zumindest in einem gewissen Rahmen). Wenn etwas schiefgeht, kann man einfach zur letzten funktionierenden Konfiguration zurückgehen (Rollback), etwa mittels nixos-rebuild switch --rollback.

In unserem NixOS-Test entscheide ich mich erst einmal dazu, KDE Plasma zu installieren. Um später einfacher zu einem anderen Desktop Environment wechseln zu können, lagere ich den KDE-spezifischen Teil in eine eigene Datei aus und binde diese in die configuration.nix Datei ein.

Hier meine /etc/nixos/kde.nix-Datei, die natürlich – wie alles hier – nur ein minimaler Test sein soll. Da ich die KDE-eigenen PIM-Programme nicht benötige, exkludiere ich diese in der Config:

{ config, pkgs, ... }:

{
  services.xserver.enable = true; # optional
  services.displayManager.sddm.enable = true;
  services.displayManager.sddm.wayland.enable = true;
  services.desktopManager.plasma6.enable = true;
  
  environment.plasma6.excludePackages = with pkgs.kdePackages; [
    kdepim-runtime
  ];
}

Die Einbindung in configuration.nix darf nicht vergessen werden:

imports =
  [ # Include the results of the hardware scan.
    ./hardware-configuration.nix
    # KDE Plasma 6
    ./kde.nix
  ];

Und mit einem neuerlichen nixos-rebuild switch haben wir – schwuppdiwupp – ein mit KDE eingerichtetes System.

SDDM Login Screen

… oder doch etwas anderes?

Und wenn einem doch der Sinn danach steht, einen Tiling Windowmanager wie Sway auszuprobieren, ist das kein Problem. Dazu braucht es lediglich ein paar Änderungen, oder eben eine sway.nix-Datei, die man anstelle von kde.nix einbindet. Spaßhalber verwende ich nicht SDDM, sondern greetd als Login Manager:

{ config, pkgs, lib, ... }:

{
  environment.systemPackages = with pkgs; [
    grim
    slurp
    wl-clipboard
    mako
  ];

  services.gnome.gnome-keyring.enable = true;

  programs.sway = {
    enable = true;
    wrapperFeatures.gtk = true;
  };
  
  services.greetd = {                                                      
    enable = true;                                                         
    settings = {                                                           
      default_session = {                                                  
        command = "${pkgs.greetd.tuigreet}/bin/tuigreet --time --cmd sway";
        user = "greeter";                                                  
      };                                                                   
    };                                                                     
  };
}

“Sway”

Durch das vorherige KDE Plasma ist das System nicht etwa verbaselt. Keine Spur mehr von den üblichen KDE-Anwendungen. Bei vielen anderen Linux-Distributionen wäre so ein “sauberer” Wechsel nur mit Aufwand möglich!

Aufräumen

Dabei wird grundsätzlich nichts überschrieben. Die KDE-Pakete sind im Nix-Store immer noch vorhanden (aber eben nicht “eingebunden”). Bei Bedarf könnte man einfach wieder auf die alte Konfiguration umschalten. Doch sammeln sich so natürlich immer mehr Dateien an und die Platte füllt sich. Auch die Bootloader-Einträge sammeln sich mit jedem nixos-rebuild an. NixOS bietet Mechanismen an, die alte Konfigurationen (bei Bedarf zyklisch) entfernt. Oder aber man räumt selbst auf. Nicht mehr referenzierte Pakete lassen sich mit nix-collect-garbage entfernen. Alte Systemkonfiguration werden dadurch jedoch nicht entfernt; ein Rollback wäre immer noch möglich. Möchte man alte Zöpfe abschneiden und ein Rollback somit unmöglich machen, ist dies mit nix-collect-garbage -d (als root) möglich.

Ausblick

Das bisherige hat wirklich nur an der Oberfläche von Nix(OS) gekratzt. Wir haben noch nicht einmal über Flakes gesprochen, ein experimentelles aber sehr beliebtes Feature, das auch Versionspinning mittels lock-Dateien erlaubt. Im NixOS-Manual begegnet einem das aber nur am Rande.

Ebenso wenig betrachtet wurde Home Manager, womit man unter anderem die Dot-Dateien in den Homeverzeichnissen der Benutzer verwalten kann.

Und so gibt es sicherlich noch viele Features, die in dem kleinen NixOS-Ausflug hier völlig ignoriert wurden, da dem Autor womöglich gar nicht bekannt.

Möchte man sich ernsthaft mit NixOS beschäftigen, empfiehlt sich sicherlich die Lektüre des Nix-Manuals, das also den Nix-Paketmanager behandelt. Insbesondere der Teil über nix-shell ist interessant, womit man temporär einfach mal schnell Pakete “installieren” kann und die, wenn man diese Nix-Shell verlässt, wieder verschwunden sind. Das NixOS-Manual behandelt dann die NixOS-Distribution.

Fazit

NixOS bietet einen völlig anderen Ansatz als alle Linux-Distributionen die ich bisher kennengelernt habe. Ich finde NixOS hochinteressant und es gefällt mir, wie einfach man ein neues “sauberes” Setup bauen kann, ohne dass es in Pakete(de)installationsarien ausartet. Warum also, um den Titel des Artikels nochmal aufzugreifen "… und zurück"? Ich fühle mich noch nicht bereit, um auf NixOS umzusteigen, es ist einfach zu … anders. Als alter Arch Linux User fühle ich mich mit pacman und Co. einfach noch sicherer. Ich habe das Gefühl, noch viel mehr über NixOS in Erfahrung bringen zu müssen, um den Schritt zu wagen. Vielleicht würde die Lektüre des NixOS & Flakes Buchs helfen, das ich mir sicherlich mal zu Gemüte führen werde.