Whatās causing the don't know how to build these paths?
Any pointers what might be missing here?
disk-image> Installing the system
disk-image> warning: the group 'nixbld' specified in 'build-users-group' does not exist
disk-image> warning: the group 'nixbld' specified in 'build-users-group' does not exist
disk-image> don't know how to build these paths:
disk-image> /nix/store/chwpfw7ihh7xj1ip1qx1g3grmiqk6n95-nixos-system-nixos-25.05.20250208.a79cfe0
disk-image> error: build of '/nix/store/chwpfw7ihh7xj1ip1qx1g3grmiqk6n95-nixos-system-nixos-25.05.20250208.a79cfe0' failed
disk-image> [ 5.223603] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000100
Hi, I did an install there once, I first looked if I could upload a qcow2 image but didnāt find a way, so I simply uploaded the ISO with the NixOS graphical installer, following this doc.
Yeah I also wanted to avoid manual install, on other providers (exoscale, infomaniak public cloud) I could use make-disk-image to create an āready to bootā qcow2 image (with cloud-init enabled), but never used those cloud images definitions. Hope youāll find a way.
edit: I think you could use make-disk-image to build a raw image and upload it with this tool
Unfortunately my nix language skills are failing me to integrate that
Some aspects of this language are just puzzling. I think I will never become a fan of that aspect of nixOS.
outputs =
inputs:
let
# pkgs = nixpkgs.legacyPackages.${system};
# inherit (pkgs) lib;
make-disk-image = import "${inputs.nixpkgs}/nixos/lib/make-disk-image.nix";
in
{
nixosConfigurations = {
nixos-x86 = inputs.nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
# inputs.disko.nixosModules.disko
./configuration.nix
# ./make-disk-image.nix
];
# disko.devices.disk.main.device = "/dev/sda";
};
disk-x86 = make-disk-image {
inherit pkgs lib; # where should these come from?
config = inputs.self.nixosConfigurations.nixos-x86.config;
name = "nixos-cloud-x86";
format = "qcow2-compressed";
copyChannel = false;
additionalSpace = "10G";
};
};
};
Iām running a few machines on Hetzner cloud that I update āon-the-flyā āfrom outsideā with nixos-rebuild --target-host ... switch
The initial deployment goes like this:
Create the nix definition of the machine (importing the qemu-guest.nix and using disko for the partition layout, and in my case agenix for secrets)
Create a machine with the default Ubuntu image
Add the IP to DNS
Get the machineās public key with ssh-keyscan <IP> and add it to the local agenix config so the secrets become available to the machine
Initial deploy with nixos-anywhere --copy-host-keys root@<IP>
After this subsequent updates can be pushed with nixos-rebuild --target-host ... switch
I agree itās a bit of a weird bootstrap step, but nixos-anywhere at least hides it fairly nicely. Apparently hcloud-upload-image does something somewhat similar (though itās nice it creates the machine for you and uses the rescue system). Of course thereās additional trade-offs here, for example you might prefer to bring your own host key instead of relying on the one provisioned by Hetzner.
But the big difference is - it bootstraps the server only once for the image.
I really want to get to the point where I can use terraform/opentofu to create my servers.
After that itās pretty much just running the flake butā¦
Iām not sure I understand what you mean by ābootstrapsā here - that it boots into the rescue system instead of the Ubuntu image? or something else?
How do you manage secrets?
(that sounds neat indeed, though for my use cases I donāt think the added complexity weighs up to the advantages yet)
i didnāt bother with any custom image for hetzner cloud to do this, i just pick an ubuntu image and run nixos-infect with terraform, wait a few minutes, and then i have a nixos machine which is ready to use
Import the nixos-generator module for the desired format into the NixOS configuration. Note that hcloud-upload-image only supports raw disk images, optionally compressed with bzip2 or xz. In my config this looks something like this:
(I pass specialArgs.flake = self; to nixosSystem. self is one of the arguments always passed to a Flakeās output function. )
Access the attribute that has the name of config.formatAttr at config.system.build; in my case this is config.system.build.raw (and not raw-efi!):
{flake, ...}: {
hetzner-disk-image = let
inherit (flake.nixosConfigurations.hetzner) config;
in
config.system.build.${config.formatAttr};
}
I then uploaded the resulting image using hcloud-upload-image.
I compressed it with xz before, but as it turns out, hcloud-upload-image just pipes the image through xz on the remote server when uploading. So this only saves bandwidth during the upload, but not any space on the Hetzner snapshot.
Do note that I use the image to directly create a single autoscaled Kubernetes node connected to my homelab cluster; and not to have a generic NixOS installer.
But I guess you could achieve that by:
creating an image for a minimal working NixOS configurations
creating a server with that image (duh)
upload the system closure (config.system.build.toplevel) for the actual configuration to it
activate it
You could of course still use nixos-anywhere, but it would kexec into a live image and reformat the disk first.