This tutorial will cover installation and basic configuration of libvirt and QEMU to a state where it's possible to easily provision new VMs with WebVirtMgr. It will be a minimalist install with as few dependencies as possible to keep the host easy to maintain. WebVirtMgr is not perfect, but is the best lightweight web GUI around at the moment. See the GitHub page for more information

Network Setup

libvirt provides a "default" virtual network which uses a NAT configuration. In most cases a bridge to the network the host is on will be preferred. More details on both can be found here

A bridge device can be configured on the command line with brctl from the bridge-utils package or with a netctl config file to allow initialisation at boot. An example of the command line is here

In this case a netctl config file named bridge0 is created. The bridge device will need to bind to an interface connected to the physical network and will become the interface which provides connectivity for both the host, and guest VMs (the physical interface it's self does not need an IP address). The configuration should be similar to bellow, virbr0 is already created by libvirt, so use virbr1 for the bridge name.

# nano /etc/netctl/bridge0
Description='Bridge device'

Set the bridge device to start at boot, then start it now.

# netctl enable bridge0
# netctl start bridge0

libvirt does provide functionality to create network devices on the host machine, however the libvirt Arch package has netcf disabled which provides this (netcf is Redhat developed and is very similar to netctl). For Arch the bridge device must be created using the netctl profile.

libvirt Installation

Install libvirt and tools.

# pacman -S qemu libvirt libvirt-python openbsd-netcat bridge-utils dnsmasq ebtables dmidecode

libvirt configuration is documented in the Arch wiki and is more than enough to get up and running. The steps bellow are taken from the wiki for a file permissions based setup which is most simple

Create a user and group for libvirt.

# groupadd libvirt
# useradd -m -g libvirt -G wheel,users -s /bin/bash libvirt
# chfn libvirt
# passwd libvirt

Add libvirt to the kvm group. Then set QEMU to run under libvirt and to listen on all interfaces.

# gpasswd -a libvirt kvm
# nano /etc/libvirt/qemu.conf
vnc_listen = ""
user = "libvirt"

Allow non-root users to manage VMs with file-permission based access control.

# nano /etc/libvirt/libvirtd.conf
unix_sock_group = "libvirt"
unix_sock_ro_perms = "0777"
unix_sock_rw_perms = "0770"
auth_unix_ro = "none"
auth_unix_rw = "none"

Enable unencrypted TCP connections. This is for simplicity, in anything other than a testing environment SASL should be enabled.

listen_tls = 0
listen_tcp = 1

Start libvirtd in listening mode by passing the --listen argument.

# nano /etc/conf.d/libvirtd

Enable and start the libvirt daemon.

# systemctl enable libvirtd
# systemctl start libvirtd

Now the daemon can be tested with a system or session connection via virsh. When connecting to system the libvirt daemon starts at boot with root permissions. A session connection will launch a libvirtd instance as the current user, taking that users permissions and some limitations compared to a system connection. More details can be found on the libvirt wiki.

$ virsh -c qemu:///system
virsh # exit
$ virsh -c qemu:///session
virsh # exit

The setup in this tutorial will use a system connection while storing VHDs in the libvirt user's home directory. This is because WebVirtMgr is currently only tested with (and hard coded to) a system connection, also keeping user data out of the root file system is a good idea. For instance, a btrfs snapshot of root shouldn't be effecting VHDs.

WebVirtMgr Setup

A Python virtualenv will be used to install WebVirtMgr (currently v4.8.8) and it's dependencies. This makes maintenance easier as the application and packages are installed in their own virtual root environment separate from the system.

# pacman -S python2-pip python2-virtualenv git

Continue the setup as the libvirt user.

A virtualenv named webvirtmgr is initialized in the home directory. The system site-packages are exposed as well to make the libvirt-python package available.

$ cd ~
$ virtualenv2 webvirtmgr --system-site-packages

Install the dependencies for Webvirtmgr, this must be done using the version of pip provided by virtualenv. The required versions are listed here, Django is the most important

$ ~/webvirtmgr/bin/pip2 install django==1.5.5 gunicorn==18.0 eventlet lockfile

Now clone WebVirtMgr from the git repository into site-packages and cd into the directory created.

$ cd ~/webvirtmgr/lib/python2.7/site-packages
$ git clone git://
$ cd webvirtmgr

Initialise the Django site database. A superuser must be created for access to the site, using libvirt is fine. Notice webvirtmgr.sqlite3 is created.

$ ~/webvirtmgr/bin/python2 syncdb

The file for Django must be enabled. Make a copy of the example, and then change the STATIC_ROOT variable as bellow to fix a path bug present in v4.8.8.

$ cp webvirtmgr/local/ webvirtmgr/local/
$ nano webvirtmgr/local/
STATIC_ROOT = os.path.join(LOCAL_PATH, '..', 'static')

To check everything is setup correctly the site can be tested with the Django development server using the runserver command.

$ ~/webvirtmgr/bin/python2 runserver

Running as a service with Gunicorn

Gunicorn is a pure Python webserver so no extra dependencies are needed. The Gunicorn config file needs one edit to bind the correct IP address.

$ nano conf/
bind = ''

Then test the server with the config file just edited.

$ ~/webvirtmgr/bin/gunicorn webvirtmgr.wsgi:application -c conf/

If the server starts then this command can be used to create a systemd service file to start Gunicorn on boot. The only differences are the absolute paths and addition of the --pythonpath attribute. Running Django with Gunicorn requires the project directory be on the Python path

A system service is created so this requires root permissions.

# nano /etc/systemd/system/webvirtmgr.service
ExecStart=/home/libvirt/webvirtmgr/bin/gunicorn webvirtmgr.wsgi:application -c /home/libvirt/webvirtmgr/lib/python2.7/site-packages/webvirtmgr/conf/ --pythonpath /home/libvirt/webvirtmgr/lib/python2.7/site-packages/webvirtmgr


Start the service, if it starts without error then enable it for automatic startup on boot. To check the service log in real time use journalctl.

# stystemctl start webvirtmgr
# systemctl enable webvirtmgr
# journalctl -fu webvirtmgr

With WebVirtMgr working there are some basic settings that are needed to get a VM running. Under the Interfaces tab the virbr1 bridge interface created earlier should be visible. To make this available for a VM to use create a new network under the Networks tab using the virbr1 interface in bridge mode.

A couple of storage pools will be needed for VHDs and ISOs. Under the Storages tab create a new "DIR" pool with the source as /home/libvirt/vhd and an "ISO" pool with the source as /home/libvirt/iso. Then it is simply a case of using sftp with the libvirt user to upload an ISO to boot a VM from.

Because WebVirtMgr is using the system connection to libvirt any VHD created here will owned by the root account. Also it is highly recommended to disable copy-on-write (COW) for the VHD directory if using Btrfs, this can be done by enabling the C attribute.

# chattr +C /home/libvirt/vhd

Because of the amount of small random writes a VHD will receive over time, the file will become heavily fragmented and reduce the performance of the VM.


Thanks goes to the WebVirtMgr developers for taking the time to create a nice lightweight GUI.


comments powered by Disqus