The lab's VM templates, built from phoenix through Saruman's API
(ADR-0074). How to run them is build-the-lab-templates.md; this
page is the map.
| VMID | Template | Source | Installer driven by | Node, and status |
|---|---|---|---|---|
| 901 | tpl-ubuntu-2604 |
ubuntu.pkr.hcl |
autoinstall, cidata disc |
Saruman, built and usable |
| 902 | tpl-kali |
kali.pkr.hcl |
Debian preseed, Packer HTTP | ifrit, waits for the host (#790) |
| 903 | tpl-debian-13 |
debian.pkr.hcl |
Debian preseed, Packer HTTP | Saruman, built twice and smoke-tested, 2026-10-08 (#920) |
| 904 | tpl-fedora-server |
fedora.pkr.hcl |
Kickstart, OEMDRV disc |
Saruman, built twice and smoke-tested, 2026-10-08 (#920) |
| 905 | tpl-opensuse-tw |
opensuse.pkr.hcl |
AutoYaST, OEMDRV disc |
Saruman, built twice and smoke-tested, 2026-10-09 (#920) |
| 906 | tpl-arch |
arch.pkr.hcl |
the live ISO's cloud-init on cidata, then arch/install.sh over SSH |
Saruman, built twice and smoke-tested, 2026-10-09 (#920) |
| 907 | tpl-alpine |
alpine.pkr.hcl |
Alpine's cloud image, imported as 917 and cloned (proxmox-clone) |
Saruman, built twice and smoke-tested, 2026-10-09 (#920) |
| 908 | tpl-gentoo |
gentoo.pkr.hcl |
Gentoo's cloud image, imported as 918 and cloned (proxmox-clone) |
Saruman, built twice and smoke-tested, 2026-10-09 (#920) |
| 909 | tpl-nixos |
nixos.pkr.hcl |
the minimal ISO, a typed boot command, then nixos/install.sh over SSH |
Saruman, built twice and smoke-tested, 2026-10-09 (#920) |
| 910 | tpl-kali-saruman |
kali.pkr.hcl (kali-saruman) |
Debian preseed, Packer HTTP: 902's build on Saruman |
Saruman, written; garuda's base (#921, ADR-0091) |
| 911 | tpl-win11-pro |
windows.pkr.hcl |
Autounattend, ANSWERS disc |
Saruman, built and smoke-tested (rebuilt 2026-10-07, #846); also the base for dot-windows |
| 912 | tpl-ws2025-eval |
windows.pkr.hcl |
Autounattend, ANSWERS disc |
Saruman, built and smoke-tested (rebuilt 2026-10-07 with the SetupComplete.cmd fix, #846) |
set -a; . ~/.config/proxmox/phoenix.env; set +a
packer init packer/
packer build -force -only='windows.proxmox-iso.ws2025-eval' packer/
scripts/packer-smoke.sh 912versions.pkr.hcl: the Proxmox plugin, pinned exactly.variables.pkr.hcl: node, storage, bridge and ISO names. The credential defaults readphoenix.env's own variable names, so nothing is spelled twice. Nothing secret has a default.ubuntu/user-data.pkrtpl: autoinstall. Thepackerbuild user is key-only and deleted at the end of the build.kali/preseed.cfg.pkrtpl: the same shape for Debian's installer.debian/preseed.cfg.pkrtpl: Kali's preseed with Debian trixie's mirror, for the dotfiles-Debian VM (ADR-0090). Served over HTTP, as Kali's is.fedora/ks.cfg.pkrtpl: the kickstart for Fedora Server, on a disc labelledOEMDRV, which Anaconda reads with no boot argument.opensuse/autoinst.xml.pkrtpl: the AutoYaST profile for Tumbleweed's NET installer, on a disc labelledOEMDRVnamed on the kernel line.nixos.pkr.hcl,nixos/install.shandnixos/configuration.nix: NixOS is installed by evaluating a configuration, not by answering questions. The build types its way into the ISO's root shell, then installs with the committed configuration: systemd-boot without Secure Boot, cloud-init on networkd, the agent, key-only sshd, and sudo for cloud-init's user.alpine.pkr.hclandgentoo.pkr.hcl: not ISO installs. Each clones a staging template thatscripts/import-cloud-template.shimported, as root onSaruman, from the project's signed cloud image (917, 918). It adds the guest agent and what the dotfiles layer needs, and deletes the image's default user. The images carry no agent, so the build gives its clone a fixed address,cloud_image_build_address, and the two builds take turns.arch/user-data.pkrtplandarch/install.sh: Arch has no installer to answer. The first lets Packer into the live ISO, and the second installs the disk over that session. Secure Boot is off for Arch, the one template so far without a Microsoft-signed shim.windows/autounattend.xml.pkrtpl: one file for both editions, rendered with the image name, the VirtIO driver folder and the product key.windows/unattend-oobe.xml.pkrtpl: the answer file a clone's OOBE reads after sysprep.windows/scripts/bootstrap.ps1: runs at the build's one autologon. It installs the guest tools first, because Packer finds the address through the agent, and opens WinRM second: HTTPS on 5986 with a self-signed certificate, admittingphoenixalone. The HTTP listener and Windows' own 5985 rules thatEnable-PSRemotingadds are removed (#846). Read throughtemplatefile()forphoenix's address, so it may not contain${or%{.windows/scripts/openssh.ps1: installs the OpenSSH server, disabled and key-only, withphoenix's key and a firewall rule admittingphoenixalone. It is howansible/reaches a clone (ADR-0077).windows/scripts/SetupComplete.cmd: runs once on each clone, closes that WinRM again (listener, certificate, rule and service), and startssshd, which generates the clone's own host keys.windows/scripts/sysprep.ps1: starts sysprep/generalize /oobe /shutdownas a one-off scheduled task as SYSTEM, and returns once it is running. Not over WinRM: generalising removes the network adapter, and Windows then kills whatever the dead session started, sysprep included.SetupComplete.cmddeletes the task on each clone.windows/scripts/wait-for-sysprep.sh: runs onphoenix(shell-local) and polls the API until the guest has powered itself off, which is sysprep saying it finished. The builder then converts it. Its shutdown of an already-stopped VM is a no-op that Proxmox endsOK.
- Full clones only.
-forcerebuilds a template at the same VMID, which a linked clone would block. - A template is an OS, not a guest. No address, no name, no domain join,
no licence gauge. Those are
ansible/'s (#448), and ADR-0029 says what they are. The one exception is the way in:sshdandphoenix's key are in the image, because a clone with no way in cannot be configured by anything. - LLMNR, NetBIOS, IPv6 and WPAD are left alone in every answer file. The lab domain exists to have them (ADR-0029).
- CI proves it parses,
phoenixproves it builds.scripts/lint.shrunspacker fmt -checkandpacker validate -syntax-onlyfrom the imagestacks/observability/compose.yamlpins. Neither needs a plugin or a Proxmox. A change here is only finished once the runbook's §6 smoke test has passed against a real build.