commit e37e956f95eb37ae4fcf26ed17c6f1b0dc9d6b94 Author: Damien Date: Sun Sep 6 17:32:17 2026 +0200 init diff --git a/README.md b/README.md new file mode 100644 index 0000000..b4ca938 --- /dev/null +++ b/README.md @@ -0,0 +1,391 @@ +# Nixos_Fleet + +Déploiement en masse (PXE ou USB) du profil générique `usagers`. + +Repo public. `git pull` sans mot de passe. + +Ne contient aucune donnée des utilisateurs nommés. Ça, c'est dans [Nixos_Users](../nixos_users), repo privé séparé. + +--- + +# Installer un PC + +Une étape à la fois. Ne saute pas d'étape. + +## Étape 1 — Brancher + +Branche le câble réseau. + +Branche le PC au secteur. + +Allume le PC. + +## Étape 2 — Menu de démarrage + +Appuie plusieurs fois sur une touche dès l'allumage. + +Dell → F12 + +HP → F9 + +Lenovo → F12 + +Choisis : Network Boot. + +## Étape 3 — Attendre + +Un écran noir avec du texte apparaît seul. + +Attends. + +## Étape 4 — Choisir un cas + +Il y a deux cas. Choisis-en un seul. + +PC normal → va à l'étape 4A. + +PC pour thomas, clara, jade ou oreo → va à l'étape 4B. + +## Étape 4A — PC normal + +Tape : `1` + +Appuie sur Entrée. + +N'appuie plus sur rien. + +Attends la fin (plusieurs minutes). + +Va à l'étape 5. + +## Étape 4B — PC pour une personne + +Tape : `2` + +Appuie sur Entrée. + +Tape le prénom (thomas, clara, jade ou oreo). + +Appuie sur Entrée. + +Une question sur le chiffrement apparaît. + +Pas sûr → appuie juste sur Entrée. + +Tape le token (donné à part, pas dans ce guide). + +Appuie sur Entrée. + +Si une passphrase est demandée : + +Tape-la. + +Note-la sur papier tout de suite. + +Attends la fin (plusieurs minutes). + +Va à l'étape 5. + +## Étape 5 — Redémarrage + +Le PC redémarre seul. + +N'y touche pas. + +## Étape 6 — Connexion + +PC normal : + +Utilisateur : `usagers` + +Mot de passe : `nixos` + +PC pour une personne : + +Utilisateur : le prénom tapé à l'étape 4B + +Mot de passe : `nixos` + +Un nouveau mot de passe est demandé tout de suite. Le choisir maintenant. + +## Étape 7 — Vérifier + +Le bureau s'affiche. + +Firefox s'ouvre. + +Le son fonctionne. + +Tout est bon → le PC est prêt. + +## Si ça bloque + +N'insiste pas seul. + +Préviens le référent technique. + +--- + +# Installer le serveur PXE + +Une étape à la fois. + +## Étape 1 — Installer NixOS + +ISO : https://nixos.org/download + +Partitionnement normal. + +Définir un mot de passe root. + +## Étape 2 — Cloner le repo + +```bash +nix-shell -p git +git clone https://gitea.miniclic.net/Damien/Nixos_Fleet.git /etc/nixos-fleet +cd /etc/nixos-fleet +``` + +## Étape 3 — Éditer 3 valeurs + +Fichier : `pxe-server/configuration.nix` + +`interface` → sortie de `ip a` + +`serverIp` → IP fixe du serveur + +`standaloneDhcp` → laisser `false` si le réseau a déjà un DHCP + +```bash +$EDITOR pxe-server/configuration.nix +``` + +## Étape 4 — Construire + +```bash +sudo nixos-rebuild switch --flake .#pxe-server +``` + +## Étape 5 — Publier l'image + +```bash +sudo systemctl start pxe-publish +sudo systemctl status pxe-publish +``` + +Doit finir en "success". Première fois : plusieurs minutes. + +## Étape 6 — Vérifier + +```bash +sudo systemctl status dnsmasq caddy +ls /var/lib/tftpboot +ls /var/www/pxe +curl -I http:///netboot.ipxe +``` + +Tout doit répondre sans erreur. + +## Étape 7 — Tester sur 1 PC + +Démarrer un seul PC en PXE. + +Vérifier qu'il arrive sur l'écran de choix. + +Si le parc a du BIOS et de l'UEFI, tester les deux. + +Ne pas lancer 20 PC avant que cette étape fonctionne. + +## Après l'installation + +Noter l'IP du serveur quelque part accessible à l'équipe. + +Vérifier que `pxe-publish.timer` est actif : + +```bash +systemctl is-enabled pxe-publish.timer +``` + +Ce serveur n'a rien à sauvegarder à part le repo git. + +## Entretien + +Republier l'image après une modif de `installer/` : + +```bash +sudo systemctl start pxe-publish +``` + +Appliquer une modif de `pxe-server/configuration.nix` : + +```bash +sudo nixos-rebuild switch --flake .#pxe-server +``` + +Voir les logs DHCP/TFTP : + +```bash +journalctl -u dnsmasq -f +``` + +Voir les logs HTTP : + +```bash +journalctl -u caddy -f +``` + +## Si ça bloque + +Écran PXE ne trouve rien → revérifier `serverIp` et `interface`. + +Boucle infinie au démarrage → regarder `journalctl -u dnsmasq` pendant un boot. + +UEFI ou BIOS ne boote pas → vérifier les deux fichiers dans `/var/lib/tftpboot`. + +IP qui changent tout le temps → un autre DHCP tourne déjà, repasser `standaloneDhcp` à `false`. + +--- + +# Référence + +## Contenu du repo + +`hosts/usagers/` → le seul profil du repo. Jamais chiffré. + +`disks/plain.nix` → layout disko (disque `main`, GPT+ESP+btrfs). + +`installer/` → l'image d'installation, PXE et USB. Même image pour tous les cas. + +`pxe-server/` → le serveur PXE (dnsmasq + Caddy). + +## Pourquoi deux repos + +Une machine de la flotte pull uniquement ce repo. + +Les comptes thomas/clara/jade/oreo vivent dans un autre repo, privé. + +La flotte ne voit jamais ce second repo. + +## Graver la clé USB + +```bash +nix build .#nixosConfigurations.installer-iso.config.system.build.isoImage +sudo dd if=result/iso/*.iso of=/dev/sdX bs=4M status=progress conv=fsync +``` + +Vérifier `/dev/sdX` avant de lancer `dd`. + +## Mises à jour de la flotte + +Chaque PC tire ses mises à jour directement depuis ce repo, tous les jours. + +Pas de `git pull` manuel sur les PC. Juste `git push` ici. + +## Avant la première vague de 100 PC + +Rien de ce repo n'a été testé sur du vrai matériel. + +À vérifier avant de lancer 100 PC : + +Détection du disque, sur une machine à 2 disques internes. + +Comportement du proxyDHCP, face au routeur réel. + +Boot BIOS et boot UEFI, sur le parc réel. + +Test sur 1-2 PC réels d'abord. + +```bash +nix flake check +nix build .#nixosConfigurations.usagers.config.system.build.toplevel +nix build .#nixosConfigurations.installer-iso +``` + +--- + +# Travailler avec Git + +## Cloner (première fois) + +```bash +git clone https://gitea.miniclic.net/Damien/Nixos_Fleet.git +cd Nixos_Fleet +``` + +## Avant de modifier + +```bash +git pull +``` + +Toujours, avant de commencer à éditer. + +## Modifier et envoyer + +```bash +git add -A +git commit -m "description courte" +git push +``` + +## Si le push est refusé + +Quelqu'un a poussé avant toi. + +```bash +git pull +``` + +Résoudre les conflits s'il y en a (voir plus bas). + +Puis repousser : + +```bash +git push +``` + +## Travailler à plusieurs + +Un repo, plusieurs personnes : risque d'écraser le travail des autres. + +Règle : une branche par changement. + +```bash +git checkout -b mon-changement +``` + +Modifier. Commit. Push la branche : + +```bash +git push -u origin mon-changement +``` + +Ouvrir une Pull Request sur Gitea. + +Quelqu'un relit, merge depuis l'interface Gitea. + +Jamais de push direct sur `main` à plusieurs. + +## Si un conflit apparaît + +Git l'annonce avec `CONFLICT` dans le message. + +Ouvrir le(s) fichier(s) listé(s). + +Chercher les marqueurs `<<<<<<<`, `=======`, `>>>>>>>`. + +Choisir quelle version garder. + +Supprimer les marqueurs. + +```bash +git add +git commit +git push +``` + +## Ce workflow git ne concerne que les développeurs + +Les PC de la flotte ne font jamais `git pull`. + +Ils tirent les mises à jour directement depuis l'URL git (voir plus haut). diff --git a/disks/plain.nix b/disks/plain.nix new file mode 100644 index 0000000..ab25d95 --- /dev/null +++ b/disks/plain.nix @@ -0,0 +1,50 @@ +# Layout disko pour les PC de la flotte : jamais chiffré (voir README). +# Le disque est déclaré sous le nom symbolique "main" ; le device réel est +# fourni au moment de l'install par : disko-install --disk main /dev/sdX +{ + disko.devices = { + disk = { + main = { + type = "disk"; + device = "/dev/placeholder"; # remplacé par disko-install --disk main + content = { + type = "gpt"; + partitions = { + ESP = { + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "umask=0077" ]; + }; + }; + root = { + size = "100%"; + content = { + type = "btrfs"; + extraArgs = [ "-f" ]; + subvolumes = { + "/root" = { + mountpoint = "/"; + }; + "/home" = { + mountpoint = "/home"; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + }; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..2c66d48 --- /dev/null +++ b/flake.nix @@ -0,0 +1,40 @@ +{ + description = "Nixos_Fleet : parc de PC génériques (PXE/USB, disko, jamais chiffré)"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05"; + disko = { + url = "github:nix-community/disko"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = + { self, nixpkgs, disko, ... }: + { + nixosConfigurations = { + usagers = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + disko.nixosModules.disko + ./hosts/usagers/configuration.nix + ]; + }; + + installer-netboot = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ ./installer/netboot.nix ]; + }; + + installer-iso = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ ./installer/iso.nix ]; + }; + + pxe-server = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ ./pxe-server/configuration.nix ]; + }; + }; + }; +} diff --git a/hosts/common/accounts.nix b/hosts/common/accounts.nix new file mode 100644 index 0000000..1a74c2d --- /dev/null +++ b/hosts/common/accounts.nix @@ -0,0 +1,23 @@ +# Compte admin des machines de la flotte : root, mot de passe "nixos" +# STABLE (pas d'expiration forcée ici, contrairement à nixos_users) — +# ces machines sont génériques/partagées, un mot de passe connu et +# constant sur tout le parc est voulu pour l'administration courante. +{ pkgs, ... }: + +{ + users.mutableUsers = true; + + users.users.root = { + initialPassword = "nixos"; + }; + + # Login root direct autorisé nativement dès qu'un mot de passe est + # défini (console/tty). SSH reste sur le défaut NixOS (clé uniquement) : + # le mot de passe "nixos" n'ouvre pas la porte à distance, seulement en + # local sur la machine. + + # `initialPassword` n'est appliqué par NixOS qu'à la création du compte, + # donc un rebuild/auto-upgrade ultérieur ne le réécrit jamais — mais ici + # on ne force pas non plus de changement : "nixos" doit rester valide + # indéfiniment sur la flotte. +} diff --git a/hosts/common/base.nix b/hosts/common/base.nix new file mode 100644 index 0000000..24903fa --- /dev/null +++ b/hosts/common/base.nix @@ -0,0 +1,68 @@ +# Socle commun à toutes les machines de la flotte (repo public). +{ pkgs, ... }: + +{ + # Toutes les machines de la flotte portent le même nom : pas + # d'identification individuelle pour l'instant (voir README du repo + # racine). À revoir plus tard via le numéro de série DMI si un vrai + # besoin d'identification apparaît. + networking.hostName = "Nixos_Fleet"; + networking.networkmanager.enable = true; + + time.timeZone = "Europe/Paris"; + i18n.defaultLocale = "fr_FR.UTF-8"; + i18n.extraLocaleSettings = { + LC_ADDRESS = "fr_FR.UTF-8"; + LC_IDENTIFICATION = "fr_FR.UTF-8"; + LC_MEASUREMENT = "fr_FR.UTF-8"; + LC_MONETARY = "fr_FR.UTF-8"; + LC_NAME = "fr_FR.UTF-8"; + LC_NUMERIC = "fr_FR.UTF-8"; + LC_PAPER = "fr_FR.UTF-8"; + LC_TELEPHONE = "fr_FR.UTF-8"; + LC_TIME = "fr_FR.UTF-8"; + }; + services.xserver.xkb = { + layout = "fr"; + variant = ""; + }; + + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + boot.loader.systemd-boot.configurationLimit = 10; + + services.openssh.enable = true; + networking.firewall.enable = true; + + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + nixpkgs.config.allowUnfree = true; + + nix.gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 30d"; + }; + + # Convergence : chaque machine de la flotte tire ses mises à jour du + # même repo public, sans intervention humaine (pas de netrc nécessaire + # ici, contrairement au repo nixos_users). Voir README pour adapter + # l'URL réelle du repo. + system.autoUpgrade = { + enable = true; + dates = "daily"; + flake = "git+https://gitea.miniclic.net/Damien/Nixos_Fleet.git#usagers"; + }; + + environment.systemPackages = with pkgs; [ + git + curl + wget + htop + nixfmt + ]; + + system.stateVersion = "26.05"; +} diff --git a/hosts/common/desktop.nix b/hosts/common/desktop.nix new file mode 100644 index 0000000..e4bafd1 --- /dev/null +++ b/hosts/common/desktop.nix @@ -0,0 +1,57 @@ +# Bureau Cinnamon générique pour la flotte. Adapté (pas importé) depuis +# nixos_cinnamon/hosts/cinnamon/desktop-cinnamon.nix : les deux repos +# restent indépendants au `git pull`. +{ pkgs, ... }: + +{ + services.xserver.enable = true; + services.xserver.displayManager.lightdm.enable = true; + services.xserver.desktopManager.cinnamon.enable = true; + services.accounts-daemon.enable = true; + + environment.cinnamon.excludePackages = with pkgs; [ + celluloid + warpinator + ]; + + # Réglages de confidentialité génériques (pas de SearXNG/DNS personnels + # comme sur le poste perso — cette config est destinée à être publique). + programs.firefox = { + enable = true; + languagePacks = [ "fr" ]; + + preferences = { + "privacy.resistFingerprinting" = true; + "browser.newtabpage.activity-stream.showSponsored" = false; + "browser.search.suggest.enabled" = false; + "dom.security.https_only_mode" = true; + "media.peerconnection.enabled" = false; + "geo.enabled" = false; + "network.captive-portal-service.enabled" = false; + }; + + policies = { + DisableTelemetry = true; + DisablePocket = true; + DisableFirefoxStudies = true; + OfferToSaveLogins = false; + DontCheckDefaultBrowser = true; + EnableTrackingProtection = { + Value = true; + Locked = true; + }; + ExtensionSettings = { + "uBlock0@raymondhill.net" = { + install_url = "https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi"; + installation_mode = "force_installed"; + }; + }; + }; + }; + + environment.systemPackages = with pkgs; [ + libreoffice + thunderbird + vlc + ]; +} diff --git a/hosts/usagers/configuration.nix b/hosts/usagers/configuration.nix new file mode 100644 index 0000000..d37294d --- /dev/null +++ b/hosts/usagers/configuration.nix @@ -0,0 +1,20 @@ +# Profil générique "usagers" : poste non-nominatif de la flotte. +{ ... }: + +{ + imports = [ + ../common/base.nix + ../common/accounts.nix + ../common/desktop.nix + ../../disks/plain.nix + ]; + + # Compte de session non-nominatif, mot de passe "nixos" stable, sans + # expiration forcée (voir hosts/common/accounts.nix). + users.users.usagers = { + isNormalUser = true; + description = "Usagers"; + extraGroups = [ "networkmanager" ]; + initialPassword = "nixos"; + }; +} diff --git a/installer/install.sh b/installer/install.sh new file mode 100644 index 0000000..a2350ff --- /dev/null +++ b/installer/install.sh @@ -0,0 +1,115 @@ +# Pas de shebang ici : ce fichier est injecté comme corps de script par +# pkgs.writeShellScriptBin dans installer-base.nix (qui ajoute déjà +# `#!...` + `set -euo pipefail`). +# +# Installeur unique pour les deux repos : +# - branche "flotte" -> nixos_fleet (public, jamais chiffré) +# - branche "utilisateur nommé" -> nixos_users (privé, chiffrement au choix) +# Ce script ne contient aucun secret : le token du repo privé est saisi en +# direct, jamais stocké dans ce fichier ni dans un repo git. + +FLEET_REPO="git+https://gitea.miniclic.net/Damien/Nixos_Fleet.git" +USERS_REPO_HOST="gitea.miniclic.net" +USERS_REPO_PATH="Damien/Nixos_Users.git" + +echo "=== Installeur Nixos_Fleet ===" +echo "1) PC de la flotte (générique)" +echo "2) Poste utilisateur nommé" +read -rp "Choix [1/2] : " CHOICE + +# --- Détection automatique du disque cible ------------------------------- +# On exclut les disques amovibles (la clé USB de boot elle-même) et les +# loop/rom. S'il en reste plusieurs (rare), on prend le plus gros et on le +# signale clairement dans les logs plutôt que de bloquer sur un menu. +echo +echo "Détection du disque cible..." +mapfile -t CANDIDATES < <( + lsblk -dn -b -o NAME,TYPE,RM,SIZE | + awk '$2 == "disk" && $3 == 0 { print $4, $1 }' | + sort -rn +) + +if [ "${#CANDIDATES[@]}" -eq 0 ]; then + echo "Aucun disque fixe détecté. Abandon." >&2 + exec bash +fi + +DEVICE="/dev/$(echo "${CANDIDATES[0]}" | awk '{print $2}')" +if [ "${#CANDIDATES[@]}" -gt 1 ]; then + echo "ATTENTION : plusieurs disques fixes détectés, le plus gros a été retenu : $DEVICE" + printf ' %s\n' "${CANDIDATES[@]}" +else + echo "Disque retenu : $DEVICE" +fi + +case "$CHOICE" in + 1) + # --- Branche flotte : rien d'autre à saisir ----------------------- + echo + echo "Installation du profil générique 'usagers' sur $DEVICE..." + nix run 'github:nix-community/disko#disko-install' -- --write-efi-boot-entries \ + --flake "${FLEET_REPO}#usagers" \ + --disk main "$DEVICE" + ;; + + 2) + # --- Branche utilisateur nommé ------------------------------------- + read -rp "Utilisateur (thomas/clara/jade/oreo) : " USER_PROFILE + USER_PROFILE=$(echo "$USER_PROFILE" | tr '[:upper:]' '[:lower:]' | xargs) + case "$USER_PROFILE" in + thomas|clara|jade|oreo) ;; + *) + echo "Utilisateur inconnu : $USER_PROFILE" >&2 + exec bash + ;; + esac + + read -rp "Chiffrer le disque ? [o/N] : " ENCRYPT + ATTR="$USER_PROFILE" + if [[ "$ENCRYPT" =~ ^[oOyY] ]]; then + ATTR="${USER_PROFILE}-luks" + fi + + read -rsp "Token Gitea (repo privé Nixos_Users) : " TOKEN + echo + + # Le token n'est utilisé qu'en mémoire/ligne de commande pour ce fetch + # ponctuel : il n'est jamais écrit dans un fichier suivi par git. + AUTHED_URL="git+https://${TOKEN}@${USERS_REPO_HOST}/${USERS_REPO_PATH}" + + echo + echo "Installation du profil '$ATTR' sur $DEVICE..." + if [[ "$ATTR" == *-luks ]]; then + echo "Disque chiffré : disko va demander une passphrase LUKS pendant le partitionnement." + fi + nix run 'github:nix-community/disko#disko-install' -- --write-efi-boot-entries \ + --flake "${AUTHED_URL}#${ATTR}" \ + --disk main "$DEVICE" + + # Le système installé doit pouvoir continuer à tirer ses mises à jour + # du repo privé tout seul : on lui laisse un netrc, jamais commité, + # jamais dans le Nix store (nix.settings.netrc-file dans le repo + # nixos_users pointe vers ce même chemin). + # + # ATTENTION : le format exact attendu par Gitea (login=token vs + # login+password séparés) dépend de la version/config du serveur — + # à vérifier sur l'instance réelle avant le déploiement pilote. + mkdir -p /mnt/etc/nix + { + echo "machine ${USERS_REPO_HOST}" + echo "login ${TOKEN}" + echo "password x-oauth-basic" + } > /mnt/etc/nix/netrc + chmod 600 /mnt/etc/nix/netrc + ;; + + *) + echo "Choix invalide." >&2 + exec bash + ;; +esac + +echo +echo "Installation terminée. Redémarrage dans 10s (Ctrl-C pour annuler et inspecter /mnt)..." +sleep 10 +reboot diff --git a/installer/installer-base.nix b/installer/installer-base.nix new file mode 100644 index 0000000..dd4e190 --- /dev/null +++ b/installer/installer-base.nix @@ -0,0 +1,48 @@ +# Environnement live commun aux deux formes d'image (PXE netboot / ISO +# USB). Contient juste de quoi partitionner et lancer disko-install ; la +# vraie configuration cible est toujours récupérée depuis git au moment +# de l'install (repo public nixos_fleet ou repo privé nixos_users). +{ pkgs, lib, ... }: + +let + installScript = pkgs.writeShellScriptBin "fleet-install" (builtins.readFile ./install.sh); +in +{ + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + + environment.systemPackages = with pkgs; [ + git + parted + gptfdisk + util-linux # lsblk + installScript + ]; + + # disko-install n'est pas préinstallé : install.sh l'invoque via + # `nix run github:nix-community/disko#disko-install`, ce qui évite de + # dépendre d'un nom de paquet nixpkgs précis (pas de package `disko` + # garanti tel quel côté nixpkgs) et reste conforme à l'usage documenté + # du projet. + + networking.networkmanager.enable = true; + services.xserver.xkb.layout = "fr"; + console.keyMap = "fr"; + + # Root autologin sur tty1, l'installeur se lance automatiquement au + # login. S'il échoue ou qu'on le quitte, on retombe sur un shell root + # normal pour dépanner à la main — pas de piège sans issue. + services.getty.autologinUser = "root"; + users.users.root.password = lib.mkForce ""; + + environment.etc."profile.d/00-fleet-installer.sh".text = '' + if [ "$(tty)" = "/dev/tty1" ] && [ -z "$FLEET_INSTALLER_RAN" ]; then + export FLEET_INSTALLER_RAN=1 + ${installScript}/bin/fleet-install + fi + ''; + + system.stateVersion = "26.05"; +} diff --git a/installer/iso.nix b/installer/iso.nix new file mode 100644 index 0000000..6f5f2a3 --- /dev/null +++ b/installer/iso.nix @@ -0,0 +1,9 @@ +# Image ISO bootable sur clé USB, en secours du PXE (même install.sh). +{ modulesPath, ... }: + +{ + imports = [ + (modulesPath + "/installer/cd-dvd/installation-cd-minimal.nix") + ./installer-base.nix + ]; +} diff --git a/installer/netboot.nix b/installer/netboot.nix new file mode 100644 index 0000000..11df15f --- /dev/null +++ b/installer/netboot.nix @@ -0,0 +1,9 @@ +# Image PXE (kernel + initrd + squashfs), servie par pxe-server/. +{ modulesPath, ... }: + +{ + imports = [ + (modulesPath + "/installer/netboot/netboot-minimal.nix") + ./installer-base.nix + ]; +} diff --git a/pxe-server/configuration.nix b/pxe-server/configuration.nix new file mode 100644 index 0000000..7788e1e --- /dev/null +++ b/pxe-server/configuration.nix @@ -0,0 +1,126 @@ +# Serveur PXE déclaratif : DHCP-proxy (ou DHCP complet)+TFTP (dnsmasq) +# pour le premier étage iPXE, HTTP (Caddy) pour kernel/initrd/script iPXE +# (TFTP seul est trop lent pour de gros fichiers). Ce host n'a besoin +# d'aucune donnée privée : il ne sert que l'image d'installation publique +# nixos_fleet ; le repo privé nixos_users n'est fetché qu'au moment de +# l'install, directement par la machine en cours d'installation. +{ config, lib, pkgs, ... }: + +let + # true = ce serveur devient l'UNIQUE serveur DHCP du réseau cible. + # false = proxyDHCP uniquement : coexiste avec le routeur/DHCP existant, + # répond seulement aux requêtes de boot PXE. C'est le mode + # recommandé si les 100 PC restent sur un réseau qui a déjà un + # DHCP (le cas le plus probable). + standaloneDhcp = false; + + # À adapter à l'interface réseau réelle du serveur, et à son IP fixe + # (le script iPXE doit pointer vers une adresse stable, pas un nom + # d'interface). + interface = "eth0"; + serverIp = "192.168.1.10"; + + fleetRepo = "git+https://gitea.miniclic.net/Damien/Nixos_Fleet.git"; + webroot = "/var/www/pxe"; + tftpRoot = "/var/lib/tftpboot"; +in +{ + networking.hostName = "pxe-server"; + networking.firewall.allowedUDPPorts = [ + 67 + 69 + 4011 + ]; + networking.firewall.allowedTCPPorts = [ 80 ]; + + services.dnsmasq = { + enable = true; + settings = { + port = 0; # pas de résolution DNS, uniquement DHCP/TFTP/PXE + inherit interface; + "enable-tftp" = true; + "tftp-root" = tftpRoot; + + # Détection d'architecture + évite la boucle de chainload iPXE : + # une machine qui a déjà démarré en iPXE s'annonce via l'option 175, + # on lui sert alors le script HTTP plutôt que de rechainer le même + # binaire à l'infini. + "dhcp-match" = [ + "set:ipxe,175" + "set:efi-x86_64,option:client-arch,7" + ]; + "dhcp-boot" = [ + "tag:ipxe,http://${serverIp}/netboot.ipxe" + "tag:!ipxe,tag:efi-x86_64,ipxe.efi" + "tag:!ipxe,tag:!efi-x86_64,undionly.kpxe" + ]; + } + // ( + if standaloneDhcp then + { "dhcp-range" = [ "192.168.1.50,192.168.1.150,12h" ]; } # à adapter au réseau cible + else + { "dhcp-range" = [ "192.168.1.0,proxy" ]; } # à adapter au sous-réseau existant + ); + }; + + # `:80` explicite (pas de nom de domaine) : Caddy ne tente donc aucune + # demande de certificat ACME, il sert juste du HTTP nu en local — exactement + # ce qu'il faut pour du netboot sur un LAN. + services.caddy = { + enable = true; + virtualHosts.":80" = { + extraConfig = '' + root * ${webroot} + file_server + ''; + }; + }; + + systemd.tmpfiles.rules = [ + "d ${tftpRoot} 0755 dnsmasq dnsmasq -" + "d ${webroot} 0755 caddy caddy -" + ]; + + # Republie l'image d'installation netboot depuis le repo public. À + # relancer après chaque évolution notable de installer/ dans + # nixos_fleet (systemctl start pxe-publish), en plus du rafraîchissement + # quotidien automatique ci-dessous. + systemd.services.pxe-publish = { + description = "Publie l'image d'installation netboot Nixos_Fleet pour le PXE"; + path = [ config.nix.package ]; + script = '' + set -euo pipefail + kernel=$(nix build --no-link --print-out-paths "${fleetRepo}#nixosConfigurations.installer-netboot.config.system.build.kernel") + initrd=$(nix build --no-link --print-out-paths "${fleetRepo}#nixosConfigurations.installer-netboot.config.system.build.netbootRamdisk") + ipxeScript=$(nix build --no-link --print-out-paths "${fleetRepo}#nixosConfigurations.installer-netboot.config.system.build.netbootIpxeScript") + + install -m 0644 "$kernel/bzImage" "${webroot}/bzImage" + install -m 0644 "$initrd/initrd" "${webroot}/initrd" + install -m 0644 "$ipxeScript/netboot.ipxe" "${webroot}/netboot.ipxe" + + # Binaires iPXE premier étage (BIOS + UEFI). Noms de sortie du + # paquet pkgs.ipxe à vérifier sur la version réelle avant le pilote. + install -m 0644 "${pkgs.ipxe}/undionly.kpxe" "${tftpRoot}/undionly.kpxe" || true + install -m 0644 "${pkgs.ipxe}/ipxe.efi" "${tftpRoot}/ipxe.efi" || true + ''; + serviceConfig.Type = "oneshot"; + }; + + systemd.timers.pxe-publish = { + description = "Rafraîchit quotidiennement l'image PXE (converge avec nixos_fleet)"; + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = "daily"; + Persistent = true; + }; + }; + + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + + networking.networkmanager.enable = lib.mkDefault true; + services.openssh.enable = true; + system.stateVersion = "26.05"; +}