168 lines
6.4 KiB
Nix
168 lines
6.4 KiB
Nix
# 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 = true;
|
|
|
|
# À 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 = "enp0s31f6";
|
|
serverIp = "192.168.1.10";
|
|
|
|
fleetRepo = "git+https://gitea.miniclic.net/Damien/Nixos_Fleet.git";
|
|
webroot = "/var/www/pxe";
|
|
tftpRoot = "/var/lib/tftpboot";
|
|
in
|
|
{
|
|
imports = [
|
|
# Chemin absolu, HORS de ce repo (emplacement par défaut de
|
|
# `nixos-generate-config`) : le repo n'a donc rien à committer pour
|
|
# que le build fonctionne, il reste purement "pull". Un flake ne
|
|
# voit que les fichiers qu'il suit lui-même par git ; un chemin
|
|
# absolu en dehors du repo échappe à cette règle, d'où le --impure
|
|
# au build (nécessaire pour lire un chemin hors du flake).
|
|
/etc/nixos/hardware-configuration.nix
|
|
];
|
|
|
|
i18n.defaultLocale = "fr_FR.UTF-8";
|
|
|
|
boot.loader.systemd-boot.enable = true;
|
|
boot.loader.efi.canTouchEfiVariables = true;
|
|
# Si le serveur est en BIOS legacy (pas UEFI), remplacer les deux lignes
|
|
# au-dessus par boot.loader.grub.device = "/dev/sdX";
|
|
|
|
networking.hostName = "pxe-server";
|
|
networking.firewall.allowedUDPPorts = [
|
|
67
|
|
69
|
|
4011
|
|
];
|
|
networking.firewall.allowedTCPPorts = [ 80 ];
|
|
|
|
services.dnsmasq = {
|
|
enable = true;
|
|
# Par défaut, NixOS fait pointer /etc/resolv.conf sur 127.0.0.1 pour
|
|
# utiliser dnsmasq comme résolveur DNS local. Comme port = 0 désactive
|
|
# justement la partie DNS de dnsmasq (on ne veut que DHCP/TFTP/PXE),
|
|
# ça cassait toute résolution DNS du système (dont git pull). On garde
|
|
# le résolveur DNS normal (DHCP/NetworkManager).
|
|
resolveLocalQueries = false;
|
|
settings = {
|
|
bind-dynamic = true; # ne pas exiger que l'interface existe au démarrage
|
|
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
|
|
'';
|
|
};
|
|
};
|
|
|
|
# Attend que le réseau soit vraiment prêt avant de démarrer (en plus de
|
|
# bind-dynamic ci-dessus, qui gère le cas où l'interface apparaît encore
|
|
# plus tard, ex. carte USB).
|
|
systemd.services.dnsmasq = {
|
|
after = [ "network-online.target" ];
|
|
wants = [ "network-online.target" ];
|
|
};
|
|
|
|
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";
|
|
# git est nécessaire : nix doit fetcher l'URL git+https:// du flake.
|
|
path = [
|
|
config.nix.package
|
|
pkgs.git
|
|
];
|
|
script = ''
|
|
set -euo pipefail
|
|
kernel=$(nix build --no-link --no-write-lock-file --refresh --print-out-paths "${fleetRepo}#nixosConfigurations.installer-netboot.config.system.build.kernel")
|
|
initrd=$(nix build --no-link --no-write-lock-file --refresh --print-out-paths "${fleetRepo}#nixosConfigurations.installer-netboot.config.system.build.netbootRamdisk")
|
|
ipxeScript=$(nix build --no-link --no-write-lock-file --refresh --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;
|
|
|
|
# git installé pour de bon (pull/push manuels sans réouvrir un
|
|
# nix-shell -p git à chaque fois).
|
|
environment.systemPackages = [ pkgs.git ];
|
|
|
|
system.stateVersion = "26.05";
|
|
}
|