Virtual Machines on RaspberryPi 5

RaspberryPi computers are now moving into the realm of being powerful enough to replace the traditional desktop PC. My most recent purchase, a RaspberryPi 500+ is proof of this as it has been my daily desktop PC since it’s arrival.

One of the things I use heavily are virtual machines. They’re great for developing, prototyping and running new services. With the ability to snapshot, rollback and backup in an instant, virtualisation helps to reduce the development and test time for many of the programs and services that I’m playing with.

With RaspberryPi computers now supporting 16GB of RAM and M.2 SSD drives there is no reason for not taking advantage of virtualisation.

To this end I decided to test running some virtualised loads on my new 500+ with the plan to deploy to 16GB Pi5’s with SSD drives in place of more expensive Intel based computers.

On my Intel based machines I use QEMU, KVM and Virt-Manager to manage the multitude of virtual machines (VMs) I have running here. Since this is a solid, high performance platform for running VMs I decided to take the same route on the 500+

Installing the necessary packages is extremely simple, just one simple apt command:

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

Note: If you’re using Debian 13 (Trixie) then the apt command to use is:

sudo apt install qemu-system-arm libvirt-daemon-system libvirt-clients virt-manager bridge-utils

The qemu-kvm package doesn’t exist in Debian 13 and so you have to replace it with the qemu-system-arm package.

To be able to create and run VMs you need to add yourself to the libvirt and libvirt-qemu groups.

sudo usermod -a -G libvirt your_username
sudo usermod -a -G libvirt-qemu your_username

Of course you can do it the old-fashioned way by editing the /etc/group file and adding your username to each group.

You’ll need to create a bridged ethernet device for the VMs to use to access the ethernet interface on your RaspberryPi.

If like me you don’t use NetworkManager the easiest way to create a bridge is to define it in your /etc/network/interfaces file.

For this example I am using an IP Address of 192.168.0.100, gateway on 192.168.0.1 with a netmask of 255.255.255.0 and DNS nameserver on 192.168.0.5.

The normal entry in the interfaces file would look like this:

# Main ethernet
auto eth0
iface eth0 inet static
address 192.168.0.100
netmask 255.255.255.0
gateway 192.168.0.1
dns-nameservers 192.168.0.5
dns-domain lan.local
dns-search lan.local
#
#

To create a bridge this entry needs to change to:

# Main ethernet
# Setup Bridge called br1 on eth0
allow-hotplug eth0
iface eth0 inet manual
auto br1
iface br1 inet static
address 192.168.0.100
network 192.168.0.0
netmask 255.255.255.0
broadcast 192.168.0.255
gateway 192.168.0.1
dns-nameservers 192.168.0.5
bridge_ports eth0
bridge_stp off
#
#

Once this is done reboot your RaspberryPi and check you have access to your local LAN and of course the internet. You will now also inherit the two new groups that you added yourself to above.

Note: If you are using NetworkManager open the network settings app and create a bridge on eth0. You can also use the nmtui copmmandline app if you prefer.

At this point you’re ready to create your first virtual machine.

It’s important to have an arm64 version of Linux in ISO format that you can use to install into your VM. My preferred distro is Debian and so I downloaded the Debian 13 Arm64 netinst ISO from the debian.org website.

From the main menu start “Virtual machine Manager” or on the commandline type:

virt-manager
QEMU Virtual Machine Manager
QEMU Virtual Machine Manager

Click the Create new VM button and then navigate to where you saved your ISO file and select it as the installation media.

Virtual Machine Manager - Local install media
Virtual Machine Manager – Local install media
Virtual Machine Manager - Select ISO file
Virtual Machine Manager – Select ISO file

Once you’ve chosen your ISO you’ll need to configure the actual VM. Start by setting the amount of RAM and number of virtual CPUs you want the VM to have.

Virtual Machine Manager - Configure RAM and CPU
Virtual Machine Manager – Configure RAM and CPU

Next set the size of the virtual disk that the VM will use.

Virtual Machine Manager - Create virtual disk
Virtual Machine Manager – Create virtual disk

Finally, give the VM a name and set its network device to br0 as created above. Click finish and your VM will boot.

Virtual Machine Manager - Name VM and select bridge interface
Virtual Machine Manager – Name VM and select bridge interface

Now it’s just a case of going through the standard Debian install process to build your Debian VM.

Virtual Machine Manager - Boot ISO
Virtual Machine Manager – Boot ISO
Virtual machine Manager - Running standard Debian install
Virtual machine Manager – Running standard Debian install

Once the installation is complete and the VM has rebooted you will have a functional Debian computer ready to use for whatever you like, just like a physical PC but, in virtual form. You’ll find that the VM runs as fast as the actual physical machine thanks to the kernel based virtualisation.

Virtual Machine Manager - Running VM
Virtual Machine Manager – Running VM

For more information on Virtual Machine Manager take a look at the Ubuntu Server documentation.

More soon …

RaspberryPi OS 13 Networking tidy up & broken lm-sensors

Since RaspberryPi are now forcing users of its SBC to use RaspberryPi OS 13 (via the RaspberryPi Imager tool) instead of the reliably stable Debian 11 or 12 several issues have come to light.

Firstly if like me you run most of the your Pi4/5 SBCs headless/lights out you’ll notice that networking is now ridiculously managed via Network Manager and Netplan.

This is a ridiculous method of managing such a simple device, it’s over complicated, messy and ill thought out. Yet another classic example of change for the sake of change and not to actually improve things.

This combination of Network Manager (often referred to as Network Mangler for good reason) and Netplan is fraught with bugs. Try setting a second IP address on an interface and you’ll find it doesn’t work. nmtui will show the ip address as being configured however, netplan never actually puts the config into play.

Having to use nmtui on the command line to manage ethernet interfaces is also ridiculous. Its badly laid out menu system takes an age to get through to do the simplest of config changes. What’s wrong with just editing the /etc/network/interfaces file?

After much frustration trying to configure the ethernet interface on my headless Pi5 I decided to get rid of this hideous method of managing ethernet interfaces and put it back to using the simple interfaces file.

I’ve documented the steps just in case anyone else wants to do the same.

Step 1: Make sure the traditional networking stack is installed:

sudo apt install ifupdown

Step 2 – Disable NetworkManager:

sudo systemctl stop NetworkManager.service
sudo systemctl disable NetworkManager.service
sudo systemctl mask NetworkManager.service

(Optional but tidy: )

sudo apt purge network-manager

Step 3 – Disable Netplan

sudo apt purge netplan.io
sudo rm -f /etc/netplan/*.yaml

Also ensure /lib/systemd/systemd-networkd is disabled, since Netplan can trigger it:

sudo systemctl disable systemd-networkd
sudo systemctl mask systemd-networkd

Step 4 – Create your /etc/network/interfaces file

# Example /etc/network/interfaces for Ethernet (eth0) with static IP:
#
# Loopback
auto lo
iface lo inet loopback

# Ethernet
auto eth0
iface eth0 inet static
    address 192.168.1.10
    netmask 255.255.255.0
    gateway 192.168.1.1
    dns-nameservers 1.1.1.1 8.8.8.8

Example for DHCP:

auto eth0
iface eth0 inet dhcp

If you use Wi-Fi:

auto wlan0
iface wlan0 inet dhcp
    wpa-ssid "YourSSID"
    wpa-psk "YourPassword"

Step 5 – Enable the traditional networking service

sudo systemctl enable networking.service
sudo systemctl restart networking.service

Then confirm:

ip a

You should see your interfaces up with the expected IP addresses, managed by ifupdown.

Step 6 – (Optionally) Clean residual files

Remove leftover NetworkManager/Netplan configs to avoid confusion:

sudo rm -rf /etc/NetworkManager
sudo rm -rf /etc/netplan

Verification

Check which subsystem is active:

systemctl is-active NetworkManager
systemctl is-active networking

Expected output:

inactive
active

The /etc/network/interfaces method works perfectly on Pi 5 and is lighter weight and ideal for embedded or headless servers.

If you later reinstall NetworkManager, it will override interfaces again unless you mark them as unmanaged in /etc/NetworkManager/NetworkManager.conf.

You can still use ifup / ifdown commands manually for control.

You now have your Pi running the classic, lightweight networking stack which is ideal if you use your Pi as a 24/7 server like I do.

Note: This method is still supported on RaspberryPi Debian 13 but, it’s no longer the default.

As a final note, if you want to add a second IP Address to your Ethernet interface it’s extremely simple to define in the /etc/network/interfaces file. I’ve created an example of how to do this below for reference.

# Loopback
auto lo
iface lo inet loopback

#
# Primary interface - static IP
#
auto eth0
iface eth0 inet static
    address 192.168.1.10
    netmask 255.255.255.0
    gateway 192.168.1.1
    dns-nameservers 1.1.1.1 8.8.8.8

#
# Secondary IP on same interface
#
auto eth0:1
iface eth0:1 inet static
    address 192.168.1.11
    netmask 255.255.255.0

Check both IP Addresses appear on the same interface:

ip a show eth0

For the example above you’ll see:

inet 192.168.1.10/24
inet 192.168.1.11/24

Finally, if like me you use lm-sensors to keep check on how hot your Pi is running you’ll find that the sensors command no longer works, it just throws a segmentation fault. This is a nuisance as I use this as part of my Node-Red Monitoring Dashboard.

A partial work around is to use the vcgencmd command as it can return the temperature of the system on a chip (SOC) device.

vcgencmd measure_temp

You can create an alias for this command in your ~/.profile file, I’ve named the alias ‘cputemp’ in this example:

alias cputemp="vcgencmd measure_temp"

Once you’ve saved your .profile file logout and back in again and you’ll now have a new command to use to get the CPU temp.

More soon …