Netboot: Difference between revisions

From NixOS Wiki
imported>Ichbinjoe
m Building this specifies that mingetty -> getty, and then errors out - rename fixes.
m Format the recently-added example with `nixfmt-rfc-style`.
 
(13 intermediate revisions by 6 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>:
<syntaxHighlight lang=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
</syntaxHighlight>
Run pixiecore:
<syntaxHighlight lang=bash>
<syntaxHighlight lang=bash>
#!/usr/bin/env bash
# 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


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


nix-build --out-link /tmp/netboot - <<'EOF'
# 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
 
</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
let
  bootSystem = import <nixpkgs/nixos> {
    # system = ...;


    configuration = { config, pkgs, lib, ... }: with lib; {
  example-configuration =
       imports = [
    { pkgs, config, ... }:
           <nixpkgs/nixos/modules/installer/netboot/netboot-minimal.nix>
    with pkgs;
      ];
    {
      ## Some useful options for setting up a new system
       config = {
      services.getty.autologinUser = mkForce "root";
        environment.systemPackages = [
      # Enable sshd which gets disabled by netboot-minimal.nix
           mtr
      systemd.services.sshd.wantedBy = mkOverride 0 [ "multi-user.target" ];
          bridge-utils
      # users.users.root.openssh.authorizedKeys.keys = [ ... ];
          vlan
      # console.keyMap = "de";
          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
    ];
   };
   };


   pkgs = import <nixpkgs> {};
   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
in
  pkgs.symlinkJoin {
if legacy then run-dnsmasq else run-pixiecore
    name = "netboot";
 
    paths = with bootSystem.config.system.build; [
</nowiki>
      netbootRamdisk
}}
      kernel
      netbootIpxeScript
    ];
    preferLocalBuild = true;
  }
EOF


n=$(realpath /tmp/netboot)
Usage example:
init=$(grep -ohP 'init=\S+' $n/netboot.ipxe)
<syntaxHighlight lang=bash>
# Build pixiecore runner
nix build -f netboot.nix -o /tmp/run-pixiecore


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


# Start the PXE server.
# Build for some ancient system with a serial console
# These ports need to be open in your firewall:
nix build -f netboot.nix --arg name '"ancient-netboot"' -o /tmp/run-netboot \
# UDP: 67, 69
   --arg configuration 'import ./ancient-config.nix' \
# TCP: 64172
   --arg legacy true --arg proxynets '["10.2.1.0"]' \
sudo /tmp/pixiecore/bin/pixiecore \
   --arg serialconsole true --arg serialport 3 --arg serialspeed 115200
   boot $n/bzImage $n/initrd \
   --cmdline "$init loglevel=4" \
   --debug --dhcp-no-bind --port 64172 --status-port 64172


</syntaxHighlight>
</syntaxHighlight>


=== See also ===
=== See also ===
NixOS: [https://search.nixos.org/options?channel=20.09&from=0&size=30&sort=relevance&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 66: 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