(I managed to figure it out, see answer below.)
The solution is to add extra initrd udev rules:
nix-build --out-link /tmp/vm - <<'EOF'
(import <nixpkgs/nixos> {
configuration = { lib, pkgs, ... }: with lib; {
boot.initrd = {
extraUdevRulesCommands = ''
cp -v ${pkgs.systemd}/lib/udev/rules.d/75-net-description.rules $out
cp -v ${pkgs.path}/nixos/modules/services/hardware/80-net-setup-link.rules $out
'';
preLVMCommands = ''
echo
echo "Yeah, predictable names:"
ls -l /sys/class/net
# Pause stage 1
read
'';
};
};
}).vm
EOF
# Run VM attached to console. To quit, press (Ctrl + A), c, q, <enter>
NIX_DISK_IMAGE=/tmp/vmimg /tmp/vm/bin/run-*-vm -m 1024 -smp 2 -nographic -append 'console=ttyS0'
This is what I use, and it works for me on Hetzner hosts, at least.
boot.kernelParams = [ "net.ifnames=0" ];
This option explicitly disables predictable names.
Without net.ifnames=0
, a device named eth0
by the kernel may be renamed to, e.g., ens3
. For example, here’s a line from dmesg
on one of my Vultr host:
[ 4.232924] virtio_net virtio0 ens3: renamed from eth0
Vultr hosts are virtualized, but this also happens on bare metal hosts.
This is particularly problematic on hosts without DHCP support (e.g., Hetzner dedicated instances) when the NixOS installer sees the original kernel name, but upon rebooting with a newer kernel, the device is renamed, and now you don’t have any network connectivity to your newly-installed machine.
The message ens3: renamed from eth0
is from udev in boot stage 2, which renames interfaces from stage 1 that are not brought up according to its extended predictable name rules.
To disable renaming, better use the more expressive networking.usePredictableInterfaceNames = false
instead of setting the kernel parameter net.ifnames=0
.
But the goal of this thread is the opposite: Enforce predictable names even in stage 1.