Linux Hypervisor Setup (libvirt/qemu/kvm)

One of the best things about Linux is how easily you can throw together a few tools and end up with a great system. This is especially true for provisioning VMs. Arguably, this is one of the key things that keeps me on a Linux desktop for my day-to-day work! However, these tools can also be used to turn an old laptop or desktop into a screaming hypervisor. This way you can laugh at all your friends with their $10,000 homelab investment while you're getting all the same goodness on commodity hardware :).

This setup is what I use day-to-day to create Kubernetes environments in a simple, manageable way without too many abstractions getting in my way. If understanding and running VMs on Linuxs hosts interests you, this post is for you!


KVM, ESXi, Hyper-V, qemu, xen....what's the deal? You're not short of options in this space. My stack, I like to think, is fairly minimal and let's me get everything I need done. The tools are as follows.

key system tools:

These are the key tools/services/features that enable vitalization.

user/client tools:

These tools can be interacted with by users / services.

ancillary system tools:

These tools are used to support the system tools listed above.

The above may feel overwhelming. But remember it is a look into the guts of all the pieces facilitating the virtualization stack. At a high-level, this diagram demonstrates the key relationships to understand:

How you install these tools depends on your package manager. My hypervisor OS is usually Arch, the following would install the above.

pacman -Sy --needed \
  qemu \
  dhclient \
  openbsd-netcat \
  virt-viewer \
  libvirt \
  dnsmasq \
  dmidecode \
  ebtables \
  virt-install \
  virt-manager \


The primary tricky bit is getting permissions correct. There are a few key pieces to configure so your using can interact with qemu:///system. This enables VMs to run as root, which is generally what you'll want. This is also the default used by virt-manager. Checkout this blog post from Colin Robinson, which calls out the differences.

virsh, will use qemu:///session by default, which means CLI calls not run as sudo will be looking at a different user. To ensure all client utilities default to qemu:///system, add the following configuration to your .config directory.

sudo cp -rv /etc/libvirt/libvirt.conf ~/.config/libvirt/ &&\
sudo chown ${YOURUSER}:${YOURGROUP} ~/.config/libvirt/libvirt.conf

Replace ${YOURUSER} and ${YOURGROUP} above.

When using qemu:///system, access is dictated by polkit. Here you have many options. Since commit e94979e9015 a libvirt group is included, which will have access to libvirtd. With this in place, you have the following options.

Depending on the option you go with, you may need to re-login or at least restart libvirtd (see below).

Configure and Start libvirtd

To begin interacting with qemu/kvm you need to start the libvirt daemon.

sudo systemctl start libvirtd

If you want libvirtd to be on at start-up, you can enable it.

sudo systemctl enable libvirtd

This is what I do on dedicated "servers". I don't enable libvirtd on my desktop machines.

libvirt keeps its files at /var/lib/libvirt/. There are multiple directories within.

drwxr-xr-x  2 root   root 4096 Apr  4 05:05 boot
drwxr-xr-x  2 root   root 4096 May  6 16:16 dnsmasq
drwxr-xr-x  2 root   root 4096 Apr  4 05:05 filesystems
drwxr-xr-x  2 root   root 4096 May  6 10:52 images
drwxr-xr-x  3 root   root 4096 May  6 09:55 lockd
drwxr-xr-x  2 root   root 4096 Apr  4 05:05 lxc
drwxr-xr-x  2 root   root 4096 Apr  4 05:05 network
drwxr-xr-x 11 nobody kvm  4096 May  6 16:16 qemu
drwxr-xr-x  2 root   root 4096 Apr  4 05:05 swtpm

The images directory is the default location a VM's disk image will be stored (e.g. qcow2).

I typically keep ISOs locally, unless I've got a PXE flow setup in my network. To store ISOs, you can create an isos directory in /var/lib/libvirtd.

mkdir /var/lib/libvirt/isos

Create a VM using virt-manager

virt-manager provides an easier way to create a new VM. In this section, you'll create a new VM from an installation ISO.

  1. Download an installation iso to your preferred directory.

    sudo wget -P /var/lib/libvirt/isos \

    This is the directory created in the last section.

  2. Launch virt-manager.

  3. Create a new virtual machine.

  4. Choose Local install media.

  5. Browse for ISO.

  6. Add a new pool.

  7. Name the pool isos.

  8. Set the Target Path to /var/lib/libvirt/isos.

  9. Click Finish.

  10. Select the iso and click Choose Volume.

  11. Go through prompts selecting desired system resources.

  12. You'll either be prompted to create a default network or choose the default network (NAT).

    There are many ways to approach the network. A common approach is to setup a bridge on the host that can act as a virtual switch. However, this is a deeper topic, maybe for another post.

  13. Click Finish.

  14. Wait for virt-viewer to popup and go through the installation process.

  15. Once installed, you can ssh to the guest based on its assigned IP address.

Create a VM using CLI

Following the setup in the previous section, you may wish to trigger the same install procedure via the command line. This could be done directly with qemu, but to keep interaction like-for-like with virt-manager, I'll show the virt-install CLI.

The equivalent to the above would be:

virt-install \
  --name ubuntu1804 \
  --ram 2048 \
  --disk path=/var/lib/libvirt/images/u19.qcow2,size=8 \
  --vcpus 2 \
  --os-type linux \
  --os-variant generic \
  --console pty,target_type=serial \
  --cdrom /var/lib/libvirt/isos/ubuntu-18.04.4-live-server-amd64.iso

Clone a VM

Cloning a VM could be a simple as replicating the filesystem. Similar to virt-install there is a tool focused on cloning VMs called virt-clone. This tool performs the clone via libvirt ensuring the disk image is copied and the new guest is setup with the same virtual hardware. Often I'll create a "base image" and use virt-clone to stamp out many instances of it. You can run a clone as follows.

virt-clone \
  --original ubuntu18.04 \
  --name cloned-ubuntu \
  --file /var/lib/libvirt/images/cu.qcow2

The value for --original can be found by looking at the existing VM names in virt-manager or running virsh list --all.