Tools: Provision Ubuntu VMs with NoCloud on Proxmox (2026)

Tools: Provision Ubuntu VMs with NoCloud on Proxmox (2026)

Step 1: Download the Ubuntu Cloud Image

Step 2: Create a Base VM Template

2.1 Create the VM

2.2 Import the disk

2.3 Set the VM disk and boot options

2.4 Attach Cloud-init disk

2.5 Enable the qemu-guest-agent

Step 3: Generate SSH Keys & NoCloud ISO

3.1 Generate a dedicated SSH key

3.2 Copy the public key

3.3 Createuser-dataandmeta-data(cloud-init)

3.4 Generate the ISO (on Proxmox)

3.5 Move ISO to/var/lib/vz/template/iso/

3.6 Attach ISO to VM

Step 4: Convert to a Template

Step 5: Clone and Deploy

5.1 Clone the template

5.2 Customize the new VM

5.3 Start up the VM Creatingrepeatable and secure VM templatesin Proxmox has been a game-changer in refining and scaling my homelab environment. In this post, I’ll show you how to: For the latest Ubuntu Cloud images, you can checkUbuntu Cloud Images. From yourProxmox server, download the latest Ubuntu 24.04 cloud image: You should see theubuntu-24.04-server-cloudimg-amd64.imgfile listed. First, create the base VM that will serve as your Ubuntu template. We’re using ID501, but you can choose any unused ID. Next, import the Ubuntu cloud image as a virtual disk into your Proxmox storage (in this case,local-zfs). I’ll generate thessh-keysfrom myMac, but any admin workstation will do. I’ll create the cloud-init configuration files that tell the VM how to initialize on first boot—things like hostname, users, and packages. Theuser-datafile contains most of the logic, whilemeta-datajust defines identity info for the instance. Create the following files:user-data Make sure you havecloud-image-utilsinstalled: This gives you access to thecloud-localdscommand you need. This gives you access to thecloud-localdscommand you need. Then, generate the iso: If your Proxmox storage useslocal-lvminstead oflocal-zfs, adjust the path accordingly.You can check available storage with:pvesm status If your Proxmox storage useslocal-lvminstead oflocal-zfs, adjust the path accordingly.You can check available storage with:pvesm status Replacelocalif your ISO storage is named differently — usepvesm statusto check. Replacelocalif your ISO storage is named differently — usepvesm statusto check. Once your base VM is configured, convert it to a Proxmox template so you can quickly clone new VMs from it. Remember to update the new IP address of the server in your~/.ssh/configfile, as shown below. Remember to update the new IP address of the server in your~/.ssh/configfile, as shown below. Now you can typessh ubuntuto connect to your newly created VM. I use this setup regularly when provisioning dev servers or test environments—it saves a ton of time. You now have a clean and SSH-ready NoCloud Ubuntu template: Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Command

Copy

$ -weight: 500;">wget -P /var/lib/vz/template/iso/ \ https://cloud-images.ubuntu.com/daily/server/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img -weight: 500;">wget -P /var/lib/vz/template/iso/ \ https://cloud-images.ubuntu.com/daily/server/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img -weight: 500;">wget -P /var/lib/vz/template/iso/ \ https://cloud-images.ubuntu.com/daily/server/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img -weight: 500;">wget -P /var/lib/vz/template/iso/ \ https://cloud-images.ubuntu.com/daily/server/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img -weight: 500;">wget -P /var/lib/vz/template/iso/ \ https://cloud-images.ubuntu.com/daily/server/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img -weight: 500;">wget -P /var/lib/vz/template/iso/ \ https://cloud-images.ubuntu.com/daily/server/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img ls /var/lib/vz/template/iso/ | grep -i ubuntu- ls /var/lib/vz/template/iso/ | grep -i ubuntu- ls /var/lib/vz/template/iso/ | grep -i ubuntu- ls /var/lib/vz/template/iso/ | grep -i ubuntu- ls /var/lib/vz/template/iso/ | grep -i ubuntu- ls /var/lib/vz/template/iso/ | grep -i ubuntu- ubuntu-24.04-server-cloudimg-amd64.img ubuntu-24.04-server-cloudimg-amd64.img ubuntu-24.04-server-cloudimg-amd64.img qm create 501 \ --name ubuntu-cloud-init-template \ --memory 2048 \ --cores 2 \ --net0 virtio,bridge=vmbr0 qm create 501 \ --name ubuntu-cloud-init-template \ --memory 2048 \ --cores 2 \ --net0 virtio,bridge=vmbr0 qm create 501 \ --name ubuntu-cloud-init-template \ --memory 2048 \ --cores 2 \ --net0 virtio,bridge=vmbr0 qm create 501 \ --name ubuntu-cloud-init-template \ --memory 2048 \ --cores 2 \ --net0 virtio,bridge=vmbr0 qm create 501 \ --name ubuntu-cloud-init-template \ --memory 2048 \ --cores 2 \ --net0 virtio,bridge=vmbr0 qm create 501 \ --name ubuntu-cloud-init-template \ --memory 2048 \ --cores 2 \ --net0 virtio,bridge=vmbr0 qm importdisk 501 /var/lib/vz/template/iso/ubuntu-24.04-server-cloudimg-amd64.img local-zfs qm importdisk 501 /var/lib/vz/template/iso/ubuntu-24.04-server-cloudimg-amd64.img local-zfs qm importdisk 501 /var/lib/vz/template/iso/ubuntu-24.04-server-cloudimg-amd64.img local-zfs qm importdisk 501 /var/lib/vz/template/iso/ubuntu-24.04-server-cloudimg-amd64.img local-zfs qm importdisk 501 /var/lib/vz/template/iso/ubuntu-24.04-server-cloudimg-amd64.img local-zfs qm importdisk 501 /var/lib/vz/template/iso/ubuntu-24.04-server-cloudimg-amd64.img local-zfs qm set 501 \ --scsihw virtio-scsi-pci \ --scsi0 local-zfs:vm-501-disk-0 \ --boot c \ --bootdisk scsi0 qm set 501 \ --scsihw virtio-scsi-pci \ --scsi0 local-zfs:vm-501-disk-0 \ --boot c \ --bootdisk scsi0 qm set 501 \ --scsihw virtio-scsi-pci \ --scsi0 local-zfs:vm-501-disk-0 \ --boot c \ --bootdisk scsi0 qm set 501 \ --scsihw virtio-scsi-pci \ --scsi0 local-zfs:vm-501-disk-0 \ --boot c \ --bootdisk scsi0 qm set 501 \ --scsihw virtio-scsi-pci \ --scsi0 local-zfs:vm-501-disk-0 \ --boot c \ --bootdisk scsi0 qm set 501 \ --scsihw virtio-scsi-pci \ --scsi0 local-zfs:vm-501-disk-0 \ --boot c \ --bootdisk scsi0 qm set 501 --ide2 local-zfs:cloudinit qm set 501 --ide2 local-zfs:cloudinit qm set 501 --ide2 local-zfs:cloudinit qm set 501 --ide2 local-zfs:cloudinit qm set 501 --ide2 local-zfs:cloudinit qm set 501 --ide2 local-zfs:cloudinit qm set 501 --agent enabled=1 qm set 501 --agent enabled=1 qm set 501 --agent enabled=1 qm set 501 --agent enabled=1 qm set 501 --agent enabled=1 qm set 501 --agent enabled=1 ssh-keygen -t ed25519 -C "ubuntu-template" -f ~/.ssh/id_ed25519_ubuntu_template ssh-keygen -t ed25519 -C "ubuntu-template" -f ~/.ssh/id_ed25519_ubuntu_template ssh-keygen -t ed25519 -C "ubuntu-template" -f ~/.ssh/id_ed25519_ubuntu_template ssh-keygen -t ed25519 -C "ubuntu-template" -f ~/.ssh/id_ed25519_ubuntu_template ssh-keygen -t ed25519 -C "ubuntu-template" -f ~/.ssh/id_ed25519_ubuntu_template ssh-keygen -t ed25519 -C "ubuntu-template" -f ~/.ssh/id_ed25519_ubuntu_template ~/.ssh/id_ed25519_ubuntu_template ~/.ssh/id_ed25519_ubuntu_template ~/.ssh/id_ed25519_ubuntu_template ~/.ssh/id_ed25519_ubuntu_template.pub ~/.ssh/id_ed25519_ubuntu_template.pub ~/.ssh/id_ed25519_ubuntu_template.pub pbcopy < ~/.ssh/id_ed25519_ubuntu_template.pub pbcopy < ~/.ssh/id_ed25519_ubuntu_template.pub pbcopy < ~/.ssh/id_ed25519_ubuntu_template.pub pbcopy < ~/.ssh/id_ed25519_ubuntu_template.pub pbcopy < ~/.ssh/id_ed25519_ubuntu_template.pub pbcopy < ~/.ssh/id_ed25519_ubuntu_template.pub mkdir -p /root/cloudinit/ubuntu-template cd /root/cloudinit/ubuntu-template mkdir -p /root/cloudinit/ubuntu-template cd /root/cloudinit/ubuntu-template mkdir -p /root/cloudinit/ubuntu-template cd /root/cloudinit/ubuntu-template mkdir -p /root/cloudinit/ubuntu-template cd /root/cloudinit/ubuntu-template mkdir -p /root/cloudinit/ubuntu-template cd /root/cloudinit/ubuntu-template mkdir -p /root/cloudinit/ubuntu-template cd /root/cloudinit/ubuntu-template #cloud-config hostname: ubuntu-template users: - name: ubuntu ssh-authorized-keys: - paste_the_public_key_you_copied_earlier -weight: 600;">sudo: ALL=(ALL) NOPASSWD:ALL shell: /bin/bash package_update: true package_upgrade: true packages: - qemu-guest-agent runcmd: - -weight: 500;">systemctl -weight: 500;">enable qemu-guest-agent - -weight: 500;">systemctl -weight: 500;">start qemu-guest-agent #cloud-config hostname: ubuntu-template users: - name: ubuntu ssh-authorized-keys: - paste_the_public_key_you_copied_earlier -weight: 600;">sudo: ALL=(ALL) NOPASSWD:ALL shell: /bin/bash package_update: true package_upgrade: true packages: - qemu-guest-agent runcmd: - -weight: 500;">systemctl -weight: 500;">enable qemu-guest-agent - -weight: 500;">systemctl -weight: 500;">start qemu-guest-agent #cloud-config hostname: ubuntu-template users: - name: ubuntu ssh-authorized-keys: - paste_the_public_key_you_copied_earlier -weight: 600;">sudo: ALL=(ALL) NOPASSWD:ALL shell: /bin/bash package_update: true package_upgrade: true packages: - qemu-guest-agent runcmd: - -weight: 500;">systemctl -weight: 500;">enable qemu-guest-agent - -weight: 500;">systemctl -weight: 500;">start qemu-guest-agent #cloud-config hostname: ubuntu-template users: - name: ubuntu ssh-authorized-keys: - paste_the_public_key_you_copied_earlier -weight: 600;">sudo: ALL=(ALL) NOPASSWD:ALL shell: /bin/bash package_update: true package_upgrade: true packages: - qemu-guest-agent runcmd: - -weight: 500;">systemctl -weight: 500;">enable qemu-guest-agent - -weight: 500;">systemctl -weight: 500;">start qemu-guest-agent #cloud-config hostname: ubuntu-template users: - name: ubuntu ssh-authorized-keys: - paste_the_public_key_you_copied_earlier -weight: 600;">sudo: ALL=(ALL) NOPASSWD:ALL shell: /bin/bash package_update: true package_upgrade: true packages: - qemu-guest-agent runcmd: - -weight: 500;">systemctl -weight: 500;">enable qemu-guest-agent - -weight: 500;">systemctl -weight: 500;">start qemu-guest-agent #cloud-config hostname: ubuntu-template users: - name: ubuntu ssh-authorized-keys: - paste_the_public_key_you_copied_earlier -weight: 600;">sudo: ALL=(ALL) NOPASSWD:ALL shell: /bin/bash package_update: true package_upgrade: true packages: - qemu-guest-agent runcmd: - -weight: 500;">systemctl -weight: 500;">enable qemu-guest-agent - -weight: 500;">systemctl -weight: 500;">start qemu-guest-agent instance-id: ubuntu-template local-hostname: ubuntu-template instance-id: ubuntu-template local-hostname: ubuntu-template instance-id: ubuntu-template local-hostname: ubuntu-template instance-id: ubuntu-template local-hostname: ubuntu-template instance-id: ubuntu-template local-hostname: ubuntu-template instance-id: ubuntu-template local-hostname: ubuntu-template cloud-image-utils cloud-image-utils cloud-image-utils -weight: 500;">apt -weight: 500;">update -weight: 500;">apt -weight: 500;">install cloud-image-utils -weight: 500;">apt -weight: 500;">update -weight: 500;">apt -weight: 500;">install cloud-image-utils -weight: 500;">apt -weight: 500;">update -weight: 500;">apt -weight: 500;">install cloud-image-utils -weight: 500;">apt -weight: 500;">update -weight: 500;">apt -weight: 500;">install cloud-image-utils -weight: 500;">apt -weight: 500;">update -weight: 500;">apt -weight: 500;">install cloud-image-utils -weight: 500;">apt -weight: 500;">update -weight: 500;">apt -weight: 500;">install cloud-image-utils cloud-localds cloud-localds cloud-localds cloud-localds nocloud.iso user-data meta-data cloud-localds nocloud.iso user-data meta-data cloud-localds nocloud.iso user-data meta-data cloud-localds nocloud.iso user-data meta-data cloud-localds nocloud.iso user-data meta-data cloud-localds nocloud.iso user-data meta-data /var/lib/vz/template/iso/ /var/lib/vz/template/iso/ /var/lib/vz/template/iso/ mv nocloud.iso /var/lib/vz/template/iso/ mv nocloud.iso /var/lib/vz/template/iso/ mv nocloud.iso /var/lib/vz/template/iso/ mv nocloud.iso /var/lib/vz/template/iso/ mv nocloud.iso /var/lib/vz/template/iso/ mv nocloud.iso /var/lib/vz/template/iso/ pvesm -weight: 500;">status pvesm -weight: 500;">status pvesm -weight: 500;">status qm set 501 --ide2 local:iso/nocloud.iso,media=cdrom qm set 501 --ide2 local:iso/nocloud.iso,media=cdrom qm set 501 --ide2 local:iso/nocloud.iso,media=cdrom qm set 501 --ide2 local:iso/nocloud.iso,media=cdrom qm set 501 --ide2 local:iso/nocloud.iso,media=cdrom qm set 501 --ide2 local:iso/nocloud.iso,media=cdrom pvesm -weight: 500;">status pvesm -weight: 500;">status pvesm -weight: 500;">status qm template 501 qm template 501 qm template 501 qm template 501 qm template 501 qm template 501 qm clone 501 105 --name "ubuntu-vm01" qm clone 501 105 --name "ubuntu-vm01" qm clone 501 105 --name "ubuntu-vm01" qm clone 501 105 --name "ubuntu-vm01" qm clone 501 105 --name "ubuntu-vm01" qm clone 501 105 --name "ubuntu-vm01" qm set 105 --memory 4096 --cores 4 qm set 105 --memory 4096 --cores 4 qm set 105 --memory 4096 --cores 4 qm set 105 --memory 4096 --cores 4 qm set 105 --memory 4096 --cores 4 qm set 105 --memory 4096 --cores 4 qm -weight: 500;">start 105 qm -weight: 500;">start 105 qm -weight: 500;">start 105 qm -weight: 500;">start 105 qm -weight: 500;">start 105 qm -weight: 500;">start 105 ~/.ssh/config ~/.ssh/config ~/.ssh/config ~/.ssh/config ~/.ssh/config ~/.ssh/config Host ubuntu HostName 10.160.0.64 User ubuntu IdentityFile ~/.ssh/id_ed25519_ubuntu_template Host ubuntu HostName 10.160.0.64 User ubuntu IdentityFile ~/.ssh/id_ed25519_ubuntu_template Host ubuntu HostName 10.160.0.64 User ubuntu IdentityFile ~/.ssh/id_ed25519_ubuntu_template Host ubuntu HostName 10.160.0.64 User ubuntu IdentityFile ~/.ssh/id_ed25519_ubuntu_template Host ubuntu HostName 10.160.0.64 User ubuntu IdentityFile ~/.ssh/id_ed25519_ubuntu_template Host ubuntu HostName 10.160.0.64 User ubuntu IdentityFile ~/.ssh/id_ed25519_ubuntu_template - Use the NoCloud datasource with Ubuntu Cloud Images - Inject SSH keys from your admin box - Enable and verify the Proxmox guest agent - Clone pre-configured VMs using Proxmox CLI Let’s walk through the whole process—from image preparation to SSH-ready VM deployment. - ~/.ssh/id_ed25519_ubuntu_template - ~/.ssh/id_ed25519_ubuntu_template.pub - Ideal for hands-off provisioning - Cloud-init friendly - Guest agent enabled out of the box Found this helpful?Check out moretech tutorialsor follow myGitHub, where I share homelab setups, automation tools, and real-world projects from my day-to-day work as an IT consultant.