NixOS 25.11 — installation reproductible, dérive zéro, contrôle maximal

Cet article vous a aidé ?

Vous connaissez cette sensation : un serveur « marche en grande partie », sauf que personne ne sait pourquoi. La règle de pare-feu a été modifiée « temporairement » le trimestre dernier, un paramètre du noyau a été édité à 2h du matin, et la disposition des disques est une surprise qui attend d’arriver lors de la prochaine panne.

NixOS est l’antidote si vous le considérez comme un système d’exploitation, pas comme un passe‑temps. Ceci est une installation orientée production de NixOS 25.11 visant la reproductibilité, une dérive minimale et le type de contrôle que l’on n’apprécie qu’après avoir débogué un bootloader cassé dans un centre de données froid.

Ce que vous construisez (et ce que vous ne construisez pas)

Vous construisez une machine qui peut être reconstruite. Pas « réinstallée avec des notes ». Reconstruite. À partir d’un repo. À la demande. Avec une piste d’audit.

Cela signifie trois points non négociables :

  • État système déclaratif : services, utilisateurs, paquets, réseau, systèmes de fichiers, paramètres du noyau.
  • Modifications atomiques : vous n’« appliquez » pas de correctifs, vous construisez une nouvelle génération du système et basculez dessus.
  • Rollback en tant que fonctionnalité de première classe : parce que la production aime les surprises, et que NixOS les déteste.

Ce que vous ne construisez pas : une machine unique « personnalisée » avec des modifications manuelles dans /etc et un tas d’historique shell. Si vous voulez cette vie, n’importe quel autre Linux vous l’autorisera volontiers.

Et clarifions une chose : NixOS ne vous sauvera pas des mauvaises décisions. En revanche, il les préservera parfaitement et de façon reproductible. C’est une caractéristique, pas une menace.

Faits et contexte intéressants (pourquoi ceci existe)

NixOS n’est pas apparu parce que quelqu’un voulait un nouveau système d’initialisation pour débattre. C’est le résultat pratique de traiter le déploiement logiciel comme un problème de construction fonctionnelle.

8 faits courts à connaître

  1. Nix précède les conteneurs comme outil ops courant. Les idées du gestionnaire de paquets Nix remontent à des recherches du début des années 2000 sur le déploiement purement fonctionnel.
  2. /nix/store est conçu de manière similaire à l’adressage par contenu. Les chemins du store incluent des hachages pour permettre d’installer plusieurs versions et variantes côte à côte sans collision de fichiers.
  3. NixOS rend les mises à jour système transactionnelles. Les nouvelles configurations construisent une nouvelle « fermeture système » et des entrées de démarrage sont générées pour chaque génération.
  4. Le rollback est intégré au menu de démarrage. Vous pouvez booter la dernière version connue bonne même quand le réseau est mort et que SSH est un luxe.
  5. Les configurations sont du code, pas un tas de fichiers difficiles à diff. C’est pourquoi NixOS est impitoyablement efficace pour la cohérence d’une flotte.
  6. Nixpkgs est l’une des collections de paquets les plus vastes. Pas parce que c’est à la mode, mais parce que l’isolation de construction de Nix évolue de façon maintenable.
  7. « OS déclaratif » n’a pas été inventé par NixOS, mais NixOS l’a opérationnalisé. On retrouve des échos dans cfengine/puppet/chef, mais NixOS rend l’OS lui‑même déclaratif.
  8. Les générations coûtent peu comparé aux images traditionnelles. Vous conservez plusieurs états système sans cloner des disques complets, car le store déduplique le contenu.

Une citation (idée paraphrasée) : le travail sur la fiabilité de Gene Kim pousse sans cesse le même principe : rendre les changements petits, réversibles et routiniers. NixOS intègre cela dans le flux de travail système.

Décisions importantes : disques, démarrage, secrets, mises à jour

Choisissez votre système de fichiers comme si vous étiez de permanence

Pour des serveurs : vous voulez une récupération prévisible, des outils solides et un modèle de défaillance que vous comprenez. Choisissez selon le confort de votre équipe, pas pour gagner des points sur Internet.

  • ext4 : ennuyeux, stable, suffisamment rapide. Si vous n’avez pas besoin de snapshots au niveau du système de fichiers, ext4 est le choix « rentrer à la maison en sécurité ».
  • Btrfs : snapshots et sous‑volumes utiles ; send/receive pratique ; peut être fantastique. Aussi : il faut respecter ses arêtes opérationnelles.
  • ZFS : meilleur de sa catégorie pour checksums, snapshots et workflows de réplication. Aussi : vous vous engagez à une discipline opérationnelle ZFS (mémoire, comportement de l’ARC, santé des pools).

Ce guide utilise racine ZFS comme voie « contrôle maximal », avec des notes pour ext4/Btrfs quand cela change des décisions.

UEFI uniquement, GPT uniquement, et pas de partitionnement « malin »

Utilisez UEFI + GPT. Créez une partition EFI System. Restez simple. Vous pourrez être malin plus tard, quand vous aurez du monitoring, des sauvegardes et un labo pour tester.

Flakes : oui, sauf raison stricte de ne pas les utiliser

Utilisez flakes pour les nouvelles installations. Ils ne sont pas parfaits, mais ils standardisent le verrouillage et la composition. L’alternative, ce sont les « channels », ce qui revient à « faites‑moi confiance, c’est la dernière version ».

Secrets : décidez maintenant, pas après

Si vous déployez autre chose qu’un laptop personnel, vous aurez des secrets : clés hôtes SSH, certificats TLS, tokens, PSK Wi‑Fi, clés API. Décidez de votre stratégie de secrets avant l’envoi :

  • Pour les petites installations : fichiers chiffrés dans git + outils basés sur age (patron courant), déchiffrés au moment du déploiement.
  • Pour les environnements d’entreprise : intégrez un backend de secrets et connectez votre configuration NixOS pour récupérer au runtime.

Ne stockez pas de secrets dans des chemins du Nix store lisibles par tous. Le store est conçu pour la reproductibilité, pas pour la confidentialité.

Mises à jour : choisissez un rythme et consignez‑le

NixOS facilite les mises à jour. Ce n’est pas la même chose que « sûr ». Vous voulez un rythme :

  • Verrouillez les inputs (flake.lock) et mettez‑les à jour de façon intentionnelle.
  • Testez les builds (même sur l’hôte) avant de basculer.
  • Gardez toujours une voie de rollback (entrées de boot + générations précédentes).

Blague #1 : La dérive de configuration, c’est comme l’entropie : on ne peut pas la contester, seulement budgéter la mort thermique de votre /etc.

Checklists / plan étape par étape

Checklist pré‑vol (avant de booter l’ISO)

  • Décidez du système de fichiers : ext4 vs Btrfs vs ZFS. Si vous choisissez ZFS, décidez du nom du pool et de la disposition des datasets.
  • Décidez du démarrage : UEFI + systemd‑boot convient pour la plupart. Si vous avez besoin de Secure Boot, planifiez‑le maintenant.
  • Décidez de l’identité : nom d’hôte, IP statique ou DHCP, modèle d’accès SSH, utilisateurs admin, et où vous stockerez la config (git).
  • Décidez du canal de mise à jour : branche de release stable vs tracking. Pour les serveurs, préférez stable + mises à jour planifiées.
  • Décidez des secrets : repo chiffré, gestionnaire externe, ou approvisionnement manuel (dernier recours).
  • Décidez de la gestion distante : déploierez‑vous localement ou via SSH depuis une machine de build ?

Checklist d’installation (haut niveau)

  1. Booter l’ISO NixOS, confirmer le réseau.
  2. Partitionner les disques (GPT + EFI + partition ZFS).
  3. Créer le pool ZFS + datasets (ou équivalents ext4/Btrfs).
  4. Monter les systèmes de fichiers sur /mnt.
  5. Générer la configuration initiale NixOS.
  6. Convertir vers une structure basée sur flake.
  7. Configurer le bootloader, le réseau, les utilisateurs, sshd, l’heure, la locale.
  8. Installer NixOS, définir le mot de passe root (ou désactiver et s’appuyer sur les clés SSH).
  9. Redémarrer, valider les entrées de boot, l’import ZFS, et SSH.
  10. Committer la config dans git. Traitez‑la comme de l’infrastructure.

Checklist post‑installation (la première heure)

  • Confirmer que des entrées de rollback existent dans le menu de boot.
  • Confirmer que vous pouvez rebuild et switcher sans erreurs.
  • Mettre en place le monitoring de base (disque, mémoire, charge, santé ZFS).
  • Mettre en place les sauvegardes (snapshots + réplication, ou sauvegardes au niveau fichier).
  • Décider comment les mises à jour sont déclenchées (manuel, timer, CI).

Tâches pratiques : commandes, sortie attendue, et décisions

Voici les tâches que j’exécute réellement. Chacune inclut ce que la sortie signifie et ce que vous décidez ensuite. Supposez que vous êtes dans l’environnement d’installation NixOS sauf indication contraire.

Task 1: Confirmer que vous avez booté en mode UEFI

cr0x@server:~$ ls /sys/firmware/efi
efivars  fw_platform_size

Ce que cela signifie : Si ce répertoire existe, vous êtes en mode UEFI. S’il n’existe pas, vous avez booté en BIOS legacy.

Décision : Si UEFI est absent, redémarrez et corrigez les paramètres du firmware. N’installez pas en mode legacy sauf contrainte très précise.

Task 2: Identifier les disques et leur topologie

cr0x@server:~$ lsblk -o NAME,SIZE,TYPE,MODEL,SERIAL,FSTYPE,MOUNTPOINTS
NAME        SIZE TYPE MODEL           SERIAL    FSTYPE MOUNTPOINTS
nvme0n1   953.9G disk Samsung SSD     S6ABC123
├─nvme0n1p1   1G part                 vfat   /mnt/boot
└─nvme0n1p2 952.9G part                 zfs_member
sda        3.6T disk ST4000NM         Z4XYZ789

Ce que cela signifie : Vous voyez les noms de périphériques, tailles, et si un système de fichiers existe déjà. Aussi : vérifiez que vous n’êtes pas sur le point d’effacer le mauvais disque.

Décision : Choisissez la cible d’installation. Si c’est une configuration de boot miroir, vous voulez deux disques. Si c’est une VM, un seul suffit.

Task 3: Vérifier sommairement les tables de partition existantes (et effacer si approprié)

cr0x@server:~$ sudo sgdisk -p /dev/nvme0n1
Disk /dev/nvme0n1: 2000409264 sectors, 953.9 GiB
Sector size (logical/physical): 512/512 bytes
Disk identifier (GUID): 4A5F0B45-7E62-4C6D-A3D2-8D5F7E0C1A1B
Partition table holds up to 128 entries
Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048         2099199   1024.0 MiB  EF00  EFI System
   2         2099200      2000408575   952.9 GiB   BF01  ZFS

Ce que cela signifie : GPT est présent. Les codes de partition EF00 (EFI) et BF01 (ZFS) sont ce que nous voulons.

Décision : Si vous voyez un ancien layout désordonné et que vous réinstallez, effacez l’étiquette du disque proprement (ne réutilisez pas à moitié des partitions sauf si vous écrivez aussi un runbook pour vous‑même).

Task 4: Partitionner un disque (exemple mono‑disque)

cr0x@server:~$ sudo sgdisk --zap-all /dev/nvme0n1
Creating new GPT entries in memory.
GPT data structures destroyed! You may now partition the disk using fdisk or other utilities.

Ce que cela signifie : Les anciennes données GPT/MBR sont supprimées.

Décision : N’exécutez ceci que si vous êtes absolument sûr d’avoir sélectionné le bon disque.

cr0x@server:~$ sudo sgdisk -n1:1M:+1G -t1:EF00 -c1:"EFI System" /dev/nvme0n1
The operation has completed successfully.
cr0x@server:~$ sudo sgdisk -n2:0:0 -t2:BF01 -c2:"ZFS" /dev/nvme0n1
The operation has completed successfully.

Ce que cela signifie : Vous avez créé un ESP de 1 GiB et une partition ZFS occupant le reste.

Décision : Si vous prévoyez l’hibernation ou des besoins spéciaux de swap, planifiez cette partition maintenant. Sinon, restez simple et faites le swap via fichier plus tard (ou pas, selon la charge).

Task 5: Formater la partition EFI System

cr0x@server:~$ sudo mkfs.fat -F 32 -n EFI /dev/nvme0n1p1
mkfs.fat 4.2 (2021-01-31)

Ce que cela signifie : L’ESP est formatée en FAT32 et étiquetée EFI.

Décision : Si vous faites du boot miroir, vous formaterez une ESP sur chaque disque et les monterez toutes les deux (ou utiliserez une approche de synchronisation). Mono‑disque est plus simple.

Task 6: Créer le pool ZFS (racine sur ZFS)

cr0x@server:~$ sudo zpool create -f -o ashift=12 \
  -O atime=off -O compression=zstd -O xattr=sa -O normalization=formD \
  -O mountpoint=none -O acltype=posixacl \
  rpool /dev/nvme0n1p2
cr0x@server:~$ sudo zpool status
  pool: rpool
 state: ONLINE
config:

        NAME           STATE     READ WRITE CKSUM
        rpool          ONLINE       0     0     0
          nvme0n1p2    ONLINE       0     0     0

errors: No known data errors

Ce que cela signifie : Le pool est créé et sain.

Décision : Si vous voyez autre chose que ONLINE avec zéro erreur, arrêtez. Corrigez le câblage, la santé des disques ou les chemins de périphériques. Ne « continuez pas en espérant ».

Task 7: Créer des datasets (root séparé, store nix, état persistant)

cr0x@server:~$ sudo zfs create -o mountpoint=none rpool/local
cr0x@server:~$ sudo zfs create -o mountpoint=none rpool/safe
cr0x@server:~$ sudo zfs create -o mountpoint=legacy rpool/local/root
cr0x@server:~$ sudo zfs create -o mountpoint=legacy -o compression=zstd rpool/local/nix
cr0x@server:~$ sudo zfs create -o mountpoint=legacy rpool/safe/persist
cr0x@server:~$ sudo zfs list -o name,mountpoint,compression
NAME               MOUNTPOINT  COMPRESSION
rpool              none        zstd
rpool/local        none        zstd
rpool/local/nix    legacy      zstd
rpool/local/root   legacy      zstd
rpool/safe         none        zstd
rpool/safe/persist legacy      zstd

Ce que cela signifie : Vous avez séparé les datasets entre « peut être reconstruit » (local) et « doit survivre à une réimage » (safe/persist).

Décision : Placez /nix sur son propre dataset. Il grossit. Il churn. Vous voulez le snapshotter différemment de l’état persistant.

Task 8: Monter les systèmes de fichiers pour l’installation

cr0x@server:~$ sudo mount -t zfs rpool/local/root /mnt
cr0x@server:~$ sudo mkdir -p /mnt/nix /mnt/persist /mnt/boot
cr0x@server:~$ sudo mount -t zfs rpool/local/nix /mnt/nix
cr0x@server:~$ sudo mount -t zfs rpool/safe/persist /mnt/persist
cr0x@server:~$ sudo mount /dev/nvme0n1p1 /mnt/boot
cr0x@server:~$ mount | head -n 5
rpool/local/root on /mnt type zfs (rw,xattr,posixacl)
rpool/local/nix on /mnt/nix type zfs (rw,xattr,posixacl)
rpool/safe/persist on /mnt/persist type zfs (rw,xattr,posixacl)
/dev/nvme0n1p1 on /mnt/boot type vfat (rw,relatime,fmask=0022,dmask=0022)

Ce que cela signifie : La racine cible est sur /mnt, avec des montages séparés pour /nix, /persist et /boot.

Décision : Si /mnt/boot n’est pas monté, l’installation de systemd‑boot produira silencieusement un système qui ne bootera pas. Corrigez‑le maintenant.

Task 9: Générer la configuration initiale

cr0x@server:~$ sudo nixos-generate-config --root /mnt
writing /mnt/etc/nixos/hardware-configuration.nix...
writing /mnt/etc/nixos/configuration.nix...

Ce que cela signifie : NixOS a détecté le matériel et écrit une configuration de base.

Décision : Traitez hardware-configuration.nix comme majoritairement généré par la machine et stable ; gardez l’intention humaine dans des modules séparés autant que possible.

Task 10: Valider que les montages ZFS sont reflétés dans la config matérielle

cr0x@server:~$ sudo sed -n '1,200p' /mnt/etc/nixos/hardware-configuration.nix
{ config, lib, pkgs, modulesPath, ... }:

{
  imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];

  boot.supportedFilesystems = [ "zfs" ];

  fileSystems."/" = {
    device = "rpool/local/root";
    fsType = "zfs";
  };

  fileSystems."/nix" = {
    device = "rpool/local/nix";
    fsType = "zfs";
  };

  fileSystems."/persist" = {
    device = "rpool/safe/persist";
    fsType = "zfs";
  };

  fileSystems."/boot" = {
    device = "/dev/disk/by-uuid/ABCD-EF01";
    fsType = "vfat";
  };
}

Ce que cela signifie : L’installateur a encodé correctement les montages. L’ESP utilise l’UUID, ZFS utilise les noms de datasets.

Décision : Gardez les noms de dataset ZFS stables. Ne vous fiez pas à /dev/nvme0n1p2 dans les configs à long terme à moins d’aimer les surprises post‑reboot.

Task 11: Pré‑valider le build avant l’installation (attraper les erreurs évidentes)

cr0x@server:~$ sudo nixos-install --root /mnt --no-root-passwd --dry-run
building the system configuration...
warning: Git tree '/mnt/etc/nixos' is dirty
dry-run succeeded

Ce que cela signifie : La config s’évalue et se construit. « dirty » est acceptable pour l’instant.

Décision : Si le build échoue, corrigez‑le maintenant pendant que vous êtes encore dans l’environnement ISO. N’« installez pas et n’espérez pas ».

Task 12: Installer et configurer le système

cr0x@server:~$ sudo nixos-install --root /mnt --no-root-passwd
building the system configuration...
installing the boot loader...
setting up /etc...
updating GRUB 2 menu...
installation finished!

Ce que cela signifie : NixOS s’est installé et a écrit des entrées de boot. (Selon la config, vous verrez peut‑être systemd‑boot au lieu des lignes GRUB.)

Décision : Si l’installation du bootloader échoue, ne redémarrez pas. Inspectez /mnt/boot et vos paramètres du bootloader d’abord.

Task 13: Avant le reboot, vérifier que les entrées de boot existent (chemin UEFI/systemd‑boot)

cr0x@server:~$ sudo ls -la /mnt/boot/loader/entries | head
total 16
drwxr-xr-x 2 root root 4096 Jan  1 00:10 .
drwxr-xr-x 3 root root 4096 Jan  1 00:10 ..
-rwxr-xr-x 1 root root  420 Jan  1 00:10 nixos-generation-1.conf

Ce que cela signifie : Des entrées systemd‑boot existent sur l’ESP.

Décision : Si le répertoire est vide, votre ESP n’a pas été montée pendant l’installation. Montez‑la et réinstallez le bootloader depuis un chroot (ou relancez l’installation attentivement).

Task 14: Après reboot, confirmer que vous exécutez la génération voulue

cr0x@server:~$ sudo nix-env -p /nix/var/nix/profiles/system --list-generations
   1   2026-02-05 00:12:33   (current)

Ce que cela signifie : Vous avez au moins une génération et elle est courante.

Décision : Si des générations manquent ou que le changement échoue plus tard, vous avez probablement un bootloader cassé ou un problème de montage de système de fichiers.

Task 15: Confirmer que le pool ZFS s’importe proprement au démarrage

cr0x@server:~$ sudo zpool status -x
all pools are healthy

Ce que cela signifie : Aucun problème connu sur les pools.

Décision : Si cela rapporte des pools dégradés, des périphériques défaillants, ou des erreurs de checksum, considérez‑le comme urgent. ZFS dit la vérité ; les gens essaient quand même de négocier.

Task 16: Valider rapidement les services et les performances de démarrage

cr0x@server:~$ systemd-analyze time
Startup finished in 3.221s (kernel) + 6.483s (userspace) = 9.704s
graphical.target reached after 6.439s in userspace

Ce que cela signifie : Un rapide aperçu du temps de démarrage séparé entre noyau et espace utilisateur.

Décision : Si l’espace utilisateur est énorme, inspectez quelles unités bloquent. Si le noyau est long, c’est souvent du firmware, l’initialisation du stockage ou la complexité de l’initrd.

cr0x@server:~$ systemd-analyze blame | head
3.812s zfs-import-cache.service
2.104s network-online.target
1.442s nix-daemon.service
1.015s systemd-journald.service

Ce que cela signifie : Quelles unités ont pris le plus de temps.

Décision : N’« optimisez » pas avant de savoir si cela a de l’importance. Si network-online.target est lent, vérifiez le DHCP ou retirez des dépendances inutiles.

Task 17: Confirmer que SSH est joignable et que les clés sont en place

cr0x@server:~$ sudo systemctl status sshd --no-pager
● sshd.service - OpenSSH Daemon
     Loaded: loaded (/etc/systemd/system/sshd.service; enabled; preset: enabled)
     Active: active (running) since Thu 2026-02-05 00:20:14 UTC; 1min ago
       Docs: man:sshd(8)
             man:sshd_config(5)

Ce que cela signifie : sshd est activé et en cours d’exécution.

Décision : S’il n’est pas actif, ne poursuivez pas avec un plan d’administration uniquement distant. Corrigez le réseau/sshd maintenant tant que vous avez encore un accès console.

Task 18: Vérifier la taille de la closure et la croissance du store (planification de capacité)

cr0x@server:~$ nix path-info -Sh /run/current-system
/nix/store/2h3...-nixos-system-server-25.11.20260201  1.8G

Ce que cela signifie : Taille approximative de la closure du système courant.

Décision : Si vous êtes à court de disque, planifiez la collecte des ordures et gardez /nix sur son propre dataset ou partition.

Une structure de configuration NixOS 25.11 sensée

Gardez votre configuration lisible. Le vous du futur sera fatigué et légèrement agacé. N’aggravez pas les choses.

Structure minimale de flake qui évolue au‑delà d’un hôte

Structure recommandée :

  • flake.nix et flake.lock à la racine du repo
  • hosts/server/configuration.nix pour l’intention hôte
  • modules/ pour des composants réutilisables (ssh, monitoring, zfs, users)
  • secrets/ pour le matériel chiffré (non stocké en clair dans le Nix store)

Exemple de flake (réduit à l’essentiel) :

cr0x@server:~$ cat /etc/nixos/flake.nix
{
  description = "NixOS fleet";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
  };

  outputs = { self, nixpkgs, ... }:
  let
    system = "x86_64-linux";
  in {
    nixosConfigurations.server = nixpkgs.lib.nixosSystem {
      inherit system;
      modules = [
        ./hosts/server/configuration.nix
      ];
    };
  };
}

Puis la configuration de l’hôte importe des modules et fixe l’intention :

cr0x@server:~$ sed -n '1,220p' /etc/nixos/hosts/server/configuration.nix
{ config, pkgs, ... }:

{
  imports = [
    ../../hardware-configuration.nix
    ../../modules/base.nix
    ../../modules/ssh.nix
    ../../modules/zfs.nix
  ];

  networking.hostName = "server";
  time.timeZone = "UTC";

  users.users.cr0x = {
    isNormalUser = true;
    extraGroups = [ "wheel" ];
    openssh.authorizedKeys.keys = [
      "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... cr0x@laptop"
    ];
  };

  services.openssh.enable = true;
  services.openssh.settings = {
    PasswordAuthentication = false;
    PermitRootLogin = "no";
  };

  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  system.stateVersion = "25.11";
}

À éviter : un configuration.nix monolithique et géant qui contient tout, de nginx aux polices en passant par des flags noyau expérimentaux. Scindez le tout. Vous déboguerez plus vite.

Persistance : décidez ce qui survit aux rebuilds

Si vous avez créé /persist, utilisez‑le. Stockez l’état dont vous tenez à cœur : clés hôtes SSH, stratégie de machine‑id, données de service, logs (peut‑être), et état applicatif (certainement). Le câblage exact varie selon les préférences, mais le principe est stable : séparez « reconstruisible » de « doit survivre ».

Une approche pratique est de bind‑monter des répertoires choisis sur /persist (ou d’utiliser des patterns de type impermanence). L’avantage est la clarté lors d’un incident : vous pouvez effacer le dataset root et garder l’état intact.

Paramètres Nix qui évitent les douleurs auto‑infligées

  • Activez le démon (par défaut) et utilisez des builds sandboxés quand c’est possible.
  • Préférez des inputs nixpkgs verrouillés et révisez les mises à jour.
  • Planifiez la garbage collection et la rétention des générations explicitement.
cr0x@server:~$ sudo nixos-option nix.gc.automatic
nix.gc.automatic = false

Ce que cela signifie : Le GC n’est pas activé par défaut dans de nombreuses configurations.

Décision : Pour des serveurs avec de petits disques, activez le GC avec une politique de rétention qui ne supprime pas votre dernière génération connue bonne juste avant que vous en ayez besoin.

Mises à jour, rollbacks et contrôle de dérive en conditions réelles

NixOS vous fournit beaucoup de filets de sécurité. Vous devez quand même conduire comme si vous transportiez du verre.

Comment « zéro dérive de configuration » fonctionne réellement

La dérive survient quand la réalité change sans que la source de vérité ne change. NixOS combat cela de deux façons :

  • Le rebuild écrase les fichiers gérés par la configuration. Cela bloque les modifications manuelles dans /etc de rester.
  • Le système est un artefact de build. Vous ne « touchez pas à l’état en direct », vous basculez vers une nouvelle génération.

Mais la dérive peut toujours exister dans les répertoires d’état (bases de données, caches, logs), dans des modifications manuelles de pare‑feu, dans des chargements de modules noyau « temporaires », et dans des changements hors‑bande comme les paramètres firmware. Votre travail est de minimiser les chemins hors‑bande et de documenter ceux qui restent.

Le modèle de mise à jour sûr

C’est le modèle que je veux en production :

  1. Mettre à jour les inputs (flake.lock) de façon intentionnelle.
  2. Construire le système.
  3. Basculez dessus.
  4. Validez les services critiques.
  5. Gardez le rollback disponible et ne faites pas de GC immédiatement.
cr0x@server:~$ sudo nixos-rebuild build --flake /etc/nixos#server
building the system configuration...
/nix/store/8m7...-nixos-system-server-25.11.20260205

Ce que cela signifie : Vous avez construit une nouvelle closure système sans l’activer.

Décision : Si le build échoue, vous n’avez pas touché le système en cours d’exécution. Corrigez avant de switcher.

cr0x@server:~$ sudo nixos-rebuild switch --flake /etc/nixos#server
building the system configuration...
activating the configuration...
setting up /etc...
reloading user units for cr0x...

Ce que cela signifie : La nouvelle génération est active. Les services peuvent avoir redémarré.

Décision : Validez les choses spécifiques qui comptent pour votre activité (ports, santé des APIs, montages de stockage). Ne faites pas confiance uniquement au message « switch succeeded ».

Rollback que vous pouvez faire sous pression

Il y a deux voies de rollback :

  • Au démarrage : choisissez une génération plus ancienne dans le menu du bootloader.
  • Depuis un système en cours : basculez vers une génération plus ancienne en place.
cr0x@server:~$ sudo nix-env -p /nix/var/nix/profiles/system --list-generations
   1   2026-02-05 00:12:33
   2   2026-02-05 01:05:10   (current)

Ce que cela signifie : Vous avez au moins deux générations pour choisir.

Décision : Si vous ne gardez qu’une génération, vous avez transformé NixOS en un gestionnaire de paquets sophistiqué. Gardez en plusieurs.

cr0x@server:~$ sudo /nix/var/nix/profiles/system-1-link/bin/switch-to-configuration switch
setting up /etc...
reloading user units for cr0x...

Ce que cela signifie : Vous êtes revenu à la génération 1.

Décision : Si le système est dans un mauvais état, préférez le rollback au démarrage. Il réinitialise plus d’assomptions.

Garbage collection sans se tirer une balle dans le pied

La pression d’espace est réelle, surtout sur des petits disques root. Mais un GC agressif est la façon dont vous supprimez votre seul noyau fonctionnel juste avant un reboot.

cr0x@server:~$ sudo nix-collect-garbage -d
finding garbage collector roots...
deleting old generations of profile /nix/var/nix/profiles/system
deleting unused links...
0 store paths deleted, 0.00 MiB freed

Ce que cela signifie : Dans cet exemple, rien n’a été libéré (probablement parce que les générations sont épinglées).

Décision : Avant d’activer un GC automatisé, définissez une politique sur le nombre de générations conservées et la durée. Le disque est bon marché ; le downtime ne l’est pas.

Blague #2 : « Activons un garbage collection quotidien » est la manière dont vous découvrez que votre plan de rollback était, en fait, une danse interprétative.

Notes d’ingénierie stockage : ZFS, Btrfs, ext4, et réalité

Le stockage est l’endroit où « ça marchait en staging » vient mourir. La bonne nouvelle : NixOS rend la configuration de stockage reproductible, ce qui signifie que vous pouvez réellement en raisonner.

Racine ZFS : ce que vous gagnez, ce que vous payez

Gains : checksums de bout en bout, snapshots, propriétés par dataset, workflows de réplication, et une observabilité excellente (scrubs, compteurs d’erreurs, signaux de défaillance clairs).

Coûts : Vous devez planifier l’usage mémoire, les scrubs, le monitoring, et le comportement d’import. ZFS est stable, mais aussi honnête : il vous dira que votre disque meurt avant votre contrôleur RAID.

Disposition des datasets : ne la compliquez pas, rendez‑la utile

La disposition de datasets vue plus haut (rpool/local/root, rpool/local/nix, rpool/safe/persist) est pensée pour le contrôle opérationnel :

  • Cadences de snapshot différentes : fréquente pour persist, moins fréquente pour nix, peut‑être aucune pour root.
  • Règles de réplication différentes : persist se réplique hors‑hôte ; nix est reconstruisible et optionnel.
  • Rayon d’impact clair : vous pouvez rollbacker persist sans rollbacker l’OS, et inversement.

ARC et mémoire : quoi surveiller

ZFS utilisera la mémoire pour le cache ARC. C’est généralement bon. Ça peut aussi être gênant sur des VM à faible RAM ou des charges mixtes où le page cache et l’ARC se disputent l’espace.

cr0x@server:~$ cat /proc/meminfo | head
MemTotal:       16342132 kB
MemFree:         2145320 kB
MemAvailable:    8021444 kB
Buffers:          212344 kB
Cached:          4219072 kB

Ce que cela signifie : « MemAvailable » est votre vraie marge. « Cached » inclut les caches de système de fichiers.

Décision : Si vous êtes juste en RAM et que vous voyez de la pression OOM sous charge, songez à contraindre l’ARC. Faites‑le intentionnellement, avec mesures, pas par superstition.

Scrubs : programmez‑les comme des sauvegardes—parce que c’en est une forme

Les scrubs lisent toutes les données et vérifient les checksums. Ils ne remplacent pas les sauvegardes, mais ils transforment la corruption silencieuse en alertes bruyantes.

cr0x@server:~$ sudo zpool scrub rpool
cr0x@server:~$ sudo zpool status
  pool: rpool
 state: ONLINE
  scan: scrub in progress since Thu Feb  5 02:11:33 2026
        32.1G scanned at 1.20G/s, 1.02G issued at 39.1M/s, 120G total
        0B repaired, 0.85% done, 0:01:39 to go

Ce que cela signifie : Le scrub est en cours ; progrès et débit sont visibles.

Décision : Si les scrubs révèlent des octets réparés ou des erreurs de checksum, prenez‑le comme signal pour enquêter sur les disques et le câblage. Ne vous contentez pas d’effacer l’erreur et d’avancer.

Différences Ext4/Btrfs (si vous ne faites pas ZFS)

Si vous choisissez ext4, votre « contrôle maximal » se déplace vers la couche supérieure : vous compterez plus sur les sauvegardes, des snapshots LVM (peut‑être), et des mises à jour prudentes.

Si vous choisissez Btrfs, vous obtenez des snapshots et send/receive. La discipline opérationnelle est différente : surveillez le comportement d’espace libre, les opérations de balance, et choisissez une disposition de sous‑volumes sensée.

La partie NixOS reste cohérente : l’état de l’OS est déclaratif, les rollbacks existent, et la dérive est minimisée. Votre plan de stockage complète le reste de l’histoire de fiabilité.

Playbook de diagnostic rapide

Voici l’ordre de triage « c’est lent / ça ne boot pas / ça flappe » qui sauve du temps. Le but n’est pas l’exhaustivité ; c’est la rapidité et le signal.

Premier point : confirmez ce qui a changé

  • Avez‑vous switché de génération ? Les inputs ont‑ils changé ?
  • Le système en cours d’exécution est‑il bien celui que vous pensez ?
cr0x@server:~$ readlink /run/current-system
/nix/store/8m7...-nixos-system-server-25.11.20260205

Décision : Si le chemin du store n’est pas celui attendu, arrêtez de deviner. Alignez l’équipe sur « ce qui tourne ».

Deuxième point : est‑ce le boot, le stockage, le réseau ou le service ?

Choisissez la catégorie vite. La plupart des pannes sont ennuyeuses.

Problèmes de boot et d’initrd

cr0x@server:~$ journalctl -b -p err --no-pager | tail -n 20
Feb 05 02:20:31 server kernel: zfs: module license 'CDDL' taints kernel.
Feb 05 02:20:33 server systemd[1]: Failed to mount /persist.
Feb 05 02:20:33 server systemd[1]: Dependency failed for Local File Systems.

Décision : Si des montages échouent, vous avez un problème d’ordre de montage/dataset. Ne cherchez pas les logs applicatifs tout de suite.

Santé du stockage

cr0x@server:~$ sudo zpool status
  pool: rpool
 state: DEGRADED
status: One or more devices could not be opened.
action: Attach the missing device and online it using 'zpool online'.
config:

        NAME           STATE     READ WRITE CKSUM
        rpool          DEGRADED     0     0     0
          nvme0n1p2    ONLINE       0     0     0
          nvme1n1p2    UNAVAIL      0     0     0  cannot open

Décision : Si ZFS est dégradé, votre priorité est la disponibilité des périphériques et la sécurité des données. Le débogage de performance peut attendre.

Atteignabilité réseau

cr0x@server:~$ ip -br a
lo               UNKNOWN        127.0.0.1/8 ::1/128
enp1s0           UP             10.20.30.40/24 fe80::a00:27ff:fe4e:66a1/64

Décision : Si l’interface n’est pas UP ou n’a pas d’adresse, corrigez la config réseau avant d’accuser DNS, TLS ou les applications.

État des services

cr0x@server:~$ systemctl --failed --no-pager
  UNIT                     LOAD   ACTIVE SUB    DESCRIPTION
● nginx.service             loaded failed failed Nginx Web Server

1 loaded units listed.

Décision : Les unités en échec indiquent où concentrer l’effort. Lisez les logs unit ; ne redémarrez pas aveuglément.

Troisième point : trouver le goulot (CPU, IO, mémoire, ou contention de verrou)

cr0x@server:~$ top -b -n 1 | head -n 12
top - 02:31:10 up 12 min,  1 user,  load average: 7.12, 6.80, 4.21
Tasks: 168 total,   2 running, 166 sleeping,   0 stopped,   0 zombie
%Cpu(s): 12.4 us,  3.1 sy,  0.0 ni, 82.9 id,  1.4 wa,  0.0 hi,  0.2 si,  0.0 st
MiB Mem :  15959.1 total,   2210.5 free,   5300.8 used,   8447.8 buff/cache
MiB Swap:      0.0 total,      0.0 free,      0.0 used.   8658.3 avail Mem

Décision : Si l’attente IO est élevée, regardez du côté du disque. Si la mémoire est faible et que le swap est absent, vous risquez un OOM. Si le CPU est saturé, profilez le service ou scalez.

Erreurs courantes : symptôme → cause racine → correction

1) Le système ne boot pas après une installation « réussie »

Symptôme : Le boot retombe sur le menu firmware ou « aucun périphérique bootable ».

Cause racine : L’ESP n’était pas montée sur /mnt/boot pendant l’installation, donc les entrées du bootloader ont été écrites au mauvais endroit (ou pas du tout).

Correction : Bootez l’ISO, montez la racine sur /mnt, montez l’ESP sur /mnt/boot, puis réinstallez le bootloader via nixos-enter ou relancez soigneusement les étapes d’installation.

2) Le pool ZFS ne s’importe pas au démarrage

Symptôme : Shell d’urgence ; erreurs sur le montage de la racine ou pool manquant.

Cause racine : Absence de boot.supportedFilesystems = [ "zfs" ];, mauvais noms de dataset, ou initrd sans les composants ZFS.

Correction : Confirmez que la config matérielle inclut le support ZFS ; rebuild ; si c’est déjà cassé, bootez une ancienne génération ou utilisez l’ISO pour importer le pool et corriger la config.

3) « Ça marchait, puis après reboot SSH est mort »

Symptôme : Impossible de se connecter en SSH après un rebuild ; la console montre que le système est up.

Cause racine : Dérive de configuration réseau (DHCP vs statique), règles de pare‑feu changées de façon déclarative, ou paramètres sshd durcis sans que les clés soient en place.

Correction : Sur la console, vérifiez ip -br a, systemctl status sshd et journalctl -u sshd. Revenez à une génération antérieure si nécessaire, puis corrigez la config avec les clés autorisées et un déploiement progressif.

4) Le disque se remplit de façon inattendue sur NixOS

Symptôme : /nix grossit jusqu’à ce que le système commence à échouer de façons étranges.

Cause racine : Anciennes générations et chemins du store qui s’accumulent ; GC non configuré ; artefacts de build conservés.

Correction : Définissez une politique de GC et de rétention des générations ; déplacez /nix sur son propre dataset/partition ; surveillez l’espace libre.

5) « nixos-rebuild switch » prend une éternité

Symptôme : Les rebuilds sont lents ; CPU et disque en churn.

Cause racine : Builds fréquents à partir de sources, absence d’accès au cache binaire, ou une configuration surdimensionnée tirant trop de dépendances.

Correction : Confirmez que vous utilisez des caches binaires, préférez des paquets stables, et évitez de compiler le monde sur des nœuds de production.

6) Secrets fuyés dans le Nix store

Symptôme : Un token apparaît dans /nix/store ou peut être lu par des utilisateurs non prévus.

Cause racine : Vous avez placé des secrets directement dans des expressions Nix ou créé des fichiers au moment du build qui atterrissent dans le store.

Correction : Déplacez les secrets vers l’approvisionnement au runtime (tmpfiles, gestionnaire externe, fichiers chiffrés déchiffrés à l’activation) et faites tourner les identifiants compromis.

Trois mini‑histoires d’entreprise (douleur, humilité, résultats)

Incident causé par une fausse hypothèse : « L’interface s’appellera eth0 »

Dans une entreprise de taille moyenne, une équipe a migré une petite flotte d’un gestionnaire de configuration traditionnel vers NixOS. Ils ont fait la bonne chose : tout était déclaratif, les builds étaient épinglés, les rollbacks fonctionnaient. Propre.

Puis ils ont acheté du nouveau matériel. La NIC a changé. Les noms d’interface prévisibles ont bien fait leur travail, et l’interface est devenue quelque chose comme enp129s0f0, pas eth0. Leur config NixOS contenait un bloc réseau statique faisant référence à l’ancien nom. Sur le banc, quelqu’un l’a testé sur un hôte unique et l’a corrigé manuellement « juste pour le mettre en ligne ». Cette correction manuelle n’a jamais été poussée dans git.

Pendant la fenêtre de déploiement, la moitié des serveurs sont montés sans réseau. Le monitoring a montré une panne partielle. L’ingénieur on‑call ne pouvait pas SSHer, car c’était l’échec entier. L’accès console existait, mais pas rapidement—ces sites étaient distants.

La cause racine n’était pas NixOS ; c’était l’hypothèse que le nom d’interface serait stable selon le matériel. Le vrai péché opérationnel était la correction manuelle sur le banc qui a contourné la source de vérité. C’est comme ça que la dérive s’insinue : par l’urgence et la bonne intention.

La correction a été simple et ennuyeuse : apparier les interfaces par adresse MAC dans la configuration et cesser d’écrire des configs dépendant des noms de périphériques. L’action postmortem n’était pas « tester plus ». C’était « pas d’éditions locales sans commit » et « la config réseau doit être indexée sur des identifiants stables ».

Optimisation qui a ralenti les choses : « GC agressif pour garder les disques propres »

Une autre organisation faisait tourner NixOS sur des nœuds de build et quelques services internes. Quelqu’un a remarqué que /nix mangeait de l’espace disque. Juste. Ils ont activé la garbage collection automatique quotidienne avec une politique de suppression agressive. L’espace libre avait l’air parfait.

Des semaines plus tard, une mise à jour de sécurité a exigé le reboot de quelques nœuds. Un nœud n’est pas revenu proprement—un problème matériel non lié a ralenti l’énumération des périphériques et la génération la plus récente avait une course au démarrage impliquant une dépendance réseau. La correction était de booter la génération précédente. Sauf que la closure de la génération précédente avait été collectée.

Ils s’étaient retrouvés avec un boot cassé et sans voie de rollback. L’ironie était assez tranchante pour couper : l’OS conçu pour les rollbacks n’en avait pas parce qu’ils avaient optimisé le stockage comme un disque scratch.

La récupération a impliqué de booter un média de secours, restaurer assez du store depuis des sauvegardes pour booter, puis avancer avec une configuration corrigée. Après, ils ont changé la politique : garder plusieurs générations pendant une fenêtre temporelle, et ne collecter qu’après un test de reboot réussi. L’usage disque a augmenté. Les incidents ont diminué.

Pratique ennuyeuse mais correcte qui a sauvé la mise : « Build, puis switch, puis vérifier »

Une équipe fintech utilisait NixOS pour un ensemble d’APIs internes. Ils n’en faisaient pas de publicité ; ils appréciaient simplement que la production puisse être reconstruite depuis git et que les déploiements soient prévisibles. Leur runbook avait une règle terne : toujours exécuter nixos-rebuild build d’abord, puis switch, et toujours lancer une petite suite de vérification après. Personne ne l’aimait, mais elle a tenu.

Un jour, un ingénieur a mis à jour des inputs épinglés pour récupérer une correction de bibliothèque. Le build a réussi, mais l’activation a échoué parce qu’une unité systemd avait un nom d’option changé en amont. Cet échec s’est produit pendant l’étape switch, pas après un reboot, et il était immédiatement visible sur la console et dans les logs de déploiement.

Parce qu’ils avaient construit d’abord, ils savaient déjà que ce n’était pas un problème de compilation. Parce qu’ils ont basculé dans une fenêtre contrôlée, le rayon d’impact a été limité. Parce qu’ils avaient des étapes de vérification, ils n’ont pas déployé un état à moitié fonctionnel où certains services utilisaient d’anciennes bibliothèques et d’autres des nouvelles.

Le rollback a été rapide : ils sont revenus à la génération précédente, ont corrigé l’unité dans le code, reconstruit, switché, vérifié, et ont avancé. Pas de drame. Personne n’a été célébré. C’est le but.

FAQ

1) NixOS est‑il vraiment « zéro dérive » ?

Pour les parties gérées de façon déclarative, oui : le rebuild impose l’état déclaré. La dérive peut néanmoins exister dans l’état persistant applicatif, les paramètres firmware, et tout ce que vous changez hors‑bande.

2) Dois‑je utiliser les flakes sur des serveurs ?

Oui. Le verrouillage et la reproductibilité sont tout le jeu. Les flakes rendent plus difficile la mise à jour accidentelle du monde parce qu’un channel a bougé.

3) Puis‑je gérer plusieurs machines depuis un seul repo ?

C’est un des meilleurs usages de NixOS. Conservez des modules par hôte et des modules partagés. Évitez le copier‑coller en factorisant proprement les rôles communs.

4) Ai‑je besoin de ZFS pour que NixOS soit reproductible ?

Non. La reproductibilité de NixOS concerne la configuration système et le Nix store. ZFS ajoute des sémantiques de stockage puissantes et des snapshots, ce qui est excellent, mais c’est optionnel.

5) Quel est le choix de bootloader le plus simple et sûr ?

UEFI + systemd‑boot est simple sur de nombreux systèmes. Si vous avez des besoins multi‑boot complexes ou du legacy, GRUB peut convenir. Choisissez, testez les entrées de rollback et documentez.

6) Comment empêcher les secrets d’atterrir dans le Nix store ?

Ne cuisez pas de secrets dans des dérivations Nix. Approvisionnez‑les au runtime (scripts d’activation, tmpfiles) ou récupérez‑les depuis un gestionnaire de secrets. Faites tourner tout secret que vous suspectez d’avoir été mis dans le store.

7) Quelle est la bonne manière de faire des rollbacks en production ?

Conservez plusieurs générations, assurez‑vous que les entrées du bootloader existent, et testez le boot sur une génération plus ancienne après un changement significatif. Le rollback doit être un réflexe, pas une théorie.

8) Comment déboguer un service en échec après un switch de génération ?

Commencez par systemctl --failed, puis journalctl -u service. Si l’échec est dû à la config, revenez immédiatement en arrière et corrigez dans le code.

9) Puis‑je faire des déploiements à distance ?

Oui, et ça vaut le coup une fois que vous faites confiance à votre pipeline. L’important est de garder l’accès console pour les échecs et d’éviter de switcher des générations sans étape de vérification.

10) Quel est le monitoring minimum recommandé ?

Espace disque (notamment /nix), pression mémoire, charge, santé des services, et pour ZFS : état des pools et résultats des scrubs. Si vous ne voyez pas, vous serez appelé plus tard.

Étapes suivantes à faire réellement

Vous avez installé NixOS 25.11. C’est la partie facile. Maintenant, rendez‑le opérationnel.

  1. Commitez votre repo de configuration (y compris flake.lock) et traitez‑le comme la source de vérité.
  2. Rédigez un runbook de rollback avec les commandes exactes et les étapes du menu de boot pour votre matériel.
  3. Définissez la rétention des générations et la politique GC qui préserve la sécurité, pas seulement l’espace libre.
  4. Décidez et implémentez la gestion des secrets avant d’ajouter d’autres services.
  5. Ajoutez du monitoring basique : disque, mémoire, santé des services, et état ZFS si applicable.
  6. Testez une reconstruction complète dans une VM ou un nœud de rechange. Si vous ne pouvez pas reconstruire, vous ne possédez pas le système.

La reproductibilité n’est pas une mode. C’est une habitude soutenue par des outils. NixOS vous donne les outils. L’habitude dépend de vous.

← Précédent
Panique de la clé de récupération BitLocker : retrouver l’accès sans rendre Windows inutilisable
Suivant →
Rétablir un pilote lorsque Windows ne démarre pas : la méthode sûre

Laisser un commentaire