From feee2f167957f2ba2ad23189ef14486e762b1c4f Mon Sep 17 00:00:00 2001 From: beatzaplenty Date: Mon, 20 Jul 2026 07:01:33 +1000 Subject: [PATCH] Add Proxmox VM disk-image building; fix disko confirmation bypass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit modules/disko/proxmox.nix gains imageSize (20G default) and a per-host imageName (networking.hostName, so every proxmox-* host produces a distinctly named image instead of an identical main.raw). This is the same disko.devices config already used to format a real disk on install, so it's available for every proxmox-* target with no per-host changes needed: nix build .#nixosConfigurations..config.system.build.diskoImagesScript sudo ./result --build-memory 2048 docs/proxmox-images.md covers building, host-key pre-seeding via disko's --pre-format-files (same host-keys/ workflow as the installer and LXC tarball paths), and the qm import/attach sequence for deploying the result to Proxmox. Also fixes a real bug in auto-install.sh found while testing: the disko confirmation bypass used --yes, which disko's CLI doesn't recognize at all (the actual flag is --yes-wipe-all-disks) — so the "skip confirmation" flag was silently a no-op and the interactive prompt kept appearing regardless. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01La55Nsss8jZ7ZuzUV9mfot --- docs/proxmox-images.md | 107 +++++++++++++++++++++++++++++++++++ modules/disko/proxmox.nix | 12 +++- modules/installer/common.nix | 2 +- 3 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 docs/proxmox-images.md diff --git a/docs/proxmox-images.md b/docs/proxmox-images.md new file mode 100644 index 0000000..99b2bad --- /dev/null +++ b/docs/proxmox-images.md @@ -0,0 +1,107 @@ +# Proxmox VM disk images + +`proxmox-*` hosts (VM platform, not `lxc-*`) can be built as standalone, +ready-to-attach `.raw` disk images via disko's own image-builder — no +`nixos-install`, no live installer boot. This uses the same `disko.devices` +config (`modules/disko/proxmox.nix`) already used to format a real disk on +install, so there's nothing host-specific to write; it's available for every +`proxmox-*` target automatically. + +## Building + +```sh +nix build .#nixosConfigurations.proxmox-server.config.system.build.diskoImagesScript +sudo ./result --build-memory 2048 +``` + +This produces `.raw` in the current directory (e.g. `server.raw` +for `proxmox-server`, matching `networking.hostName`, not the flake attribute +name — every `proxmox-*` host gets a distinctly named image instead of all +of them producing an identical `main.raw`). The script builds inside a +temporary QEMU VM and moves the finished image out to the working directory +when done; `--build-memory` controls how much RAM that build VM gets. + +`disko.devices.disk.main.imageSize` (currently `20G`, in +`modules/disko/proxmox.nix`) sets the image's total size — disko doesn't +support auto-resizing, so this needs to comfortably fit ESP + swap + root at +build time. Grow the virtual disk (and resize the filesystem) in Proxmox +after attaching if a host needs more than that; this is the normal way to +size these images, not a one-time decision to get exactly right up front. + +## Host keys + +The disko image script runs a real activation pass inside its temporary +build VM while constructing the image — the same sops-nix +activation-before-first-boot problem the installer and LXC tarball workflows +have (see `docs/auto-installer.md`) applies here too, unmodified. Disko has +a native mechanism for it: + +```sh +sudo ./result \ + --pre-format-files host-keys/server_ssh_host_ed25519_key /etc/ssh/ssh_host_ed25519_key \ + --pre-format-files host-keys/server_ssh_host_ed25519_key.pub /etc/ssh/ssh_host_ed25519_key.pub \ + --build-memory 2048 +``` + +Generate the key first with `scripts/prepare-host-key.sh `, same +as any other host — see `docs/auto-installer.md` for the full sops.yaml +registration walkthrough. + +## Deploying to Proxmox + +The image needs **UEFI (OVMF)**, not Proxmox's default SeaBIOS — +`modules/boot/efi.nix` uses `systemd-boot`, which only works with UEFI +firmware. `virtio-scsi` is safe to use as the disk bus: +`hardware-configuration/vm/proxmox.nix` already includes `virtio_scsi` in +its initrd kernel modules. + +1. Copy the image to the Proxmox host: + + ```sh + scp server.raw root@:/var/lib/vz/import/ + ``` + +2. Create an empty VM shell (no disk yet) — replace `` with a free ID + and `` with your storage pool's name (`pvesm status` or + Datacenter → Storage in the web UI): + + ```sh + qm create --name proxmox-server --memory 2048 --cores 2 \ + --net0 virtio,bridge=vmbr0 \ + --bios ovmf --machine q35 \ + --scsihw virtio-scsi-pci \ + --efidisk0 :1,efitype=4m,pre-enrolled-keys=0 + ``` + + (`--efidisk0` is required for UEFI — it's where OVMF persists boot-entry + NVRAM; without it, systemd-boot's boot entry may not survive a reboot.) + +3. Import the raw disk into storage: + + ```sh + qm importdisk /var/lib/vz/import/server.raw + ``` + + This prints the resulting disk identifier (e.g. `vm--disk-1`). + +4. Attach it and set it as the boot disk: + + ```sh + qm set --scsi0 :vm--disk-1 + qm set --boot order=scsi0 + ``` + +5. Boot it: + + ```sh + qm start + ``` + +No install step — it boots straight into the already-activated system. + +## Why not `nix build .#nixosConfigurations..config.system.build.vm`? + +That's a different, unrelated feature — `system.build.vm` (`nixos-rebuild +build-vm`) produces an ephemeral QEMU script for locally testing a +configuration, not a distributable disk image. It's not part of this +workflow. diff --git a/modules/disko/proxmox.nix b/modules/disko/proxmox.nix index bc55250..d2dd4c8 100644 --- a/modules/disko/proxmox.nix +++ b/modules/disko/proxmox.nix @@ -1,4 +1,4 @@ -_: +{ config, ... }: { disko.devices = { @@ -6,6 +6,16 @@ _: type = "disk"; device = "/dev/sda"; + # Only used when building a standalone disk image directly (`nix build + # .#nixosConfigurations..config.system.build.diskoImagesScript`) + # rather than formatting a real device — see docs/proxmox-images.md. + # imageSize sets the .raw file's total size (root's "100%" below fills + # whatever's left after ESP + swap within it); imageName keeps each + # host's image distinctly named instead of every proxmox-* host + # producing an identical "main.raw". + imageSize = "20G"; + imageName = config.networking.hostName; + content = { type = "gpt"; diff --git a/modules/installer/common.nix b/modules/installer/common.nix index 6ad2626..e7e1667 100644 --- a/modules/installer/common.nix +++ b/modules/installer/common.nix @@ -123,7 +123,7 @@ if nix eval --refresh --json --extra-experimental-features "flakes nix-command" "''${nix_extra_opts[@]}" "''${FLAKE_BASE_URL}#nixosConfigurations.''${choice}.config.disko.devices.disk.main.device" >/dev/null 2>&1; then disko --mode destroy,format,mount \ - --flake "''${FLAKE_BASE_URL}#''${choice}" "''${nix_extra_opts[@]}" --yes + --flake "''${FLAKE_BASE_URL}#''${choice}" "''${nix_extra_opts[@]}" --yes-wipe-all-disks else # No raw disk to partition — true for every LXC container, which has # no block device visible from inside it, only its already-mounted