Wednesday, October 1, 2025

Booting an Ubuntu Server disk image with QEMU

1. Download an Ubuntu server cloud qcow2 disk image.

wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img

2. Create cloud-init configuration files

Also, you can generate an SSH key pair and use it to login over SSH if you put the public key as I did below. cloud-init will automatically write it to ~/.ssh/authorized_keys
touch meta-data
touch network-data
touch vendor-data

cat << EOF > user-data
#cloud-config
users:
  - name: ubuntu
    sudo: ALL=(ALL) NOPASSWD:ALL
    groups: sudo
    shell: /bin/bash
    lock_passwd: false
    password: password
    ssh_authorized_keys:
      - <your public SSH key>

chpasswd:
  list: |
    ubuntu:password
  expire: False

ssh_pwauth: True
EOF

3. Create an ISO disk image out of those files

The volume id should be cidata. Here, I enabled the Rock Ridge and Joliet ISO 9660 extensions.

xorriso -as mkisofs \
    -output seed.img \
    -volid cidata -rational-rock -joliet \
    user-data meta-data network-config

4. Run the guest OS

Notice that the disk image that holds Ubuntu Server and the CD-ROM disk image are both "plugged in" to the machine being emulated. See the QEMU documentation for more help on writing the correct and fastest QEMU invocation for your platform and use.

qemu-system-x86_64 \
  -m 2G \
  -accel tcg \
  -drive file=noble-server-cloudimg-amd64.img,if=virtio,format=qcow2 \
  -drive file=seed.img,format=raw,media=cdrom \
  -netdev user,id=net0 \
  -device virtio-net-pci,netdev=net0,hostfwd=tcp::2222-:22 \ # you only need hostfwd if you're using ssh
  -nographic

Now, in the guest OS:

ubuntu@ubuntu:~$ uname -a
Linux ubuntu 6.8.0-90-generic #91-Ubuntu SMP PREEMPT_DYNAMIC Tue Nov 18 14:14:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux

In this case, the username is ubuntu, and the password is password. If you set up SSH, you can login without your password:

ssh -p 2222 -i private_key ubuntu@localhost

5.  Optionally, mount the host file-system onto guest's file system

Make sure that QEMU is compiled with support for the 9p protocol. Add this to the QEMU invocation:
-virtfs local,path=/Users/varunnawathey,mount_tag=share0,security_model=passthrough
And, in the guest, mount the file system tag
sudo mount -t 9p share0 /mnt

Relevant Documentation: