Cloud-init template + hardened deploy
This lab produces a reusable, hardened cloud-init template you can clone into dozens of identical containers in seconds.
Steps
1. Download a cloud image
cd /tmp
wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
2. Create the base VM shell
qm create 9000 --name ubuntu-template --memory 1024 --cores 2 \
--net0 virtio,bridge=vmbr0 --ostype l26 --scsihw virtio-scsi-single
3. Import the cloud image as a disk
qm importdisk 9000 /tmp/noble-server-cloudimg-amd64.img local-lvm -format qcow2
qm set 9000 --scsi0 local-lvm:vm-9000-disk-0,iothread=1 --boot order=scsi0
4. Add the cloud-init drive
qm set 9000 --ide2 local-lvm:cloudinit
qm set 9000 --serial0 socket --vga serial0
qm set 9000 --agent enabled=1
5. Configure boot-time customisation
qm set 9000 --ipconfig0 ip=dhcp
qm set 9000 --ciuser ubuntu
qm set 9000 --sshkeys ~/.ssh/id_rsa.pub
qm set 9000 --ciupgrade packages
6. Boot and inspect (optional)
qm start 9000
# Wait for the VM to boot
qm guest exec 9000 hostnamectl
qm stop 9000
7. Convert to template
In the GUI: right-click the VM → “Convert to template”.
Or via CLI:
qm template 9000
8. Clone the template to a deployable VM
qm clone 9000 100 --name web-01 --full 0
qm set 100 --ipconfig0 ip=10.0.0.50/24,gw=10.0.0.1
qm set 100 --ciuser deployer
qm set 100 --sshkeys ~/.ssh/deployer.pub
qm start 100
9. Verify the deploy
ssh deployer@10.0.0.50
# Should log in with your key, no password prompt
10. Harden SSH inside the deployed VM
# Inside the VM
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
sudo systemctl restart sshd
# Verify
sudo sshd -T | grep -E 'passwordauth|permitroot'
# Expected: passwordauthentication no; permitrootlogin prohibit-password
11. Bake the hardening into the template (optional but recommended)
If you want every clone to inherit hardening, do step 10 inside the
template VM before converting it, and add a firstboot script:
# Inside the template VM, before qm template
cat > /etc/cloud/cloud.cfg.d/99-hardening.cfg << 'EOF'
runcmd:
- sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
- systemctl restart sshd
EOF
Then re-convert:
qm stop 9000
qm template 9000
Verification
qm listshows the template- Cloned VMs inherit your SSH keys, hostname, and IP
- Password SSH is disabled on every clone
- All clones share the same disk-image footprint (linked clone)
Cleanup
qm stop 100 && qm destroy 100
qm destroy 9000