To create a Debian VM that is ready for Ansible using Terraform/OpenTofu, Proxmox VE, and Cloud-init.
You will need to:
- have a running Proxmox server whose console you can reach, via either web GUI or SSH
- have Snippets enabled on at least one storage location with your customized
ci-user.ymlandci-net.ymlfile in it - set up a pool (here,
mypool) on the Proxmox server - set up a token for your Proxmox user (by default,
root@pam) and know its secret - choose a numerical identifier for the VM (here,
10000) - know the unique ID of the default Proxmox network interface (by default,
vmbr0) - download a Debian cloud image of the genericcloud variety in .qcow2 or .raw format and save it somewhere on the Proxmox server
Using the Proxmox node's console, create a "bare minimum" template VM from which Terraform can clone further VMs that are ready for cloud-init. In particular, create no disks; instead, import only the Debian cloud image as scsi0.
qm create 10000 --name debian-template --template 1 --memory 4096 --cores 2 --cpu x86-64-v2-AES \
--machine q35 --vga vmware --bios ovmf --ostype l26 --boot "order=scsi0;net0" \
--net0 "virtio,bridge=vmbr0,firewall=1" --scsihw virtio-scsi-pci \
--scsi0 "local-zfs:0,discard=on,import-from=/path/to/debian-13-genericcloud-amd64.qcow2"
This VM has 4 GB of memory, 2 x86_64/amd64 cores, UEFI, Secure Boot, VirtIO network and SCSI devices, and a VMWare-compatible display adapter (to avoid garbled console, which didn't happen with "default" on Debian 12). Note that UEFI and TPM disks have not yet been added, and the imported image has not been resized to a full-size disk (The Debian 13 "cloud image" is about 3 GB when imported and decompressed at time of writing).
Use Terraform/OpenTofu, Telmate's Proxmox provider, and main.tf to clone and customize the VM before launching it.
Create a terraform.tfvars file and override the default values in the variables file with values that match your own. When you run tofu apply, it creates a full clone of the template VM, so it inherits everything from its parent, then:
- adds
agent = 1, telling Proxmox that the guest agent is installed and running - adds a serial port (as most servers have for console access)
- adds disks for UEFI, TPM, and cloud-init that are stored in
local-zfs - resizes disk
scsi0(the cloud image we imported) to 32 GB - adds custom cloud-init user data and network config, using the YAML files in Snippets
You should get an IPv4 address (such as 192.168.12.34) as an output from Terraform when the VM is up and running. SSH into the VM using this address and the private half of the public key you put where it says <snip> in the ci-user.yml file:
ssh -i ~/.ssh/debian_vm_sshkey_ed25519 -o PreferredAuthentications=publickey [email protected]
If you connect and get an ansibleuser@vmdebian prompt: congratulations! You now have an Ansible-ready Debian VM that's ready for your inventory and playbooks.
If you have improvements or bug fixes, please feel free to share them.
For the cloud-init files: local:snippets/ci-user.yml resolved to /var/lib/vz/snippets/ci-user.yml on my Proxmox host.
As configured, ci-user.yml sets up access via SSH key pairs, but locks the user's password and disables SSH password authentication, so if you can't use a password to get in, that's why.
When the VM starts for the first time, it should ingest the cloud-init files and, after a short while, the VM's console should present you with a vmdebian login: prompt. It appeared to hang during first boot for me, and the QEMU agent took a couple of minutes to start, but give it a couple of minutes; if IP addresses show up in the VM's Summary tab after a short while, you'll know that cloud-init did its thing.
SPDX-License-Identifier: GPL-3.0-only
Copyright © 2025 by R. Dumas. All rights not granted in the GPL version 3 reserved.