We want to run Debian Linux on a virtual machine using QEMU.
Create a directory where all of the QEMU stuff will reside:
mkdir -p ~/qemu-stuff
Download the Debian netinst
ISO image from https://www.debian.org/CD/netinst/. Put it in the ~/qemu-stuff
directory:
cd ~/qemu-stuff
curl \
--proto '=https' \
--tlsv1.2 \
-sSf \
-L "https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-13.0.0-amd64-netinst.iso" \
-o "debian-13.0.0-amd64-netinst.iso"
After downloading, check the sha256
hash:
sha256sum /home/valera/qemu-stuff/debian-13.0.0-amd64-netinst.iso
You should get e363cae0f1f22ed73363d0bde50b4ca582cb2816185cf6eac28e93d9bb9e1504
.
Install QEMU:
sudo apt install qemu-system qemu-system-common qemu-system-data qemu-system-gui
We are going to have a folder per VM. All the disk files, along with the install script, and the start script, will live in the VM folder. This way it’s easy to copy VMs - just copy entire folder, and name it differently. Also, if you are going to run a lot of VMs, best to organize everything so that you don’t loose track of what disks belong to which VM, and how to start each VM.
mkdir -p ~/qemu-stuff/first-vm
cd ~/qemu-stuff/first-vm
Let’s create a single disk for now:
qemu-img create -f qcow2 ./disk-0.qcow2 16G
Now we can launch QEMU, specify our new disk, and also load the Debian ISO file to the VM’s virtual CDROM. Let’s create an install script, call it install-vm.sh
:
#!/bin/bash
set -o errexit
set -o pipefail
qemu-system-x86_64 \
-cpu host,pdpe1gb \
-machine accel=kvm \
-m 4G \
-smp 4 \
-nic user,model=virtio \
-display gtk \
-device virtio-scsi-pci,id=scsi0,num_queues=4 \
-device scsi-hd,drive=drive0,bus=scsi0.0,channel=0,scsi-id=0,lun=0 \
-drive file=~/qemu-stuff/first-vm/disk-0.qcow2,if=none,id=drive0 \
-cdrom ~/qemu-stuff/debian-13.0.0-amd64-netinst.iso
echo "Script ran without error."
exit 0
And - we install:
chmod u+x ./install-vm.sh
./install-vm.sh
After the installation, machine will reboot. You can stop the machine booting, and issue a halt
command.
Now let’s create the normal start up script start-vm.sh
, which will exclude the CDROM mounting our Debian ISO:
#!/bin/bash
set -o errexit
set -o pipefail
qemu-system-x86_64 \
-cpu host,pdpe1gb \
-machine accel=kvm \
-m 4G \
-smp 4 \
-nic user,model=virtio \
-display gtk \
-device virtio-scsi-pci,id=scsi0,num_queues=4 \
-device scsi-hd,drive=drive0,bus=scsi0.0,channel=0,scsi-id=0,lun=0 \
-drive file=~/qemu-stuff/first-vm/disk-0.qcow2,if=none,id=drive0
echo "Script ran without error."
exit 0
And - let’s start the VM:
chmod u+x ./start-vm.sh
./start-vm.sh
Pass the flag -vga std
to QEMU. Then inside the guest you will be able to change the default resolution.
Refer to 1 and 2 for information on changing resolution using xrandr
tool. Works out of the box on Debian QEMU guests.
If you want to be able to reach the host from inside the guest VM, we need to change our network card options. We started with a simple:
-nic user,model=virtio
Let’s change that to:
-device rtl8139,netdev=net0
and also add some -netdev
configuration:
-netdev user,id=net0,net=192.168.76.0/24,dhcpstart=192.168.76.9
So the whole start command becomes:
qemu-system-x86_64 \
-cpu host,pdpe1gb \
-machine accel=kvm \
-m 4G \
-smp 4 \
-device rtl8139,netdev=net0 \
-netdev user,id=net0,net=192.168.76.0/24,dhcpstart=192.168.76.9 \
-display gtk \
-device virtio-scsi-pci,id=scsi0,num_queues=4 \
-device scsi-hd,drive=drive0,bus=scsi0.0,channel=0,scsi-id=0,lun=0 \
-drive file=~/qemu-stuff/first-vm/disk-0.qcow2,if=none,id=drive0
If you run the VM now, you will be able to ping the host machine via:
ping 192.168.76.2
NOTE: the ping command should be issue inside the VM (the guest).
Refer to more networking options in Documentation/Networking section on the QEMU site.
There is an awesome project libvirt which enables to share the filesystem between the host and the guest. QEMU supports this using the virtiofsd. Also see this and this.
There are some guides out there, such as the gentoo Virtiofs guide and the Standalone virtiofs usage guide.
I will describe the approach that is working for me.
First - on the host - install virtiofsd:
sudo apt install virtiofsd
Second - create the host directory which we will pass through to the guest:
cd /mnt
sudo mkdir ./common_host
sudo chown --recursive valera:valera ./common_host
sudo chgrp --recursive valera ./common_host
Third - create a directory for the virtiofsd socket:
cd /mnt
sudo mkdir ./virtiofsd_socket
sudo chown --recursive valera:valera ./virtiofsd_socket
sudo chgrp --recursive valera ./virtiofsd_socket
Fourth - we need the tool rootlesskit:
sudo apt install rootlesskit
Using rootlesskit
- we will start the virtiofsd
daemon:
rootlesskit /usr/libexec/virtiofsd \
--syslog \
--socket-path /mnt/virtiofsd_socket/virtiofsd.sock \
--shared-dir /mnt/common_host \
--announce-submounts \
--log-level debug
If you see that the daemon started, and is running, then all should be good. You can also check the logs in a separate terminal:
tail -f /var/log/syslog
Make sure everyone can access the socket file:
chmod --recursive a+rw /mnt/virtiofsd_socket/
Now - we can launch the VM with some additional configuration:
qemu-system-x86_64 \
-cpu host,pdpe1gb \
-machine accel=kvm \
-m 4G \
-smp 4 \
-nic user,model=virtio \
-display gtk \
-device virtio-scsi-pci,id=scsi0,num_queues=4 \
-device scsi-hd,drive=drive0,bus=scsi0.0,channel=0,scsi-id=0,lun=0 \
-drive file=~/qemu-stuff/first-vm/disk-0.qcow2,if=none,id=drive0 \
# additional configuration for "virtiofs"
-object memory-backend-memfd,id=mem,size=4G,share=on \
-numa node,memdev=mem \
-chardev socket,id=char0,path=/mnt/virtiofsd_socket/virtiofsd.sock \
-device vhost-user-fs-pci,chardev=char0,tag=mount_tag
NOTE: remove the comment # additional configuration for virtiofs
from the above command before running it!
If you see an error such as:
Failed to connect to '/mnt/virtiofsd_socket/virtiofsd.sock': Connection refused
make sure that the virtiofsd
daemon is running. I have found that sometimes it quits unexpectedly.
Once the guest machine has booted up - you can mount the virtual folder with the commands:
sudo mkdir /mnt/shared_folder
sudo mount -t virtiofs mount_tag /mnt/shared_folder
NOTE: These two commands should run inside the VM (guest).
Important thing to note - due to the security model - files in the guest should be written as root
, and on the host they will be available as the regular user who is running the virtiofsd
daemon (in my case - valera
).
This howto is part of a larger collection of howtos maintained by the author (mostly for his own reference). The source code for the current howto in plain Markdown is available on GitHub. If you have a GitHub account, you can jump straight in, and suggest edits or improvements via the link at the bottom of the page (Improve this page).
made with ❤ by Valera Rozuvan