Configuring vagrant to use kvm

Page contents

Automating virtual machines is an easy task with vagrant. In just a few commands, you can create, configure and destroy reproducible machines and environments - but making it work with KVM requires additional configuration.

Setting up kvm/libvirt and tools

You obviously need libvirt installed to use kvm as a backend, so we start with that.


For debian-like distros (Debian, Ubuntu, Mint etc):

sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients \
    bridge-utils dnsmasq-base virt-manager

For RHEL-like distros (Fedora, Rockylinux, Almalinux etc):

sudo dnf install @virtualization

Now we need to configure it for our needs. Start by starting and enabling the libvirtd service:

sudo systemctl enable --now libvirtd

Next, add your current user to the libvirt groups to allow access to the root-owned system socket:

sudo usermod -aG libvirt,libvirt-qemu $USER

Finally, test if you user can interact with the kvm system socket:

virsh --connect qemu:///system list --all

If you get no error, the kvm install was successful.

Make sure to include the --connect flag and do not use sudo! Vagrant does not support the session libvirt socket, only system.

Install and configure vagrant for libvirt

Make sure you have vagrant installed on your machine. If you need to install it, follow the official installation instructions.


When done, you will need to install a compiler toolchain and some libraries to compile the libvirt plugin for vagrant.

For debian-like distros:

sudo apt install \
    qemu-kvm \
    libvirt-daemon-system libvirt-clients \
    libvirt-dev \
    ruby-dev \
    build-essential \
    libxslt-dev libxml2-dev zlib1g-dev \
    ebtables dnsmasq-base \
    bridge-utils \
    pkg-config

For RHEL-like distros:

sudo dnf groupinstall "Development Tools"
sudo dnf install libvirt-devel ruby-devel \
    libxml2-devel libxslt-devel zlib-devel

Now we can install the vagrant plugin:

vagrant plugin install vagrant-libvirt

All that's left to do now is to tell vagrant to user libvirt as the default virtualization provider. You can do this by adding the following line to your ~/.bashrc file (for your user only) or into /etc/profile.d/vagrant.sh (for all users on the system):

export VAGRANT_DEFAULT_PROVIDER=libvirt

Installing NFSd

The last missing piece is an NFS server to enable mounting the working directory into the vagrant guest.

For debian-like distros:

sudo apt install nfs-kernel-server

For RHEL-like distros:

sudo dnf install nfs-utils

Once installed, make sure the service is running and starts on boot:

sudo systemctl enable --now nfs-server

Now all prerequisites are installed.

Verifying vagrant works as expected

Now that all dependencies and tools are installed, it is time to verify that vagrant works with libvirt out of the box.

Create, start and SSH into a test box:

vagrant init debian/bookworm64
vagrant up
vagrant ssh

Inside the box, check if the contents of /vagrant contains the mounted working directory from the host machine:

ls /vagrant

If all files are in place, your setup is now complete. Log out and destroy the box again:

vagrant destroy -f

Disabling password prompts

You may have noticed that running vagrant commands with libvirt requires your user password for some tasks like creating/destroying guest boxes. This is due to the fact that the system qemu socket is owned by root, so vagrant needs escalated privileges to interact with it.

You can disable the password prompt if you value convenience or automation over reduced security.

Create the file /etc/polkit-1/rules.d/50-libvirt.rules and allow passwordless qemu access:

polkit.addRule(function(action, subject) {
    if ((action.id == "org.libvirt.unix.manage" ||
         action.id == "org.libvirt.unix.read" ||
         action.id == "org.libvirt.unix.control") &&
        subject.isInGroup("libvirt")) {
        return polkit.Result.YES;
    }
});

Restart the polkit service for changes to take effect:

sudo systemctl restart polkit

That's it! Running vagrant commands should no longer prompt for your password.

More articles

A guide to byte encodings

From binary to text and back

Understanding the different sizes of ai models

Making sense of differing model sizes and variations

Enabling gpu support in docker

Accelerating video and machine learning workloads inside containers