mirror of
https://github.com/nix-community/raspberry-pi-nix.git
synced 2025-11-08 19:46:03 +01:00
259 lines
8.5 KiB
Nix
259 lines
8.5 KiB
Nix
# This module creates a bootable netboot image containing the given NixOS
|
|
# configuration. The generated image consists of a `/boot` partition
|
|
# (for TFTP boot) and a `/root` partition (for NFS root). The goal is to
|
|
# allow the system to boot over the network, using TFTP to retrieve the
|
|
# boot files and NFS to mount the root filesystem, enabling fully
|
|
# headless deployment of the NixOS system.
|
|
|
|
# The generated netboot image consists of two directories:
|
|
# - `/boot`: Contains the necessary bootloader, kernel, and initrd files
|
|
# required for booting the system. These files will be served via TFTP
|
|
# to the target machine.
|
|
# - `/root`: Contains the root filesystem that will be mounted by the
|
|
# target machine over NFS. This is typically an ext4 root partition
|
|
# populated with the necessary NixOS configuration.
|
|
|
|
# The image is generated in such a way that it can be used to netboot a
|
|
# Raspberry Pi (or any other compatible hardware) directly, as long as
|
|
# the appropriate network boot infrastructure (TFTP server for `/boot`
|
|
# and NFS server for `/root`) is configured.
|
|
|
|
# The image does not include a bootable SD card but instead prepares the
|
|
# filesystem and boot files for network-based booting. The NixOS
|
|
# configuration will be automatically applied when the system boots.
|
|
|
|
# The generated image will be placed in
|
|
# config.system.build.netImage. This image is intended to be deployed
|
|
# to a TFTP server (for the boot files) and an NFS server (for the root
|
|
# filesystem) for a fully headless, network-booted NixOS system.
|
|
|
|
# Note: This module assumes that you have already set up the TFTP and
|
|
# NFS servers on your network, and the target machine is configured
|
|
# for network booting.
|
|
|
|
{ modulesPath, config, lib, pkgs, ... }:
|
|
|
|
with lib;
|
|
|
|
let
|
|
rootfsImage = pkgs.callPackage (builtins.path { path = ./make-root-fs.nix; }) ({
|
|
inherit (config.netImage) storePaths;
|
|
populateImageCommands = config.netImage.populateRootCommands;
|
|
});
|
|
in
|
|
{
|
|
imports = [ ];
|
|
|
|
options.netImage = {
|
|
rootDirectoryName = mkOption {
|
|
default =
|
|
"${config.netImage.imageBaseName}-${config.system.nixos.label}-${pkgs.stdenv.hostPlatform.system}";
|
|
description = ''
|
|
Name of the generated root directory.
|
|
'';
|
|
};
|
|
|
|
imageBaseName = mkOption {
|
|
default = "nixos-net-image";
|
|
description = ''
|
|
Prefix of the name of the generated image file.
|
|
'';
|
|
};
|
|
|
|
storePaths = mkOption {
|
|
type = with types; listOf package;
|
|
example = literalExpression "[ pkgs.stdenv ]";
|
|
description = ''
|
|
Derivations to be included in the Nix store in the generated Netboot image.
|
|
'';
|
|
};
|
|
|
|
nfsRoot = mkOption {
|
|
type = types.str;
|
|
default = "192.168.0.108:/mnt/nfsshare/${config.netImage.imageBaseName}-${config.system.nixos.label}-${pkgs.stdenv.hostPlatform.system}";
|
|
description = ''
|
|
cmdline.txt nfs parameter for the root filesystem.
|
|
'';
|
|
};
|
|
|
|
nfsOptions = mkOption {
|
|
type = with types; listOf str;
|
|
default = [
|
|
# Disable file locking
|
|
"nolock"
|
|
# Mount the filesystem read-write
|
|
"rw"
|
|
# Use NFS version 3
|
|
"vers=3"
|
|
# Set the read buffer size to 131072 bytes
|
|
"rsize=131072"
|
|
# Set the write buffer size to 131072 bytes
|
|
"wsize=131072"
|
|
# Set the maximum filename length to 255 characters
|
|
"namlen=255"
|
|
# Use hard mounts (retry indefinitely on failure)
|
|
"hard"
|
|
# Disable Access Control Lists
|
|
"noacl"
|
|
# Use TCP as the transport protocol
|
|
"proto=tcp"
|
|
# Set the NFS timeout to 11 tenths of a second
|
|
"timeo=11"
|
|
# Set the number of NFS retransmissions to 3
|
|
"retrans=3"
|
|
# Use the 'sys' security flavor
|
|
"sec=sys"
|
|
# Specify the NFS server address
|
|
# "mountaddr=192.168.0.108"
|
|
# Use NFS mount protocol version 3
|
|
"mountvers=3"
|
|
# Use TCP for the mount protocol
|
|
"mountproto=tcp"
|
|
# Enable local locking
|
|
"local_lock=all"
|
|
# Specify the NFS server address
|
|
# "addr=192.168.0.108"
|
|
# Do not update inode access times on reads
|
|
"noatime"
|
|
# Do not update directory inode access times on reads
|
|
"nodiratime"
|
|
];
|
|
description = ''
|
|
NFS options to use when mounting the root filesystem.
|
|
'';
|
|
};
|
|
|
|
populateFirmwareCommands = mkOption {
|
|
example =
|
|
literalExpression "'' cp \${pkgs.myBootLoader}/u-boot.bin ./ ''";
|
|
description = ''
|
|
Shell commands to populate the ./ directory.
|
|
All files in that directory are copied to the
|
|
tftp files on the Netboot image.
|
|
'';
|
|
};
|
|
|
|
populateRootCommands = mkOption {
|
|
example = literalExpression
|
|
"''\${config.boot.loader.generic-extlinux-compatible.populateCmd} -c \${config.system.build.toplevel} -d ./files/boot''";
|
|
description = ''
|
|
Shell commands to populate the ./files directory.
|
|
All files in that directory are copied to the
|
|
root (/) partition on the Netboot image. Use this to
|
|
populate the ./files/boot (/boot) directory.
|
|
'';
|
|
};
|
|
};
|
|
|
|
config = {
|
|
# net
|
|
networking.useDHCP = lib.mkForce true;
|
|
networking.interfaces.eth0.useDHCP = lib.mkForce true;
|
|
networking.interfaces.wlan0.useDHCP = lib.mkForce false;
|
|
|
|
# boot
|
|
boot.initrd.network.enable = lib.mkForce true;
|
|
boot.initrd.network.flushBeforeStage2 = lib.mkForce false;
|
|
boot.initrd.supportedFilesystems = [
|
|
# Network File System (NFS) support for mounting root over the network
|
|
"nfs"
|
|
# Overlay filesystem for layering file systems
|
|
"overlay"
|
|
];
|
|
|
|
boot.initrd.availableKernelModules = [
|
|
# Network File System (NFS) module
|
|
"nfs"
|
|
# Overlay filesystem module
|
|
"overlay"
|
|
# Broadcom PHY library for Ethernet device support
|
|
"bcm_phy_lib"
|
|
# Broadcom-specific driver module
|
|
"broadcom"
|
|
# Broadcom GENET Ethernet controller driver
|
|
"genet"
|
|
];
|
|
|
|
boot.initrd.kernelModules = [
|
|
# Network File System (NFS) module
|
|
"nfs"
|
|
# Overlay filesystem module
|
|
"overlay"
|
|
# Broadcom PHY library for Ethernet device support
|
|
"bcm_phy_lib"
|
|
# Broadcom-specific driver module
|
|
"broadcom"
|
|
# Broadcom GENET Ethernet controller driver
|
|
"genet"
|
|
];
|
|
|
|
|
|
# fileSystems
|
|
fileSystems = {
|
|
"/boot/firmware" = {
|
|
device = "${config.netImage.nfsRoot}/boot/firmware";
|
|
fsType = "nfs";
|
|
options = config.netImage.nfsOptions;
|
|
neededForBoot = lib.mkForce true;
|
|
};
|
|
"/" = {
|
|
device = "${config.netImage.nfsRoot}";
|
|
fsType = "nfs";
|
|
options = config.netImage.nfsOptions;
|
|
neededForBoot = lib.mkForce true;
|
|
};
|
|
};
|
|
|
|
netImage.storePaths = [ config.system.build.toplevel ];
|
|
|
|
system.build.netImage = pkgs.callPackage
|
|
({ stdenv, util-linux }:
|
|
stdenv.mkDerivation {
|
|
name = config.netImage.rootDirectoryName;
|
|
|
|
nativeBuildInputs = [ util-linux ];
|
|
|
|
buildCommand = ''
|
|
set -e
|
|
set -x
|
|
mkdir -p $out/nix-support $out/net-image
|
|
export rootfs=$out/net-image/os/${config.netImage.rootDirectoryName}
|
|
export bootfs=$out/net-image/boot
|
|
|
|
echo "${pkgs.stdenv.buildPlatform.system}" > $out/nix-support/system
|
|
|
|
# Populate the files intended for NFS
|
|
echo "Exporting rootfs image"
|
|
mkdir -p $rootfs
|
|
cp -r ${rootfsImage}/* $rootfs
|
|
|
|
# Populate the files intended for TFTP
|
|
echo "Exporting rootfs image"
|
|
${config.netImage.populateFirmwareCommands}
|
|
mkdir -p $bootfs
|
|
cp -r . $bootfs
|
|
mkdir -p $rootfs/boot/firmware
|
|
cp -r . $rootfs/boot/firmware
|
|
'';
|
|
})
|
|
{ };
|
|
|
|
boot.postBootCommands = ''
|
|
# On the first boot do some maintenance tasks
|
|
if [ -f /nix-path-registration ]; then
|
|
set -euo pipefail
|
|
set -x
|
|
|
|
# Register the contents of the initial Nix store
|
|
${config.nix.package.out}/bin/nix-store --load-db < /nix-path-registration
|
|
|
|
# nixos-rebuild also requires a "system" profile and an /etc/NIXOS tag.
|
|
touch /etc/NIXOS
|
|
${config.nix.package.out}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
|
|
|
|
# Prevents this from running on later boots.
|
|
rm -f /nix-path-registration
|
|
fi
|
|
'';
|
|
};
|
|
}
|