Raspberry Pi as a KVM hypervisor



Introduction

The Raspberry Pi has long transcended its original role as a simple board for enthusiasts: today it is a fully functional mini-computer capable of performing complex tasks, including hardware virtualization. This article provides a step-by-step guide to installing Raspberry Pi OS Lite, configuring SSH access, updating the system, installing KVM support, setting up the Cockpit web interface, and creating and running a guest operating system using KVM. This approach allows for transforming the Raspberry Pi into a convenient platform for testing and learning in the field of virtualization.

Installing Raspberry Pi OS Lite

Using the Raspberry Pi Imager utility, we install the Raspberry Pi OS Lite (64) operating system on a micro SD card. During the installation phase, we need to change the configuration so that we can then work with the Raspberry Pi remotely by connecting via SSH.

  • Hostname
  • Username and password
  • Enable SSH

We boot the Raspberry Pi from this memory card and check if it is connected to the network, if not, then we initialize the process of configuring the network connection by calling the system configurator:

The Raspberry Pi connection must be via cable and not via wifi.

System Update

Connecting to the Raspberry Pi via SSH

ssh [email protected]

We update the OS to the latest version and restart the Raspberry Pi

sudo apt update && sudo apt full-upgrade -y
sudo reboot

Installing KVM + libvirt

Starting with the Linux kernel 5.10+ (and now Raspberry Pi OS uses 6.x), support for KVM hardware virtualization for ARM64 is included directly in the kernel. On Raspberry Pi OS (64-bit, desktop, or lite), KVM is activated automatically as soon as the device supports hardware virtualization.

This was made possible by the fact that the Raspberry Pi Foundation integrated KVM support directly into the upstream kernel for its ARM64 platforms. They focus on the fact that the user can immediately experiment with virtualization – without additional configuration.

However, it is better to check this by running the following commands:

if the file /dev/kvm exists – support is active

ls /dev/kvm
/dev/kvm

will show the KVM startup log

dmesg | grep -i kvm
[    1.078559] kvm [1]: nv: 554 coarse grained trap handlers
[    1.084177] kvm [1]: IPA Size Limit: 40 bits
[    1.088486] kvm [1]: GICV region size/alignment is unsafe, using trapping (reduced performance)
[    1.097272] kvm [1]: vgic interrupt IRQ9
[    1.101231] kvm [1]: VHE mode initialized successfully
[    3.526966] systemd[1]: Hostname set to <kvm>

Since kvm works by default, you need to install libvirt

sudo apt install libvirt-daemon-system libvirt-clients bridge-utils virtinst

Checking the operation of the service:

systemctl status libvirtd
● libvirtd.service - Virtualization daemon
     Loaded: loaded (/lib/systemd/system/libvirtd.service; enabled; preset: enabled)
     Active: active (running) since Thu 2025-05-08 10:42:46 BST; 25s ago
TriggeredBy: ● libvirtd-admin.socket
             ● libvirtd-ro.socket
             ● libvirtd.socket
       Docs: man:libvirtd(8)
             https://libvirt.org
   Main PID: 4708 (libvirtd)
      Tasks: 19 (limit: 32768)
        CPU: 138ms
     CGroup: /system.slice/libvirtd.service
             └─4708 /usr/sbin/libvirtd --timeout 120

May 08 10:42:46 kvm systemd[1]: Starting libvirtd.service - Virtualization daemon...
May 08 10:42:46 kvm systemd[1]: Started libvirtd.service - Virtualization daemon.

Change user permissions

You need to add a user to the libvirt and kvm groups. Since we created the kvm user in the first step, there is no need to add it to the kvm group, but if you created another user in the initial step, you need to add it to the kvm group.

sudo usermod -aG libvirt kvm

After adding a user to the libvirt group, in order not to reboot the system, you can activate the new permissions with the command:

newgrp libvirt

Installing the Cockpit

Cockpit – це веб-інтерфейс для керування Linux-серверами, і один із його плагінів — Cockpit Machines — є надбудовою саме для KVM

sudo apt install cockpit cockpit-machines

Checking the operation of the service:

sudo systemctl status cockpit.socket
● cockpit.socket - Cockpit Web Service Socket
     Loaded: loaded (/lib/systemd/system/cockpit.socket; enabled; preset: enabled)
     Active: active (listening) since Thu 2025-05-08 10:59:18 BST; 46s ago
   Triggers: ● cockpit.service
       Docs: man:cockpit-ws(8)
     Listen: [::]:9090 (Stream)
      Tasks: 0 (limit: 9561)
        CPU: 12ms
     CGroup: /system.slice/cockpit.socket

May 08 10:59:18 kvm systemd[1]: Starting cockpit.socket - Cockpit Web Service Socket...
May 08 10:59:18 kvm systemd[1]: Listening on cockpit.socket - Cockpit Web Service Socket.

The service is active, but in listening mode, you need to activate it

sudo systemctl status cockpit.socket
● cockpit.socket - Cockpit Web Service Socket
     Loaded: loaded (/lib/systemd/system/cockpit.socket; enabled; preset: enabled)
     Active: active (running) since Thu 2025-05-08 10:59:18 BST; 3min 24s ago
   Triggers: ● cockpit.service
       Docs: man:cockpit-ws(8)
     Listen: [::]:9090 (Stream)
      Tasks: 0 (limit: 9561)
        CPU: 12ms
     CGroup: /system.slice/cockpit.socket

May 08 10:59:18 kvm systemd[1]: Starting cockpit.socket - Cockpit Web Service Socket...
May 08 10:59:18 kvm systemd[1]: Listening on cockpit.socket - Cockpit Web Service Socket.

Now you can follow the link to port 9090 in your browser: https://192.168.99.181:9090/

Guest OS Test

You need to log in through the Cockpit web interface using the username and password of the server user. The first thing the user will see is a dashboard with general information about the server

I previously downloaded the Ubuntu Server ISO image ubuntu-24.04.2-live-server-arm64.iso and placed it in the root of the system in the iso directory. I will run this image locally.

  • Name: Ubuntu_server
  • Connection: System
  • Installation type: Local install medis (ISO image or distro install tree)
  • Installation source: /iso/ubuntu-24.04.2-live-server-arm64.iso
  • Operating system: Generic Linux 2022
  • Storage: Create new volume
  • Storage limit: 20 Gib
  • Memory: 4 Gib

To start the build, click create and run, but after a moment you will get an error:

Creation of VM Ubuntu_server failed
ERROR Requested operation is not valid: network ‘default’ is not active Domain installation does not appear to have been successful. If it was, you can restart your domain by running: virsh –connect qemu:///system start Ubuntu_server otherwise, please restart your installation.

This error means that the virtual machine cannot be created because the default network is inactive. Libvirt creates a virtual network named default by default, but it may be inactive or not automatically started at startup. To fix this, you need to enable the network and add it to autostart:

sudo virsh net-start default
Network default started

sudo virsh net-autostart default
Network default marked as autostarted

Let’s check the status of the default network:

sudo virsh net-list --all
 Name      State    Autostart   Persistent
--------------------------------------------
 default   active   yes         yes

Let’s try to run the guest OS creation again. Click create and run again, and the image is mounted successfully, which indicates that the service is working correctly. The corresponding entry has appeared in the list of virtual machines.

To define and change the settings of a virtual OS, or to access OS management, at least for the logical completion of the installation, you must select the required OS from the list and then the user will be taken to the dashboard of this OS with its detailed characteristics.

To enlarge the console screen, click on the Expand button, and proceed to install Ubuntu Server for ARM. In my case, the window was partially cropped, so I installed the OS intuitively, selecting parameters with the left, right, tab, spacebar and enter buttons.

The first launch of the installed OS was not successful, a loop conflict occurred. In the console, selecting Serial Console, I saw many messages: Recursive exception occurred while dumping the CPU state.

After shutting down the virtual machine and after a certain startup time, the second attempt still launched, but not without errors. Since this OS is cloud-based, it needs access to the Internet. At the moment, the Internet is not configured, so the launch took place after waiting for the message:

Connected to domain 'linux2022-2025-5-10'
[ ***  ] Job systemd-networkd-wait-online.se…tart running (1min 22s / no limit)

But the OS still started!

Now you need to go to the section for configuring the local network and Internet via the bridge.

Network settings

Warning! The following settings may cause a loss of connection to the host, so before executing any command, make sure you have physical access to the host so that you can later correct the settings and regain access.

I was never able to successfully complete the network settings, so if you know an easy way to implement this, please share your experience in the comments.

By default, the built-in virtio interface is used with the following network 192.168.122.1/24, the guest OS was assigned IP 192.168.122.39, but the host itself is in a different subnet, which requires some configuration.

The bridge is created in the Networking -> Interfaces section, select Add Bridge and specify the name bridge0, do not check any boxes, as this may lead to loss of connection with the host. Thus, a new interface bridge0 with automatic DHCP IP address acquisition has appeared in the list of interfaces. Currently, there is no interface associated with this bridge, so we continue the configuration on the host via the terminal.

We need to make sure that the physical interface of the host is included in the bridge

sudo brctl show
bridge name     bridge id               STP enabled     interfaces
bridge0         8000.000000000000       no
virbr0          8000.5254006ad9b7       yes

In the output of this command, the interfaces column is empty, which indicates that the interfaces are not linked to each other, you need to link them manually with the following command:

sudo brctl addif bridge0 eth0
sudo ip link set bridge0 up

We run the bridge status check command again and see that the interface column has already acquired a connection to the physical interface:

sudo brctl show
bridge name     bridge id               STP enabled     interfaces
bridge0         8000.d83adde83f07       no              eth0
virbr0          8000.5254006ad9b7       yes

After that, the bridge will perform its function. Now we go back to the Cockpit web interface, to the Networking section, and expect the bridge to provide an IP address.

The IP address of the correct subnet appeared in the IP address column, but due to some peculiarities, the virtual machine never received it.

Conclusion

Using KVM virtualization and Cockpit on Raspberry Pi is a great opportunity to learn, test and experiment in the world of ARM64 virtualization. This combination allows users to gain a deeper understanding of the principles of hypervisor, resource management and network interface configuration.

However, practical application remains quite questionable due to several serious limitations:

  1. Compatibility of ARM64 operating systems
    • Many popular OSes have .img instead of .iso, which makes them difficult to run in KVM.
    • Not all distributions support UEFI correctly, which leads to difficulties with booting.
    • Lack of official optimized ARM64 distributions in .iso format.
  2. Unstable operation of KVM on ARM64
    • Frequent CPU compatibility problems (KVM is not supported for this guest CPU type).
    • Critical errors such as “Recursive Exception occurred while dumping the CPU state” occur, making virtual machines unpredictable.
    • Limited support for host passthrough for ARM64.
  3. Networking issues
    • Instability in the bridge configuration (bridge0) via NetworkManager.
    • Issues with DHCP and manually adding interfaces to the bridge (NO-CARRIER).
    • Cockpit does not always correctly recognize network parameters in ARM64 virtual machines.

Overall, KVM on Raspberry Pi is more of an experimental platform than a stable option for productive use. It is great for research in the field of virtualization on low-power ARM devices, but due to technical limitations and instability, it is difficult to recommend it for real-world deployments.