Why struggle with Cloud-init for simple lab environments?
Downloading an Ubuntu or CentOS Cloud Image (.qcow2) to run on KVM is extremely lightweight. However, the catch is that these images usually have the default password locked and require Cloud-init for configuration. If you just need to quickly spin up one or two VMs for testing, setting up a Cloud-init server or writing metadata files is honestly quite tedious and time-consuming.
In the past, I usually had to boot the VM, open the console, and type commands manually. Doing it for one machine is fine, but by the fifth one, it starts to get frustrating. With my 12-VM Homelab cluster on Proxmox, using virt-customize saves me up to 80% of the preparation time. Instead of spending 5-10 minutes configuring each one, it now takes me less than 60 seconds to have a “custom-tailored” image.
virt-customize is part of the libguestfs-tools suite. It allows you to interact directly with disk files (.qcow2, .raw, .vmdk) without turning on the VM. Imagine performing “endoscopic surgery” on a virtual hard drive. It’s convenient and extremely precise.
Installing virt-customize
This tool runs well on most popular Linux distributions. Note that the libguestfs-tools package is a bit heavy because it pulls in a mini-kernel to read the file system formats inside the image.
On Ubuntu/Debian, install it via:
sudo apt update && sudo apt install libguestfs-tools -y
On CentOS/RHEL/Fedora:
sudo yum install libguestfs-tools -y
Pro tip: If you’re running on Ubuntu and encounter kernel access errors, grant read permissions to the current kernel with the command: sudo chmod 0644 /boot/vmlinuz-*. This error is very common but often overlooked.
5 tricks for lightning-fast Cloud Image customization
Suppose you have an ubuntu-22.04.qcow2 file you just downloaded. Here are the most practical commands to turn it into a ready-to-use image.
1. Set the Root password instantly
Cloud Images usually have the root user locked by default. To log in via the console quickly during troubleshooting, set the password immediately:
virt-customize -a ubuntu-22.04.qcow2 --root-password password:123456a@
Want to create an additional user for the team? Just one line of code:
virt-customize -a ubuntu-22.04.qcow2 --run-command 'useradd -m -s /bin/bash devops'
2. Inject SSH Key (A must-know)
This is the most professional way to manage VMs. Instead of manual copy-pasting, you push the public key directly into the authorized_keys file inside the image:
virt-customize -a ubuntu-22.04.qcow2 --ssh-inject root:file:/home/user/.ssh/id_rsa.pub
This command automatically handles everything: from creating the .ssh directory to setting the correct access permissions.
3. Pre-install necessary packages
Don’t wait for the machine to boot to run apt install. You can install Vim, Htop, or Curl right from the outside:
virt-customize -a ubuntu-22.04.qcow2 --install vim,htop,curl,net-tools
Its mechanism is very clever: it automatically chroots into the image and uses the image’s own package manager (apt/yum) to download them.
4. Set Timezone and Hostname
To ensure system logs are accurate, set the timezone to your local time (e.g., Vietnam):
virt-customize -a ubuntu-22.04.qcow2 --timezone "Asia/Ho_Chi_Minh" --hostname web-srv-01
5. Upload configuration files to the VM
If you already have an nginx.conf file or a backup script, use the --upload option:
virt-customize -a ubuntu-22.04.qcow2 --upload /path/to/local/nginx.conf:/etc/nginx/nginx.conf
Checking the results
To make sure everything is as expected, you can use virt-inspector to “inspect” the image content without booting:
virt-inspector -a ubuntu-22.04.qcow2
Important note: virt-customize overwrites the original file directly. To be safe, make a backup copy before proceeding. In case you accidentally type a command to delete /etc, you’ll still have a way back.
cp ubuntu-22.04.qcow2 ubuntu-custom-v1.qcow2
To optimize time, you should combine all options into a single command. This avoids mounting/unmounting the image multiple times:
virt-customize -a my-image.qcow2 \
--hostname my-vm \
--root-password password:secret \
--ssh-inject root:file:~/.ssh/id_rsa.pub \
--install nginx,git \
--selinux-relabel
Mastering virt-customize is the first step toward professional Infrastructure as Code (IaC). Instead of using bloated images, you can now create ultra-lightweight templates in seconds.

