Aller au contenu

NixOS : immuable et reproductible

Mise à jour :

Logo Nixos

NixOS est une distribution Linux basée sur le gestionnaire de paquets fonctionnel Nix. Ce qui la rend unique ? Tout le système se déclare dans des fichiers de configuration : du bootloader aux services en passant par les utilisateurs. On appelle ça l’approche déclarative.

J’utilise NixOS depuis quelques temps maintenant pour mon poste de travail personnel. Ce que j’apprécie particulièrement, c’est la possibilité de reconstruire une machine identique à partir d’un simple fichier de configuration versionné dans Git. Pas de surprise, pas de “ça marche pas sur ma machine”.

Pourquoi NixOS pour le DevSecOps ?

Avant de plonger dans la technique, laissez-moi vous expliquer pourquoi NixOS m’intéresse particulièrement dans un contexte DevSecOps :

  • Reproductibilité totale : deux machines avec la même configuration sont identiques, byte pour byte
  • Rollback instantané : retour à un état précédent en une commande si quelque chose casse
  • Audit facilité : la configuration complète du système est versionnée dans Git
  • Surface d’attaque réduite : seuls les paquets déclarés sont présents, rien de plus

C’est particulièrement utile pour les bastions et les machines d’administration où la sécurité et la reproductibilité sont primordiales.

Installation de Nix

Avant de pouvoir construire des images NixOS, il faut installer le gestionnaire de paquets Nix sur votre poste de développement. Nix propose deux modes d’installation :

  • Single-user : installation dans le répertoire home de l’utilisateur, sans daemon
  • Multi-user : installation système avec daemon, pour les machines partagées

Comme je ne partage pas ma machine et que je suis le seul utilisateur, j’installe en mode single-user. C’est plus simple et ça évite de faire tourner un daemon en permanence :

Terminal window
# Installation single-user (sans daemon)
sh <(curl -L https://nixos.org/nix/install) --no-daemon

L’installateur crée les répertoires nécessaires et ajoute la ligne de chargement du profil dans votre shell. Il suffit d’ouvrir un nouveau terminal pour que Nix soit disponible.

Pour activer les flakes (nous verrons plus tard à quoi ça sert), créez le fichier de configuration :

Terminal window
# Créer le répertoire de configuration
mkdir -p ~/.config/nix
# Activer les fonctionnalités expérimentales
cat > ~/.config/nix/nix.conf << 'EOF'
experimental-features = nix-command flakes
EOF

Vérifiez que tout fonctionne :

Terminal window
# Tester l'installation
nix --version
# Tester les flakes avec un hello world
nix run nixpkgs#hello

Si la commande nix run affiche “Bonjour, le monde !”, c’est bon, vous êtes prêt !

Comment fonctionne Nix ?

Avant d’aller plus loin, prenons le temps de comprendre comment Nix fonctionne sous le capot. C’est important, car une fois ces concepts assimilés, tout le reste devient logique.

Le Nix Store : le cœur du système

Contrairement à apt ou dnf qui installent les paquets dans /usr/bin, /usr/lib, etc., Nix stocke tout dans /nix/store/. Chaque paquet a son propre répertoire avec un nom unique basé sur un hash cryptographique :

Terminal window
# Exemple de chemin dans le store
/nix/store/zpzfafanlmgkf1w3m3hbm8n8413hq5mc-firewall-reload

Ce hash (la partie zpzfafanlmgkf1w3m3hbm8n8413hq5mc) est calculé à partir de tout ce qui entre dans la construction du paquet : les sources, les dépendances, les options de compilation, le compilateur utilisé… Du coup, deux builds identiques produisent exactement le même résultat, byte pour byte. C’est ce qu’on appelle la reproductibilité.

Pourquoi c’est génial ? Plusieurs versions d’un même paquet coexistent sans conflit. Vous pouvez avoir Firefox 120 et Firefox 115 installés en même temps, chacun dans son répertoire. Pas de “DLL hell” comme sous Windows, pas de conflits de dépendances comme avec pip ou npm où installer un paquet peut en casser un autre.

Les profils et les générations

Mais alors, comment le système sait quel Firefox lancer quand vous tapez firefox ? C’est là qu’interviennent les profils. Un profil est simplement un ensemble de liens symboliques qui pointent vers les paquets dans le store.

Quand vous installez ou supprimez un paquet, Nix crée une nouvelle génération de votre profil. L’ancienne génération reste disponible. Si quelque chose ne va pas après une mise à jour, vous pouvez revenir en arrière instantanément :

Terminal window
# Lister les générations
nix-env --list-generations
# Revenir à la génération précédente
nix-env --rollback
# Ou revenir à une génération spécifique
nix-env --switch-generation 42

C’est exactement le même principe pour NixOS au niveau système : chaque nixos-rebuild switch crée une nouvelle génération. Au boot, vous pouvez choisir quelle génération démarrer dans le menu GRUB.

Configuration déclarative

Sur une distribution classique, pour configurer un serveur SSH, vous :

  1. Installez le paquet avec apt install openssh-server
  2. Éditez /etc/ssh/sshd_config
  3. Lancez systemctl enable --now sshd

Sur NixOS, tout ça se fait en une seule ligne dans votre configuration :

services.openssh.enable = true;

NixOS s’occupe d’installer le paquet, de générer la configuration, de créer le service systemd et de l’activer. Voici un exemple plus complet :

# Configuration NixOS minimale - /etc/nixos/configuration.nix
{ config, pkgs, ... }:
{
# Bootloader - systemd-boot pour les machines UEFI
boot.loader.systemd-boot.enable = true;
# Nom de la machine
networking.hostName = "bastion";
# Firewall activé par défaut, on ferme tout sauf SSH
networking.firewall.enable = true;
# SSH avec quelques options de sécurité
services.openssh.enable = true;
# Paquets disponibles pour tous les utilisateurs
environment.systemPackages = with pkgs; [
vim
git
htop
];
# Création d'un utilisateur admin
users.users.admin = {
isNormalUser = true;
extraGroups = [ "wheel" ]; # wheel = sudo
};
# Version de NixOS utilisée lors de l'installation initiale
# Ne pas changer après l'installation !
system.stateVersion = "24.11";
}

Pour appliquer cette configuration :

Terminal window
# Reconstruire et activer la configuration
sudo nixos-rebuild switch

Simple, non ? Tout est dans un fichier, versionnable dans Git, auditable. Si je veux ajouter un paquet, je l’ajoute à la liste environment.systemPackages et je relance la commande. Si je veux activer un service, j’ajoute services.monservice.enable = true;. Je sais, vous allez me dire: “encore un langage à apprendre…”. Oui, mais le langage Nix est simple et dédié à la gestion de paquets et de configurations. Et surtout, le gain en robustesse et en maintenabilité est énorme.

L’énorme avantage, c’est que je peux prendre ce fichier, le copier sur une autre machine, et obtenir exactement la même configuration. Pas de “j’ai oublié d’installer tel truc” ou “j’ai modifié tel fichier de config, mais je ne me souviens plus lequel”.

Les Flakes : le standard moderne

Les Flakes représentent l’évolution majeure de Nix depuis 2020. Ils sont encore marqués “expérimentaux”, mais tout le monde les utilise en production.

Le problème qu’ils résolvent ? Avant les flakes, quand vous faisiez nix-build, le résultat dépendait de la version de nixpkgs installée sur votre machine via les channels. Deux personnes avec des channels différents obtenaient des résultats différents. Pas très reproductible…

Les flakes apportent le verrouillage des dépendances via un fichier flake.lock, exactement comme package-lock.json pour npm ou poetry.lock pour Python. Vous déclarez vos dépendances dans flake.nix, et Nix génère automatiquement flake.lock avec les versions exactes (commits Git, hashes…).

# flake.nix minimal
{
description = "Configuration NixOS moderne";
# Les inputs sont les dépendances du flake
inputs = {
# On utilise nixpkgs version 24.11
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
};
# Les outputs sont ce que le flake produit
outputs = { self, nixpkgs }: {
# Une configuration NixOS nommée "bastion"
nixosConfigurations.bastion = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [ ./configuration.nix ];
};
};
}

Le fichier flake.lock généré automatiquement ressemble à ça :

{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1701282334,
"narHash": "sha256-MxCVrXY6v...",
"rev": "057f9aecfb71c4437d2b27d3323df7f93c010b7e",
"type": "github"
}
}
}
}

Plus de surprise lors d’un déploiement : même flake.lock = même système. Quand vous voulez mettre à jour, vous faites explicitement nix flake update, vous testez, et vous committez le nouveau flake.lock.

NixOS : un système d’exploitation pas comme les autres

Maintenant qu’on a vu comment fonctionne Nix le gestionnaire de paquets, parlons de NixOS la distribution Linux. Car NixOS pousse le concept beaucoup plus loin : ce n’est pas juste Nix installé sur une base Debian ou Fedora, c’est un système entièrement repensé.

Qu’est-ce qu’un OS “immuable” ?

On entend souvent parler de NixOS comme d’un OS “immuable”. C’est un peu un abus de langage, mais l’idée est là : sur NixOS, vous ne modifiez pas le système en place, vous déclarez un nouvel état et NixOS construit ce nouvel état à côté de l’ancien.

Concrètement, quand vous faites nixos-rebuild switch :

  1. NixOS lit votre configuration (/etc/nixos/configuration.nix ou votre flake)
  2. Il calcule tout ce qui doit être construit ou téléchargé
  3. Il télécharge/construit les paquets manquants dans /nix/store/
  4. Il crée une nouvelle “génération” du système avec des liens symboliques
  5. Il active cette nouvelle génération

L’ancienne génération reste intacte dans /nix/store/. Rien n’est supprimé, rien n’est modifié. C’est pour ça qu’on peut revenir en arrière instantanément.

Le processus de boot

Au démarrage, NixOS présente un menu (GRUB ou systemd-boot) avec la liste des générations disponibles :

NixOS - Configuration 147 (2024-11-28)
NixOS - Configuration 146 (2024-11-25)
NixOS - Configuration 145 (2024-11-20)
...

Chaque génération est un système complet et fonctionnel. Si la dernière mise à jour a cassé quelque chose, vous redémarrez sur une génération précédente et tout remarche. Pas besoin de snapshots Btrfs ou de sauvegardes : c’est intégré au système.

En interne, chaque génération pointe vers un chemin dans le store :

Terminal window
# Voir les générations système
ls -la /nix/var/nix/profiles/system-*
# La génération actuelle
readlink /run/current-system
# /nix/store/abc123...-nixos-system-bastion-24.11

Organisation du système de fichiers

Sur une distribution classique, la configuration est éparpillée partout : /etc/ssh/sshd_config, /etc/nginx/nginx.conf, /etc/systemd/system/… Sur NixOS, ces fichiers existent aussi, mais ils sont générés à partir de votre configuration Nix.

Voici comment NixOS organise les choses :

RépertoireContenuModifiable ?
/nix/store/Tous les paquets et configurations généréesNon (read-only)
/etc/Liens symboliques vers /nix/store/Non (régénéré)
/run/État temporaire du système actuelNon
/home/Données utilisateursOui
/var/Données variables (logs, bases de données)Oui
/tmp/Fichiers temporairesOui

La partie “immuable” c’est /nix/store/ et /etc/. Les données utilisateurs dans /home/ et les données applicatives dans /var/ restent modifiables, bien sûr.

Comment /etc/ fonctionne

Sur NixOS, /etc/ n’est pas un répertoire classique. C’est un mélange de liens symboliques vers le store et de fichiers générés au boot.

Par exemple, si vous activez SSH :

services.openssh.enable = true;
services.openssh.settings.PermitRootLogin = "no";

NixOS génère /etc/ssh/sshd_config avec le contenu approprié. Ce fichier pointe vers quelque chose comme :

Terminal window
ls -la /etc/ssh/sshd_config
lrwxrwxrwx 1 root root 27 1 déc. 16:10 ssh/sshd_config -> /etc/static/ssh/sshd_config

Si vous éditez /etc/ssh/sshd_config à la main, vos modifications seront écrasées au prochain nixos-rebuild. C’est voulu ! La configuration doit passer par les fichiers Nix pour être reproductible.

Les services systemd

NixOS utilise systemd comme init system, mais là encore avec une approche déclarative. Quand vous écrivez :

services.nginx.enable = true;
services.nginx.virtualHosts."example.com" = {
root = "/var/www/example";
};

NixOS génère automatiquement :

  • Le fichier de configuration nginx
  • L’unité systemd nginx.service
  • Les dépendances (création des répertoires, utilisateur nginx, etc.)
  • L’activation du service au boot

Vous pouvez voir les services générés :

Terminal window
# Lister les services actifs
systemctl list-units --type=service
# Voir la configuration générée pour nginx
systemctl cat nginx.service

Ce qui est vraiment immuable (et ce qui ne l’est pas)

Soyons précis sur ce qui est immuable et ce qui ne l’est pas :

Immuable (géré par Nix) :

  • Les binaires et bibliothèques (/nix/store/)
  • La configuration système (/etc/ généré)
  • Les services systemd
  • Le bootloader et le kernel

Mutable (données persistantes) :

  • /home/ - répertoires utilisateurs
  • /var/ - logs, bases de données, état des services
  • /root/ - répertoire root
  • Tout ce que vous déclarez avec environment.persistence si vous utilisez impermanence

Cette séparation est importante : NixOS garantit la reproductibilité du système, pas des données. Vos bases de données PostgreSQL, vos fichiers utilisateurs, vos logs… tout ça persiste entre les générations.

Garbage collection

Avec le temps, /nix/store/ accumule les anciennes générations. Pour nettoyer :

Terminal window
# Supprimer les générations de plus de 30 jours
sudo nix-collect-garbage --delete-older-than 30d
# Supprimer tout sauf la génération actuelle (attention !)
sudo nix-collect-garbage -d

Après un garbage collection, vous ne pourrez plus revenir aux générations supprimées. Je recommande de garder au moins 2-3 générations de secours.

Vous pouvez aussi automatiser le nettoyage dans votre configuration :

nix.gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 30d";
};

Tester rapidement avec une VM

Assez de théorie ! Le plus simple pour démarrer, c’est de créer une VM locale. Voici comment je fais avec disko pour le partitionnement déclaratif et QEMU/KVM. On va mettre en pratique tout ce qu’on a vu : flakes, configuration déclarative, génération de système, et boot sur une génération.

Structure du projet

Je crée un répertoire avec trois fichiers :

nixos-vm/
├── flake.nix # Point d'entrée : dépendances et outputs
├── flake.lock # Versions verrouillées (généré automatiquement)
├── configuration.nix # Configuration NixOS de la VM
└── disko-config.nix # Schéma de partitionnement déclaratif

Initialisons le projet :

Terminal window
# Créer le répertoire et initialiser Git (obligatoire pour les flakes)
mkdir nixos-vm && cd nixos-vm
git init

Configuration disko

Disko est un outil de la communauté Nix qui permet de décrire le partitionnement des disques de manière déclarative. Plus besoin de lancer fdisk ou parted manuellement et de se souvenir des commandes !

disko-config.nix
{ lib, ... }:
{
disko.devices = {
disk = {
main = {
type = "disk";
device = "/dev/vda"; # Disque virtio dans QEMU
content = {
type = "gpt"; # Table de partition GPT (moderne)
partitions = {
# Partition EFI pour le boot UEFI
ESP = {
size = "512M";
type = "EF00"; # Code pour partition EFI System
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
# Partition racine, tout l'espace restant
root = {
size = "100%";
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
};
};
};
};
};
};
}

C’est verbeux, mais l’avantage, c’est que c’est explicite et reproductible. Vous savez exactement comment votre disque sera partitionné. Et surtout, c’est versionné dans Git !

Configuration NixOS

Voici la configuration système. On retrouve tout ce qu’on a vu : activation des services via services.xxx.enable, configuration du bootloader, paquets système, utilisateur avec hash de mot de passe…

configuration.nix
{ config, pkgs, ... }:
{
# Boot en UEFI avec systemd-boot (moderne et simple)
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
# Hostname de la machine
networking.hostName = "nixos-vm";
# Timezone et locale (comme sur une distro classique, mais déclaratif)
time.timeZone = "Europe/Paris";
i18n.defaultLocale = "fr_FR.UTF-8";
console.keyMap = "fr";
# SSH activé pour se connecter à la VM
# NixOS génère /etc/ssh/sshd_config automatiquement
services.openssh = {
enable = true;
settings = {
PermitRootLogin = "prohibit-password";
PasswordAuthentication = false;
};
};
# Utilisateur admin avec authentification par clé SSH uniquement
# Pas de mot de passe = plus sécurisé (connexion SSH par clé obligatoire)
users.users.admin = {
isNormalUser = true;
extraGroups = [ "wheel" ]; # sudo
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAA... votre-cle-publique" # Remplacez par votre clé
];
};
# Pour autoriser sudo sans mot de passe (optionnel, pour cette VM de test)
security.sudo.wheelNeedsPassword = false;
# Paquets système disponibles pour tous les utilisateurs
environment.systemPackages = with pkgs; [
vim
git
htop
curl
tmux
];
# Activer les flakes et nix-command (déjà fait, mais explicite)
nix.settings.experimental-features = [ "nix-command" "flakes" ];
# Garbage collection automatique (ce qu'on a vu plus haut)
nix.gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 30d";
};
# Version de NixOS (ne pas changer sans migration)
system.stateVersion = "24.11";
}

Chaque option dans ce fichier correspond à quelque chose de concret :

  • services.openssh.enable = true → génère /etc/ssh/sshd_config et le service systemd
  • users.users.admin → crée l’utilisateur dans /etc/passwd, /etc/shadow
  • environment.systemPackages → installe les paquets dans le store et crée les liens dans /run/current-system/sw/bin/

Le flake complet

Le flake assemble tout. Il déclare les inputs (dépendances avec leurs versions) et les outputs (ce qu’on produit, ici une configuration NixOS) :

flake.nix
{
description = "VM NixOS de test avec disko";
inputs = {
# NixOS 24.11 stable
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
# Disko pour le partitionnement déclaratif
disko = {
url = "github:nix-community/disko";
inputs.nixpkgs.follows = "nixpkgs"; # Utiliser notre nixpkgs
};
};
outputs = { self, nixpkgs, disko, ... }: {
# Définition de notre système NixOS
nixosConfigurations.nixos-vm = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
# Module disko pour gérer le partitionnement
disko.nixosModules.disko
# Notre schéma de partitionnement
./disko-config.nix
# Notre configuration NixOS
./configuration.nix
];
};
};
}

À la première exécution, Nix va créer flake.lock avec les versions exactes de nixpkgs et disko. Ce fichier doit être commité dans Git !

Versionner la configuration

Avant de continuer, on commite tout :

Terminal window
# Ajouter les fichiers
git add flake.nix disko-config.nix configuration.nix flake.lock
# Premier commit
git commit -m "Initial NixOS VM configuration"
# Optionnel : pousser sur GitHub pour installer à distance
git remote add origin git@github.com:votre-user/nixos-vm.git
git push -u origin main

Créer et démarrer la VM

Maintenant, on crée une VM et on démarre sur l’ISO NixOS :

Terminal window
# Télécharger l'ISO NixOS minimal (environ 900 Mo)
wget https://channels.nixos.org/nixos-24.11/latest-nixos-minimal-x86_64-linux.iso
# Créer une image disque vide de 20 Go (format QCOW2, sparse)
qemu-img create -f qcow2 nixos-vm.qcow2 20G
# Démarrer la VM sur l'ISO
qemu-system-x86_64 \
-enable-kvm \
-m 2048 \
-smp 2 \
-boot d \
-cdrom latest-nixos-minimal-x86_64-linux.iso \
-drive file=nixos-vm.qcow2,format=qcow2,if=virtio \
-bios /usr/share/ovmf/OVMF.fd \
-nic user,hostfwd=tcp::2222-:22

Options expliquées :

  • -enable-kvm : virtualisation matérielle (beaucoup plus rapide)
  • -m 2048 : 2 Go de RAM
  • -smp 2 : 2 CPU virtuels
  • -boot d : booter sur le CD-ROM (l’ISO)
  • -bios /usr/share/ovmf/OVMF.fd : firmware UEFI (nécessaire pour systemd-boot)
  • -nic user,hostfwd=tcp::2222-:22 : réseau NAT avec redirection SSH

Installer NixOS depuis le flake

Une fois dans la VM (l’ISO démarre sur un shell root), on doit d’abord activer SSH et définir un mot de passe temporaire pour pouvoir copier nos fichiers :

Terminal window
# Dans la VM : définir un mot de passe pour root
sudo -i
passwd
# Entrez un mot de passe temporaire (ex: "nixos")

Depuis un autre terminal sur l’hôte, on copie notre configuration via scp :

Terminal window
# Depuis l'hôte, copier le répertoire dans la VM
scp -P 2222 -r nixos-vm root@localhost:/root/
# Se connecter en SSH à la VM
ssh -p 2222 root@localhost

Puis dans la VM :

Terminal window
# Activer les flakes dans l'ISO
sudo -i
export NIX_CONFIG="experimental-features = nix-command flakes"
# Aller dans le répertoire copié
cd /root/nixos-vm
# Partitionner et formater avec disko
nix run github:nix-community/disko -- --mode disko --flake .#nixos-vm
# Installer NixOS
nixos-install --flake .#nixos-vm --no-root-passwd
# Redémarrer
reboot

Vérifier le résultat

Après le reboot, la VM démarre sur le système installé. Connectez-vous en SSH :

Terminal window
# Depuis l'hôte
ssh -p 2222 admin@localhost

Une fois connecté, on peut vérifier que tout fonctionne :

Terminal window
# Voir la génération actuelle
nixos-version
# 24.11.20241201.abc1234 (Vicuña)
# Voir les générations disponibles (une seule pour l'instant)
sudo nix-env --list-generations -p /nix/var/nix/profiles/system
# 1 2025-12-01 16:10:15 (current)
# Voir où pointe le système actuel
readlink /run/current-system
# /nix/store/abc123...-nixos-system-nixos-vm-24.11
# Vérifier que SSH est bien configuré comme déclaré
cat /etc/ssh/sshd_config | grep -E "^(PermitRootLogin|PasswordAuthentication)"
PermitRootLogin prohibit-password
PasswordAuthentication no

Modifier et mettre à jour

La vraie puissance de NixOS apparaît quand on modifie la configuration. Ajoutons nginx à notre VM :

# Dans configuration.nix, ajouter :
services.nginx = {
enable = true;
virtualHosts."localhost" = {
root = "/var/www/html";
locations."/" = {
index = "index.html";
};
};
};
# Créer le contenu web
systemd.tmpfiles.rules = [
"d /var/www/html 0755 root root -"
"f /var/www/html/index.html 0644 root root - '<h1>Hello from NixOS!</h1>'"
];

Puis, on applique. Deux options :

Terminal window
# Option 1 : recopier via scp (rapide pour les tests)
scp -P 2222 -r nixos-vm admin@localhost:/home/admin/
ssh -p 2222 admin@localhost
cd /home/admin/nixos-vm
sudo nixos-rebuild switch --flake .#nixos-vm
# Option 2 : cloner depuis Git (recommandé, plus reproductible)
ssh -p 2222 admin@localhost
git clone https://github.com/votre-user/nixos-vm.git
cd nixos-vm
sudo nixos-rebuild switch --flake .#nixos-vm

L’option Git est préférable en production : la configuration vient toujours du dépôt, pas d’un répertoire local qui pourrait différer.

Après le rebuild, vous avez maintenant deux générations. Vous pouvez vérifier avec :

Terminal window
sudo nix-env --list-generations -p /nix/var/nix/profiles/system
1 2025-12-01 16:10:15
2 2025-12-01 16:23:45 (current)
sudo systemctl status nginx.service
nginx.service - Nginx Web Server
Loaded: loaded (/etc/systemd/system/nginx.service; enabled; preset: ignored)
Active: active (running) since Mon 2025-12-01 16:24:47 CET; 1min 11s ago
Invocation: 178e2181c1a8472e84e3b28eca9d20c5
Process: 693 ExecStartPre=/nix/store/x8nbgq6myz2js47r03j520srlcy0bg25-unit-script-nginx-pre-start/bin/nginx-pre-sta>
Main PID: 716 (nginx)
IP: 0B in, 0B out
IO: 4.6M read, 0B written
Tasks: 2 (limit: 4678)
Memory: 6.9M (peak: 8.1M)
CPU: 151ms
CGroup: /system.slice/nginx.service
├─716 "nginx: master process /nix/store/yvhfvc77k124mbdqpiclq7m129anph3v-nginx-1.26.3/bin/nginx -c /nix/st>
└─717 "nginx: worker process"
déc. 01 16:24:47 nixos-vm systemd[1]: Starting Nginx Web Server...
déc. 01 16:24:47 nixos-vm nginx-pre-start[701]: nginx: the configuration file /nix/store/id8vp83giycaw4s0r7bvbq4kjqpzpi>
déc. 01 16:24:47 nixos-vm nginx-pre-start[701]: nginx: configuration file /nix/store/id8vp83giycaw4s0r7bvbq4kjqpzpik4-n>
déc. 01 16:24:47 nixos-vm systemd[1]: Started Nginx Web Server.

Si nginx pose problème, vous pouvez revenir à la génération 1 :

Terminal window
# Rollback immédiat
sudo nixos-rebuild switch --rollback
# Vérifier que nginx n'est plus là
sudo systemctl status nginx.service
# Unit nginx.service could not be found.

Une fois que vous avez validé que le système fonctionne correctement sur une génération stable, vous pouvez nettoyer les anciennes générations :

Terminal window
# Supprimer les générations de plus de 7 jours
sudo nix-collect-garbage --delete-older-than 7d

Et voilà ! Vous avez une VM NixOS fonctionnelle, entièrement définie par du code versionné. Configuration déclarative, flakes pour la reproductibilité, disko pour le partitionnement, et rollback automatique. Tout ce qu’on a expliqué dans ce guide, en pratique.

Pour aller plus loin

Cet article pose les bases de NixOS : le Nix Store, les générations, la configuration déclarative, les flakes, et le fonctionnement interne de l’OS. Vous avez maintenant une VM fonctionnelle pour expérimenter.

J’apprécie vraiment la partie définition du système via des fichiers de configuration, même si cela impose d’apprendre le langage Nix. L’approche est un peu “hard” au début, mais une fois qu’on a compris les concepts, c’est très puissant.

J’adore aussi la possibilité de tester des outils sans les installer via nix-shell ou nix run. Par exemple :

Terminal window
# Lancer temporairement un outil sans l'installer
nix run nixpkgs#htop
# Ou créer un shell avec plusieurs outils
nix-shell -p git vim curl

Voici la liste des sujets que je compte approfondir (à partir d’une recherche faite ce matin) :

  • Le langage Nix : expressions, fonctions, listes, attributs
  • Les Flakes en détail : overlays, modules réutilisables
  • Écrire ses propres modules NixOS
  • nixos-generators : images QCOW2, RAW, ISO, AMI
  • nixos-anywhere : installation à distance via kexec
  • Intégration cloud Outscale : Outscale Machine Image (OMI)
  • Hardening niveau BP-28 : recommandations ANSSI
  • Colmena : déploiements multi-serveurs

Ressources complémentaires