Set host name via DHCP when PXE booting

Goal: PXE booting several back-end boxes behind a front-end box to create an “appliance”.

Problem: back-end boxes are not setting their host names from the information being supplied via DHCP. (They all end up with “nixos” as their host name.)

Details:

  • NixOS 24.11
  • Prototyping with VMs via Incus before setting up physical machines
  • pixiecore to supply the kernel image, initrd, and cmdline for PXE booting
  • back-end box and pixiecore configuration:
{inputs, lib, ...}:
let
  system = "x86_64-linux";
  config = { config, pkgs, lib, modulesPath, ... }: {
    imports = [
      "${modulesPath}/installer/netboot/netboot-minimal.nix"
    ];
    config = {
      virtualisation.incus.agent.enable = true;
      system.nixos.tags = [ "netboot" ];
      system.stateVersion = config.system.nixos.release;
      networking.hostName = "";  # get from DHCP rather than set it here
    };
  };
  mkSys = system: config: inputs.nixpkgs.lib.nixosSystem {
    inherit system;
    modules = [ config ];
  };
  sys = mkSys system config;
  build = sys.config.system.build;
in {
  services.pixiecore = {
    enable = true;
    openFirewall = true;
    dhcpNoBind = true;  # use existing DHCP server
    port = 64172;
    statusPort = 64172;

    mode = "boot";
    kernel = "${build.kernel}/bzImage";
    initrd = "${build.netbootRamdisk}/initrd";
    cmdLine = "init=${build.toplevel}/init";
    debug = true;
  };
}
  • MAC addresses set in Incus when VMs are created
  • dnsmasq configuration to assign IP addresses and host names based on MAC addresses
  services.dnsmasq.settings = {
    ...
    host-record = [
      "frontbox,10.0.8.2"
      "backbox1,10.0.8.11"
      ...
    ];
    dhcp-host   = [
      "00:16:3e:00:00:01,backbox1,10.0.8.11,infinite"
      ...
    ];
    ...
  };

According to the hostname man page the order followed in setting the host name is:

  1. cmdline=system.hostname=<name>
  2. /etc/hostname
  3. systemd-hostnamed.service (/etc/machine-info)
  4. localhost

There is no system.hostname on the boot cmdline. The files /etc/nostname and /etc/machine-info do not exist. Somehow the transient host name built into the netboot image is being used.

$ incus exec backbox1 -- bash

# cat /proc/cmdline
kernel initrd=initrd0 init=/nix/store/iaxdv94fwsvd6m29nv611rm0jwnksbxy-nixos-system-unnamed-netboot-24.11.20250412.26d499f/init

# cat /etc/hostname /etc/machine-info
cat: /etc/hostname: No such file or directory
cat: /etc/machine-info: No such file or directory

# hostnamectl | grep hostname
     Static hostname: (unset)
  Transient hostname: nixos

The journal on the front-end box shows that it is correctly sending DHCP option 12 “hostname” as “backbox1”

May 08 15:14:43 frontbox dnsmasq-dhcp[54250]: 402364354 DHCPACK(eth1) 10.0.8.11 00:16:3e:00:00:01 backbox1
May 08 15:14:43 frontbox dnsmasq-dhcp[54250]: 402364354 requested options: 1:netmask, 121:classless-static-route, 3:router,
May 08 15:14:43 frontbox dnsmasq-dhcp[54250]: 402364354 requested options: 6:dns-server, 12:hostname, 15:domain-name,
May 08 15:14:43 frontbox dnsmasq-dhcp[54250]: 402364354 requested options: 26:mtu, 28:broadcast, 33:static-route, 42:ntp-server,
May 08 15:14:43 frontbox dnsmasq-dhcp[54250]: 402364354 requested options: 51:lease-time, 58:T1, 59:T2, 119:domain-search
May 08 15:14:43 frontbox dnsmasq-dhcp[54250]: 402364354 next server: 10.0.8.2
May 08 15:14:43 frontbox dnsmasq-dhcp[54250]: 402364354 sent size:  1 option: 53 message-type  5
May 08 15:14:43 frontbox dnsmasq-dhcp[54250]: 402364354 sent size:  4 option: 54 server-identifier  10.0.8.2
May 08 15:14:43 frontbox dnsmasq-dhcp[54250]: 402364354 sent size:  4 option: 51 lease-time  infinite
May 08 15:14:43 frontbox dnsmasq-dhcp[54250]: 402364354 sent size:  4 option:  1 netmask  255.255.255.0
May 08 15:14:43 frontbox dnsmasq-dhcp[54250]: 402364354 sent size:  4 option: 28 broadcast  10.0.8.255
May 08 15:14:43 frontbox dnsmasq-dhcp[54250]: 402364354 sent size:  4 option: 15 domain-name  internal
May 08 15:14:43 frontbox dnsmasq-dhcp[54250]: 402364354 sent size:  7 option: 12 hostname  backbox1
May 08 15:14:43 frontbox dnsmasq-dhcp[54250]: 402364354 sent size: 16 option: 42 ntp-server  1.1.1.1
May 08 15:14:43 frontbox dnsmasq-dhcp[54250]: 402364354 sent size:  6 option:119 domain-search  08:69:6e:74:65:72:6e:61:6c:00
May 08 15:14:43 frontbox dnsmasq-dhcp[54250]: 402364354 sent size:  4 option:  6 dns-server  10.0.8.2
May 08 15:14:43 frontbox dnsmasq-dhcp[54250]: 402364354 sent size:  4 option:  3 router  10.0.8.1

but still the host name is “nixos”.

Even if a system.hostname option is added to the cmdLine in the pixiecore configuration, the host name of the back-end box is still “nixos” even though the command line says it should be backbox1.

# hostname
nixos

# cat /proc/cmdline 
kernel initrd=initrd0 init=/nix/store/iaxdv94fwsvd6m29nv611rm0jwnksbxy-nixos-system-unnamed-netboot-24.11.20250412.26d499f/init system.hostname=backbox1

What am I missing?

2 Likes

Support for setting the hostname via dhcpcd was very recently added to NixOS (nixos/dhcpcd: fix hostname via DHCP by rnhmjoj · Pull Request #385348 · NixOS/nixpkgs · GitHub). Try using nixos-unstable.

2 Likes

Thanks for the pointer. I got it working after updating to unstable by adding the following to the configuration above:

+      networking.hostName = "";  # get from DHCP rather than set it here
+      networking.dhcpcd.setHostname = true;  # set DHCP hostname
+      security.polkit.enable = true;  # required to set hostname
+      networking.dhcpcd.allowSetuid = true;  # weaken sandbox to allow hostname to be set

Note: it takes about 5s after the VM allows login before the host name is changed.

What is the failure mode if one or two of the last lines are missing? Why don’t we have networking.dhcpd.setHostname = true also enable polkit and setuid?

Good catch. It looks like networking.dhcpcd.allowSetuid = true is being done for me and isn’t needed. It works with commented out. Likewise for security.polkit.enable = true. Neither need to be enabled explicitly.