NoRocketScience Logo
Published on

Deploy Proxmox virtual machines using Cloud-init

  • avatar
    Thomas Brandstetter

Due to performance problems with my ESXI homelab I decided to give the open source solution Proxmox a try. One of my goals was to install all my virtual machines with the Cloud-init solution. With Cloud-init it is possible to inject informations such as ssh keys, network information or user profiles in an standarized way at boot time. The benefit of using Cloud-init is the pre-provisioning of necessary configuration items such as a static ip address or a default user with activated ssh public key authentication. Furthermore, this kind of provisioning helps a lot for further automation steps with Ansible or even complete CI/CD pipelines in Gitlab, Jenkins etc. But first, let's start with the VM provisioning steps in Proxmox.

Location of Cloud-Init images

Nowadays, nearly all big Linux distributions offer ready to use Cloud-init images. Here is a short list of mirrors where you can choose the distribution that fits your needs:

Create your template

Download the image on your Proxmox server (I'm using Ubuntu for my VMs)


Define your virtual machine which you're like to use as a template

qm create 9000 --name "ubuntu-1804-cloudinit-template" --memory 2048 --net0 virtio,bridge=vmbr0

With this command you have created a new virtual machine with the id 9000 (has to be unique in the Proxmox ecosystem), 2 gigabyte of ram and a bridge network using the virtio controller.

(Important for Ubuntu!) Rename your image suffix

mv bionic-server-cloudimg-amd64.img bionic-server-cloudimg-amd64.qcow2

I don't know why, but if import the disk image using the *.img suffix, Proxmox is unable to boot from this image. I have to open a bug report for that.

Import the disk image in the local Proxmox storage

qm importdisk 9000 bionic-server-cloudimg-amd64.qcow2 local-lvm

The commandline utility uploads the image in the local Proxmox storage and assigns a unique name (for the virtual machine with the id 9000) to it. In this case we're getting the name "vm-9000-disk-0".

Configure your virtual machine to use the uploaded image

qm set 9000 --scsihw virtio-scsi-pci --scsi0 local-lvm:vm-9000-disk-0

Adding the Cloud-init image as CD-Rom to your virtual machine

qm set 9000 --ide2 local-lvm:cloudinit

This is an important step, because it allows you to change the settings I've already mentioned before.

Do not set settings here, because we're using this virtual machine as a template. You can edit the settings after you've cloned the template for use.

Restrict the virtual machine to boot from the Cloud-init image only

qm set 9000 --boot c --bootdisk scsi0

Attach a serial console to the virtual machine (this is needed for some Cloud-Init distributions, such as Ubuntu)

qm set 9000 --serial0 socket --vga serial0

Finally create a template

qm template 9000

Create a virtual machine out of the template

With the template you can clone as many virtual machines as you like and change the Cloud-init parameters for your needs. First we have to clone the template to a new virtual machine:

qm clone 9000 100 --name my-virtual-machine

We created a new virtual machine with the unique id 100 and the name "my-virtual-machine". Now you can change the Cloud-init settings either in the admin ui or with the qm command:

qm set 100 --sshkey ~/.ssh/ 
qm set 123 --ipconfig0 ip=,gw=

With this command you have set a public key for SSH authentication and the static IP We didn't set a user which means Ubuntu is using the default one (ubuntu). That's it! Your Cloud-Init image should now boot up fine with the desired settings.

Next steps

This tutorial is just the beginning. You're now able to use Terraform, Ansible or other automation tools to create "Infrastructure as a code" helping you to ramp up whole datacenters with just a few commands. But this is another story I have to tell ;-)