1 Can I run KVM
Before we can start with setting everything up, we first need to check if we can even run KVM.
We can do so with the following commands.
lira@computer:~$ egrep -c '(vmx|svm)' /proc/cpuinfo 1 lira@computer:~$ kvm-ok INFO: /dev/kvm exists KVM acceleration can be used
If the first command returns a number that is higher than zero, we are good. The next way to check if we can run KVM is with kvm-ok.
2 Installing KVM and QEMU
To install the packages we need, run the following command
lira@computer:~$ sudo apt install qemu-kvm \ libvirt-daemon-system \ libvirt-clients \ virt-manager \ ovmf \ bridge-utils
Below a list of the different packages and why we need them.
- qemu-kvm
- The processor-emulator QEMU with additional KVM-support.
- libvirt-daemon-system
- Functionality to interact with a virtualised Linux-system. It has support for multiple virtualisers, including QEMU and KVM.
- libvirt-clients
- Includes the application Virsh, which we will use to connect with the server.
- virt-manager
- A graphical virtual machine viewer. We will only need
virt-install, which is included in this package. Also, having a GUI can come in handy later. - ovmf
- An UEFI-implementation for QEMU.
- bridge-utils
- A bridge to get our server connected to the outside world.
Before we continue, lets check if libvirt is enabled. We can do that with systemctl status.
lira@computer:~$ sudo systemctl status libvirtd ● libvirtd.service - Virtualization daemon Loaded: loaded (/lib/systemd/system/libvirtd.service; enabled; vendor pres> Active: active (running) since Thu 2001-02-30 01:02:30 CET; 1h 20min ago TriggeredBy: ● libvirtd-admin.socket ● libvirtd-ro.socket ● libvirtd.socket Docs: man:libvirtd(8) https://libvirt.org Main PID: 978 (libvirtd) Tasks: 19 (limit: 32768) Memory: 34.3M CGroup: /system.slice/libvirtd.service ├─ 978 /usr/sbin/libvirtd ├─1198 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/defa> └─1201 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/defa> Jan 10 01:02:30 computer dnsmasq-dhcp[1198]: DHCP, sockets bound exclusivel> Jan 10 01:02:30 computer dnsmasq[1198]: reading /etc/resolv.conf Jan 10 01:02:30 computer dnsmasq[1198]: using nameserver 127.0.0.53#53 Jan 10 01:02:30 computer dnsmasq[1198]: read /etc/hosts - 7 addresses Jan 10 01:02:30 computer dnsmasq[1198]: read /var/lib/libvirt/dnsmasq/defau> Jan 10 01:02:30 computer dnsmasq-dhcp[1198]: read /var/lib/libvirt/dnsmasq/> Jan 10 01:02:30 computer dnsmasq[1198]: reading /etc/resolv.conf
To quit, press the Q-key.
If libvirtd is not running, you can enable it with systemctl enable.
lira@computer:~$ sudo systemctl enable --now libvirtd
3 Setting permissions
In order to use KVM we need to add our user to the groups libvirt and kvm.
lira@computer:~$ sudo adduser lira libvirt lira@computer:~$ sudo adduser lira kvm
The images for our OS will be put in /var/lib/libvirt/images/. In order to access that library, we need to set the permissions it got from the parent-folders from root to libvirt.
lira@computer:~$ sudo chgrp libvirt /var/lib/libvirt/images lira@computer:~$ sudo chmod 775 /var/lib/libvirt/images lira@computer:~$ ls -ld /var/lib/libvirt/images drwxrwxr-x 2 root libvirt 4096
Now you will have to relog for group-permissions to take effect. Once you are back you can run groups to check if kvm and libvirt are among your groups.
lira@computer:~$ groups lira cdrom sudo kvm libvirt
4 Installing an OS
Next we need to download the OS for our VM. In this article I will use Ubuntu Server. Download the latest Ubuntu via the download page, I chose version 20.04.3
Move the ISO-file to the libvirt-images-folder
lira@computer:~$ mv \ Downloads/ubuntu-20.04.3-live-server-amd64.iso \ /var/lib/libvirt/images/ubuntu-20.04.3-live-server-amd64.iso
Onto the installation itself!
Ubuntu Installation guide recommends 2GB RAM, but actually wants 2GiB. Let's just give it the 2,048GB it actually wants.
lira@computer:~$ cd /var/lib/libvirt/images lira@computer:/var/lib/libvirt/images$ virt-install \ --name=UbuntuServer20 \ --vcpus=1 \ --ram=2048 \ --disk path=./ubuntuserver20.qcow2,size=15 \ --cdrom ./ubuntu-20.04.3-live-server-amd64.iso \ --graphics vnc lira@computer:/var/lib/libvirt/images$ cd ~
You might get a lot of failure-codes, but you can just ignore those. It is mostly about not finding a CD-ROM and things like that. Just press the enter-key whenever the installation pauses.
After rebooting it will show some more failure-codes, which we will again ignore with the mighty enter-key, after which we can log in
Once logged in, the first thing we do is bringing the system up-to-date. Afterwards we shut it down again. We will restart it later.
lira@ubuntuserver:~$ sudo apt update lira@ubuntuserver:~$ sudo apt upgrade lira@ubuntuserver:~$ sudo shutdown now
Now we can start the server again. Virsh allows us to act on a VM by specifying the tool-URI, qemu in this case. We pass it the start-command.
lira@computer:~$ virsh --connect qemu:///system start UbuntuServer20
It will take a few seconds before the server is fully operational. If you run virsh domifaddr while it is not ready yet, it will not show any rows. So keep trying for a while until it does.
lira@computer:~$ virsh domifaddr UbuntuServer20 Name MAC address Protocol Address ----------------------------------------------------------------- vnet0 52:54:00:f3:4f:d0 ipv4 192.168.122.179/24
Great! We got the IP-address. Lets do a little ping-test, after which we connect to it via SSH to start working on the web-server itself.
lira@computer:~$ ping -c 4 192.168.122.179 lira@computer:~$ ssh adminadmin@192.168.122.179
5 The web-server
Now you can set up your web-server. If you don't have one but still want to continue this article, here is a very basic web-server written in C you can use.
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(){
int s, i, size;
struct sockaddr_in a, o;
if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) return -10;
a.sin_family = AF_INET;
a.sin_port = htons(8080);
a.sin_addr.s_addr = htonl(INADDR_ANY);
memset(&(a.sin_zero), '\0', 8);
if(bind(s, (struct sockaddr*)&a, sizeof(struct sockaddr)) < 0) return -20;
if(listen(s, 1) < 0) return -30;
repeat:
size = sizeof(struct sockaddr_in);
if((i = accept(s, (struct sockaddr*)&o, &size)) < 0) goto repeat;
send(i, "Hello\n", 6, 0);
close(i);
goto repeat;
close(s);
}
Helloonce reached from port 8080
To compile the code run gcc BasicWebServer.c -o BasicWebServer.
Now we can run the web-server!
lira@ubuntuserver:~$ ./BasicWebServer
Now we can test the web-server! Since it is just a basic string that gets returned, let's give cURL a try.
lira@computer:~$ curl -X GET --http0.9 http://192.168.122.179:8080
Helloto us!
Once we are done, we can go back to the server and shut it down.
lira@ubuntuserver:~$ sudo shutdown now
6 Sources
- How to Install KVM on Ubuntu 20.04, by Marko Aleksic
- Install Ubuntu Server: requirements, by Canonical Ltd.
- Manual of virt-install, by Red Hat
- Create A KVM Virtual Machine Using Qcow2 Image In Linux, by Senthil Kumar
- How do I open VM from command line with virsh, answered by Christian Ehrhardt
- Everything curl: HTTP versions, by Daniel Stenberg
- qemu:///system vs qemu:///session, by Cole Robinson
- Connection URIs, by participants in the libvirt project
- Uniform Resource Identifier (URI): Generic Syntax: Syntax components, by Berners-Lee, et al.
- Beej’s Guide to Network Programming, by Brian "Beej" Hall (PDF, HTTP-only)