Don’t Let VM Installation Waste Your Time
If you’ve ever sat around for 20 minutes just to install an Ubuntu Server instance on VirtualBox, you know how tedious it feels. The task becomes even more agonizing when you need to build a 3-5 node cluster to test Docker Swarm or Kubernetes. Mounting ISO files, setting usernames, typing passwords, and waiting is an outdated process.
In my homelab, I manage about 12 VMs on Proxmox. However, when I need to perform a quick test on my personal laptop with VirtualBox, I always use Cloud-Init. This is the secret that allows me to deploy a complete virtual machine in less than 2 minutes instead of the usual half hour.
Comparing Popular VM Initialization Methods
Before we dive in, let’s look at why Cloud-Init is the top choice for professionals:
1. Manual Installation from ISO
- Reality: You have to babysit the screen to click “Next”.
- Problem: Very time-consuming and prone to typos in IPs or passwords. This method is completely non-repeatable.
2. Using Vagrant
- Reality: Quite fast and convenient with a Vagrantfile.
- Problem: Sometimes Vagrant Cloud downloads images very slowly. Deep customization of VirtualBox networking can also be quite complex.
3. Cloning from a “Golden Image”
- Reality: Copying an existing virtual machine.
- Problem: VMs end up with duplicate Machine-IDs and SSH Host Keys. You’ll need extra effort to run cleanup scripts; otherwise, you’ll run into logging conflicts.
4. Cloud-Init (The Modern Standard)
Cloud-init is a tool for configuring virtual machines at boot-time. You only need to prepare a YAML file to define users, SSH keys, and software packages to be installed. This is exactly how AWS and Google Cloud initialize millions of VMs every day.
Why Does Cloud-Init Work on VirtualBox?
Normally, Cloud-Init retrieves data from cloud providers’ metadata services. For VirtualBox, we trick it using the NoCloud data source method. Instead of querying over the network, Cloud-init reads the configuration from a virtual disk (a tiny ISO file) attached directly to the machine.
Practical Implementation Steps
Step 1: Download the Cloud Image (Only ~500MB)
Skip those bulky multi-gigabyte installation ISOs. You need to download the Cloud Image (.ova or .vmdk). These versions are size-optimized and come with Cloud-init pre-installed.
Download link for Ubuntu: Ubuntu Cloud Images.
Step 2: Write the user-data Configuration File
Create a file named user-data (no file extension). This is where you command the VM on what to do:
#cloud-config
# Create user and grant sudo privileges without password
users:
- name: techadmin
groups: sudo
shell: /bin/bash
sudo: ['ALL=(ALL) NOPASSWD:ALL']
ssh_authorized_keys:
- ssh-rsa AAAAB3... (Paste your SSH Public Key here)
# Automatically update and install software
package_update: true
packages:
- qemu-guest-agent
- curl
- git
# Run check commands after installation
runcmd:
- [ systemctl, start, qemu-guest-agent ]
- echo "Server setup complete!" > /etc/motd
Don’t forget to create a meta-data file to identify the machine:
instance-id: lab-vm-01
local-hostname: ubuntu-lab
Step 3: Package the “Seed” ISO File
VirtualBox cannot read YAML files directly. You need to package them into a small ISO file using the following command:
For Linux/macOS:
genisoimage -output seed.iso -volid cidata -joliet -rock user-data meta-data
If you’re using Windows, you can install WSL (Windows Subsystem for Linux) to run this command easily.
Step 4: VirtualBox Setup
- Create a new VM, selecting the Cloud Image file you downloaded in Step 1 as the hard drive.
- Go to Settings > Storage.
- Under Controller: IDE, add an optical drive and select the
seed.isofile you just created. - Change Network to Bridged Adapter so the VM receives an IP in the same range as your host machine.
Step 5: Launch and Enjoy
Click Start. You will see the console running automated commands. Cloud-init is silently creating the user, configuring SSH, and installing your requested packages. After about a minute, you can SSH directly into the VM:
ssh [email protected]
Hard-Won Lessons When Using Cloud-Init
After many exhausting debugging sessions, I’ve gathered some important tips:
- Whitespace errors: YAML is extremely picky. A single extra space can cause Cloud-init to fail. Use online YAML validators before packaging the ISO.
- Runs only once: Cloud-init only performs the configuration on the first boot. If you modify the ISO file later, the VM won’t update unless you completely reset it.
- Cleanup: Once the machine is up and SSH is successful, you can remove the
seed.isofile to keep things tidy.
Mastering Cloud-init is a crucial stepping stone toward an Infrastructure as Code mindset. Instead of being a manual installer, let code do the work for you. Good luck setting up your lab!

