scripts/ had grown to 10 top-level scripts covering three distinct concerns (sops/age + SSH host-key management, Proxmox deployment, and repo-wide bootstrap/CI) with no grouping. Move the key-management scripts (backup-admin-key.sh, rotate-admin-key.sh, prepare-host-key.sh, sync-host-keys.sh) into scripts/secrets/, and the Proxmox scripts (create-proxmox-resource.sh, configure-nix-cache-client.sh) into scripts/proxmox/; leave env.sh, codex-setup.sh, codex-maintenance.sh, and bump-nixpkgs-release.sh at the top level (frequently hand-typed or pure shared config) and scripts/lib/ as-is. Updates every cross-reference: each moved script's repo_root computation (now one directory deeper), shellcheck source= directives, inter-script paths (create-proxmox-resource.sh's call into sync-host-keys.sh and its remote bootstrap of configure-nix-cache-client.sh on the Proxmox node), and every doc/module mention (CLAUDE.md's Scripts section reorganized to match, README.md, docs/auto-installer.md, docs/proxmox-images.md, modules/installer/common.nix, modules/platforms/lxc.nix). CI workflows need no change -- they only invoke codex-maintenance.sh, which didn't move. Verified via bash -n, shellcheck (no new warnings beyond the pre-existing SC1091/SC2029/SC2095 baseline), and live dry-runs of sync-host-keys.sh --all and create-proxmox-resource.sh --list from their new paths. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
4.4 KiB
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.
scripts/proxmox/create-proxmox-resource.sh --type vm --host <name> automates the
whole walkthrough below (and the equivalent LXC one) end to end, including
host-key handling and building the image directly on the Proxmox node
itself (no local build, no image transfer) — see its --help. The steps
here are what it runs under the hood, useful for doing any of it by hand
or understanding what it does before you trust it against real
infrastructure.
Building
nix build .#nixosConfigurations.proxmox-server.config.system.build.diskoImagesScript
sudo ./result --build-memory 2048
This produces <hostname>.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:
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/secrets/sync-host-keys.sh <hostname>, same
as any other host — see docs/auto-installer.md for the full walkthrough
(it registers the new key in .sops.yaml and re-encrypts the affected
secrets/*.yaml files too, no manual editing needed).
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.
-
Copy the image to the Proxmox host:
scp server.raw root@<proxmox-host>:/var/lib/vz/import/ -
Create an empty VM shell (no disk yet) — replace
<vmid>with a free ID and<storage>with your storage pool's name (pvesm statusor Datacenter → Storage in the web UI):qm create <vmid> --name proxmox-server --memory 2048 --cores 2 \ --net0 virtio,bridge=vmbr0 \ --bios ovmf --machine q35 \ --scsihw virtio-scsi-pci \ --efidisk0 <storage>:1,efitype=4m,pre-enrolled-keys=0(
--efidisk0is required for UEFI — it's where OVMF persists boot-entry NVRAM; without it, systemd-boot's boot entry may not survive a reboot.) -
Import the raw disk into storage:
qm importdisk <vmid> /var/lib/vz/import/server.raw <storage>This prints the resulting disk identifier (e.g.
vm-<vmid>-disk-1). -
Attach it and set it as the boot disk:
qm set <vmid> --scsi0 <storage>:vm-<vmid>-disk-1 qm set <vmid> --boot order=scsi0 -
Boot it:
qm start <vmid>
No install step — it boots straight into the already-activated system.
Why not nix build .#nixosConfigurations.<host>.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.