Netboot: Difference between revisions

From NixOS Wiki
imported>Erikarvstedt
Improve example: Move script definition to system build. Fix old `nix build` syntax. Add firewall commands.
m Format the recently-added example with `nixfmt-rfc-style`.
 
(9 intermediate revisions by 4 users not shown)
Line 2: Line 2:


=== Example ===
=== Example ===
This example uses [https://github.com/danderson/netboot/tree/master/pixiecore Pixiecore] for hosting, which works in an ordinary network environment with an existing DHCP server.
This example uses [https://github.com/danderson/netboot/tree/main/pixiecore Pixiecore] for hosting, which works in an ordinary network environment with an existing DHCP server.


Create file <code>system.nix</code>:
Create file <code>system.nix</code>:
Line 12: Line 12:
   sys = nixpkgs.lib.nixosSystem {
   sys = nixpkgs.lib.nixosSystem {
     system = "x86_64-linux";
     system = "x86_64-linux";
     modules = [
     modules = [
      pixiecoreNetboot
       ({ config, pkgs, lib, modulesPath, ... }: {
       ({ config, pkgs, lib, ... }: with lib; {
        imports = [
          (modulesPath + "/installer/netboot/netboot-minimal.nix")
        ];
         config = {
         config = {
           ## Some useful options for setting up a new system
           ## Some useful options for setting up a new system
           # services.getty.autologinUser = mkForce "root";
           # services.getty.autologinUser = lib.mkForce "root";
           # users.users.root.openssh.authorizedKeys.keys = [ ... ];
           # users.users.root.openssh.authorizedKeys.keys = [ ... ];
           # console.keyMap = "de";
           # console.keyMap = "de";
Line 29: Line 30:
   };
   };


   pixiecoreNetboot = { config, pkgs, lib, modulesPath, ... }: {
   run-pixiecore = let
    imports = [
    hostPkgs = if sys.pkgs.system == builtins.currentSystem
      (modulesPath + "/installer/netboot/netboot-minimal.nix")
              then sys.pkgs
    ];
              else nixpkgs.legacyPackages.${builtins.currentSystem};
 
     build = sys.config.system.build;
     system.build.run-pixiecore = let
  in hostPkgs.writers.writeBash "run-pixiecore" ''
      build = config.system.build;
    exec ${hostPkgs.pixiecore}/bin/pixiecore \
    in
      boot ${build.kernel}/bzImage ${build.netbootRamdisk}/initrd \
      pkgs.writers.writeBash "run-pixiecore" ''
      --cmdline "init=${build.toplevel}/init loglevel=4" \
        exec ${lib.getExe pkgs.pixiecore} \
      --debug --dhcp-no-bind \
          boot ${build.kernel}/bzImage ${build.netbootRamdisk}/initrd \
      --port 64172 --status-port 64172 "$@"
          --cmdline "init=${build.toplevel}/init loglevel=4" \
  '';
          --debug --dhcp-no-bind \
          --port 64172 --status-port 64172 "$@"
      '';
  };
in
in
   sys.config.system.build.run-pixiecore
   run-pixiecore
</syntaxHighlight>
</syntaxHighlight>


Line 55: Line 52:


# Open required firewall ports
# Open required firewall ports
sudo iptables -I nixos-fw -p udp -m multiport --dports 67,69,4011 -j ACCEPT
sudo iptables -w -I nixos-fw -p udp -m multiport --dports 67,69,4011 -j ACCEPT
sudo iptables -I nixos-fw -p tcp -m tcp --dport 64172 -j ACCEPT
sudo iptables -w -I nixos-fw -p tcp -m tcp --dport 64172 -j ACCEPT


# Run pixiecore
# Run pixiecore
Line 62: Line 59:


# Close ports
# Close ports
sudo iptables -D nixos-fw -p udp -m multiport --dports 67,69,4011 -j ACCEPT
sudo iptables -w -D nixos-fw -p udp -m multiport --dports 67,69,4011 -j ACCEPT
sudo iptables -D nixos-fw -p tcp -m tcp --dport 64172 -j ACCEPT
sudo iptables -w -D nixos-fw -p tcp -m tcp --dport 64172 -j ACCEPT
 
</syntaxHighlight>
 
=== Another example ===
{{file|netboot.nix|nix|
<nowiki>
{
  name ? "netboot",
  arch ? "x86_64-linux",
  configuration ? _: { }, # --arg configuration 'import ./netboot-config.nix'
  legacy ? false, # variation with pxelinux and dnsmasq for older systems
  cmdline ? [ ],
  loglevel ? 4,
  pixiecoreport ? 64172,
  proxynets ? [ "192.168.0.0" ],
  serialconsole ? false,
  serialport ? 0,
  serialspeed ? 9600,
  nixpkgs ? import <nixpkgs> { },
  ...
}:
with nixpkgs;
with lib;
let
 
  example-configuration =
    { pkgs, config, ... }:
    with pkgs;
    {
      config = {
        environment.systemPackages = [
          mtr
          bridge-utils
          vlan
          ethtool
          jwhois
          sipcalc
          netcat-openbsd
          tsocks
          psmisc
          pciutils
          usbutils
          lm_sensors
          dmidecode
          microcom
          unar
          mkpasswd
          ripgrep
          wget
          rsync
          sshfs-fuse
          iperf3
          mc
          mutt
          borgbackup
          rxvt_unicode.terminfo
        ];
        # users.users.nixos.openssh.authorizedKeys.keys = [ … ];
        # services.openssh = { ports = [2]; settings.PasswordAuthentication = false; };
        # virtualisation.lxc.enable = true;
      };
    };
 
  config = import <nixpkgs/nixos/lib/eval-config.nix> {
    # see <nixpkgs/nixos/release.nix>
    system = arch;
    modules = [
      <nixpkgs/nixos/modules/installer/netboot/netboot-minimal.nix>
      version-module
      example-configuration
      configuration
    ];
  };
 
  version-module =
    { config, ... }:
    {
      system.stateVersion = config.system.nixos.version; # be quiet
      system.nixos.tags = [ name ];
    };
 
  run-pixiecore = writeShellScript "${name}-run-pixiecore" ''
    exec ${pixiecore}/bin/pixiecore \
      boot ${kernel} ${initrd} \
      --cmdline "${cmd-line}" \
      --debug --dhcp-no-bind --log-timestamps \
      --port ${toString pixiecoreport} \
      --status-port ${toString pixiecoreport} "$@"
  '';
 
  run-dnsmasq = writeShellScript "${name}-run-dnsmasq" ''
    exec ${dnsmasq}/bin/dnsmasq \
      -d -k --no-daemon -C "${dnsmasq-conf}" "$@"
  '';
 
  tftp-root = linkFarm "${name}-tftp-root" (
    mapAttrsToList (name: path: { inherit name path; }) {
      "pxelinux.cfg/default" = pxelinux-cfg;
      "pxelinux.0" = "syslinux/pxelinux.0";
      "syslinux" = "${syslinux}/share/syslinux";
      "bzImage" = kernel;
      "initrd" = initrd;
    }
  );
 
  dnsmasq-conf = writeText "${name}-dnsmasq-conf" ''
    pxe-prompt="Booting NixOS..",1
    local-service=net
    dhcp-boot=pxelinux.0
    ${flip concatMapStrings proxynets (net: ''
      dhcp-range=${net},proxy
    '')}
    dhcp-no-override
    dhcp-leasefile=/dev/null
    log-dhcp
    enable-tftp
    tftp-port-range=6900,6999
    tftp-root=${tftp-root}
  '';
 
  cmd-line = concatStringsSep " " (
    [
      "init=${build.toplevel}/init"
      "loglevel=${toString loglevel}"
    ]
    ++ optional serialconsole "console=ttyS${toString serialport},${toString serialspeed}"
    ++ cmdline
  );
 
  pxelinux-cfg = writeText "${name}-pxelinux.cfg" ''
    ${optionalString serialconsole "serial ${toString serialport} ${toString serialspeed}"}
    console 1
    prompt 1
    timeout 37
    default NixOS
    label NixOS
      kernel bzImage
      append initrd=initrd ${cmd-line}
  '';
 
  build = config.config.system.build;
  kernel = "${build.kernel}/${kernel-target}";
  kernel-target = config.pkgs.stdenv.hostPlatform.linux-kernel.target;
  initrd = "${build.netbootRamdisk}/initrd";
 
in
if legacy then run-dnsmasq else run-pixiecore
 
</nowiki>
}}
 
Usage example:
<syntaxHighlight lang=bash>
# Build pixiecore runner
nix build -f netboot.nix -o /tmp/run-pixiecore
 
# Build dnsmasq + pxelinux runner
nix build -f netboot.nix --arg legacy true -o /tmp/run-dnsmasq
 
# Build for some ancient system with a serial console
nix build -f netboot.nix --arg name '"ancient-netboot"' -o /tmp/run-netboot \
  --arg configuration 'import ./ancient-config.nix' \
  --arg legacy true --arg proxynets '["10.2.1.0"]' \
  --arg serialconsole true --arg serialport 3 --arg serialspeed 115200
 
</syntaxHighlight>
</syntaxHighlight>


=== See also ===
=== See also ===
NixOS: [https://search.nixos.org/options?channel=22.11&from=0&size=30&sort=relevance&type=packages&query=services.pixiecore Pixiecore module].
NixOS: [https://search.nixos.org/options?channel=23.11&from=0&size=30&sort=relevance&type=packages&query=services.pixiecore Pixiecore module].


NixOS manual: [https://nixos.org/nixos/manual/index.html#sec-booting-from-pxe PXE booting].
NixOS manual: [https://nixos.org/nixos/manual/index.html#sec-booting-from-pxe PXE booting].
Line 76: Line 238:


<b>Note:</b> Your iPXE must be recent enough to support https:// links
<b>Note:</b> Your iPXE must be recent enough to support https:// links
[[Category:Booting]]

Latest revision as of 14:48, 30 October 2024

Building and serving a netboot image

Example

This example uses Pixiecore for hosting, which works in an ordinary network environment with an existing DHCP server.

Create file system.nix:

let
  # NixOS 22.11 as of 2023-01-12
  nixpkgs = builtins.getFlake "github:nixos/nixpkgs/54644f409ab471e87014bb305eac8c50190bcf48";

  sys = nixpkgs.lib.nixosSystem {
    system = "x86_64-linux";
    modules = [
      ({ config, pkgs, lib, modulesPath, ... }: {
        imports = [
          (modulesPath + "/installer/netboot/netboot-minimal.nix")
        ];
        config = {
          ## Some useful options for setting up a new system
          # services.getty.autologinUser = lib.mkForce "root";
          # users.users.root.openssh.authorizedKeys.keys = [ ... ];
          # console.keyMap = "de";
          # hardware.video.hidpi.enable = true;

          system.stateVersion = config.system.nixos.release;
        };
      })
    ];
  };

  run-pixiecore = let
    hostPkgs = if sys.pkgs.system == builtins.currentSystem
               then sys.pkgs
               else nixpkgs.legacyPackages.${builtins.currentSystem};
    build = sys.config.system.build;
  in hostPkgs.writers.writeBash "run-pixiecore" ''
    exec ${hostPkgs.pixiecore}/bin/pixiecore \
      boot ${build.kernel}/bzImage ${build.netbootRamdisk}/initrd \
      --cmdline "init=${build.toplevel}/init loglevel=4" \
      --debug --dhcp-no-bind \
      --port 64172 --status-port 64172 "$@"
  '';
in
  run-pixiecore

Run pixiecore:

# Build pixiecore runner
nix build -f system.nix -o /tmp/run-pixiecore

# Open required firewall ports
sudo iptables -w -I nixos-fw -p udp -m multiport --dports 67,69,4011 -j ACCEPT
sudo iptables -w -I nixos-fw -p tcp -m tcp --dport 64172 -j ACCEPT

# Run pixiecore
sudo $(realpath /tmp/run-pixiecore)

# Close ports
sudo iptables -w -D nixos-fw -p udp -m multiport --dports 67,69,4011 -j ACCEPT
sudo iptables -w -D nixos-fw -p tcp -m tcp --dport 64172 -j ACCEPT

Another example

netboot.nix
{
  name ? "netboot",
  arch ? "x86_64-linux",
  configuration ? _: { }, # --arg configuration 'import ./netboot-config.nix'
  legacy ? false, # variation with pxelinux and dnsmasq for older systems
  cmdline ? [ ],
  loglevel ? 4,
  pixiecoreport ? 64172,
  proxynets ? [ "192.168.0.0" ],
  serialconsole ? false,
  serialport ? 0,
  serialspeed ? 9600,
  nixpkgs ? import &lt;nixpkgs&gt; { },
  ...
}:
with nixpkgs;
with lib;
let

  example-configuration =
    { pkgs, config, ... }:
    with pkgs;
    {
      config = {
        environment.systemPackages = [
          mtr
          bridge-utils
          vlan
          ethtool
          jwhois
          sipcalc
          netcat-openbsd
          tsocks
          psmisc
          pciutils
          usbutils
          lm_sensors
          dmidecode
          microcom
          unar
          mkpasswd
          ripgrep
          wget
          rsync
          sshfs-fuse
          iperf3
          mc
          mutt
          borgbackup
          rxvt_unicode.terminfo
        ];
        # users.users.nixos.openssh.authorizedKeys.keys = [ … ];
        # services.openssh = { ports = [2]; settings.PasswordAuthentication = false; };
        # virtualisation.lxc.enable = true;
      };
    };

  config = import &lt;nixpkgs/nixos/lib/eval-config.nix&gt; {
    # see &lt;nixpkgs/nixos/release.nix&gt;
    system = arch;
    modules = [
      &lt;nixpkgs/nixos/modules/installer/netboot/netboot-minimal.nix&gt;
      version-module
      example-configuration
      configuration
    ];
  };

  version-module =
    { config, ... }:
    {
      system.stateVersion = config.system.nixos.version; # be quiet
      system.nixos.tags = [ name ];
    };

  run-pixiecore = writeShellScript "${name&#125;-run-pixiecore" ''
    exec ${pixiecore}/bin/pixiecore \
      boot ${kernel} ${initrd} \
      --cmdline "${cmd-line}" \
      --debug --dhcp-no-bind --log-timestamps \
      --port ${toString pixiecoreport} \
      --status-port ${toString pixiecoreport} "$@"
  '';

  run-dnsmasq = writeShellScript "${name&#125;-run-dnsmasq" ''
    exec ${dnsmasq}/bin/dnsmasq \
      -d -k --no-daemon -C "${dnsmasq-conf}" "$@"
  '';

  tftp-root = linkFarm "${name&#125;-tftp-root" (
    mapAttrsToList (name: path: { inherit name path; }) {
      "pxelinux.cfg/default" = pxelinux-cfg;
      "pxelinux.0" = "syslinux/pxelinux.0";
      "syslinux" = "${syslinux}/share/syslinux";
      "bzImage" = kernel;
      "initrd" = initrd;
    }
  );

  dnsmasq-conf = writeText "${name&#125;-dnsmasq-conf" ''
    pxe-prompt="Booting NixOS..",1
    local-service=net
    dhcp-boot=pxelinux.0
    ${flip concatMapStrings proxynets (net: ''
      dhcp-range=${net},proxy
    '')}
    dhcp-no-override
    dhcp-leasefile=/dev/null
    log-dhcp
    enable-tftp
    tftp-port-range=6900,6999
    tftp-root=${tftp-root}
  '';

  cmd-line = concatStringsSep " " (
    [
      "init=${build.toplevel}/init"
      "loglevel=${toString loglevel}"
    ]
    ++ optional serialconsole "console=ttyS${toString serialport},${toString serialspeed}"
    ++ cmdline
  );

  pxelinux-cfg = writeText "${name&#125;-pxelinux.cfg" ''
    ${optionalString serialconsole "serial ${toString serialport} ${toString serialspeed}"}
    console 1
    prompt 1
    timeout 37
    default NixOS
    label NixOS
      kernel bzImage
      append initrd=initrd ${cmd-line}
  '';

  build = config.config.system.build;
  kernel = "${build.kernel}/${kernel-target}";
  kernel-target = config.pkgs.stdenv.hostPlatform.linux-kernel.target;
  initrd = "${build.netbootRamdisk}/initrd";

in
if legacy then run-dnsmasq else run-pixiecore

Usage example:

# Build pixiecore runner
nix build -f netboot.nix -o /tmp/run-pixiecore

# Build dnsmasq + pxelinux runner
nix build -f netboot.nix --arg legacy true -o /tmp/run-dnsmasq

# Build for some ancient system with a serial console
nix build -f netboot.nix --arg name '"ancient-netboot"' -o /tmp/run-netboot \
  --arg configuration 'import ./ancient-config.nix' \
  --arg legacy true --arg proxynets '["10.2.1.0"]' \
  --arg serialconsole true --arg serialport 3 --arg serialspeed 115200

See also

NixOS: Pixiecore module.

NixOS manual: PXE booting.

netboot.xyz

There is now official netboot.xyz support. Just select NixOS from Linux installs and you should be ready to go.

Note: Your iPXE must be recent enough to support https:// links