Setting up KVM virtual machines using a bridge network on an Ubuntu host
I recently wanted to set up a VM on my home Ubuntu 22.04 LTS server, with the following goals:
- the VM uses KVM virtualization, for performance
- the guest VM is assigned an IP via DHCP by my home network router
- the guest VM is accessible by everything on the home network, including the host
- the setup process relies entirely on CLI tools
Requirement (2) means I’ll need to set up a bridge network interface on the host. Requirement (3) rules out — as far as I understand, anyway — using macvlan networking for the guest.
This (admittedly terse) blog post walks through the process I used to get this working.
Basic virtualization setup
Install the required software:
sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients virtinst libguestfs-tools libosinfo-bin bridge-utils
Verify the host’s CPU will support KVM virtualization:
$ kvm-ok
INFO: /dev/kvm exists
KVM acceleration can be used
Add your user to the relevant groups. This will allow you to manage VMs without sudo
:
sudo adduser cdzombak libvirt
sudo adduser cdzombak kvm
You’ll need to log out and back in for those changes to take effect. Verify this change with the id
command.
Check that libvirtd is running:
$ sudo systemctl status libvirtd
🟢 libvirtd.service - Virtualization daemon
Loaded: loaded (/lib/systemd/system/libvirtd.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2024-01-31 20:47:10 EST; 17h ago
Networking setup
Run ip add
and note the name of your Ethernet interface. In my case, it’s enp0s31f6
.
Examine the contents of /etc/netplan
. In my case, there was one file, with these contents:
network:
ethernets:
enp0s31f6:
dhcp4: true
version: 2
If yours differs substantially, take care to understand what this file is doing! Some of the reference links below might help.
Back up the YAML file from /etc/netplan
, then edit it. Add a bridges
section, so the result looks like the following code sample. Note that enp0s31f6
should be replaced by the name of your Ethernet interface:
network:
version: 2
ethernets:
enp0s31f6:
dhcp4: true
bridges:
br0:
dhcp4: yes
interfaces:
- enp0s31f6
Test it with sudo netplan try
. This allows you to test the configuration and make sure it’s working properly. It will offer to make the changes permanent for you, and if you don’t accept that prompt within a minute or two the changes will be reverted automatically.
Assuming that it worked, br0
is now assigned an IP address by your local DHCP server. You can verify this by running ip add
.
You’ll need to update DHCP reservations for the host, if you have any, to use the MAC address of the bridge interface. ip add
will show you this MAC address.
Finally, create a file called kvm-hostbridge.xml
in a location of your choice, with the following content:
<network>
<name>hostbridge</name>
<forward mode="bridge"/>
<bridge name="br0"/>
</network>
Create and enable this network by running:
virsh net-define /path/to/my/kvm-hostbridge.xml
virsh net-start hostbridge
virsh net-autostart hostbridge
iptables considerations for hosts that also run Docker
Installing Docker enables netfilter for bridge interfaces on the host machine. This is needed because Docker creates and manages iptables rules to isolate bridge networks — the default Docker network type — from each other and allow them access to the network.
These rules will, by default, break networking for your VMs. In my case I wanted all VMs to have access to the network as if they were real, physical machines; and to do this I added a single iptables rule on the host:
sudo iptables -A FORWARD -p all -i br0 -j ACCEPT
My guest VM was unable to get a DHCP reservation until I did this.
I am far from an iptables expert, but this worked for me. I'm not too worried because this host is not directly accessible on the Internet; it's only exposed to my LAN and Tailscale network. If you're doing this on a host with an Internet-facing attack surface, you should probably spend more time studying and understanding this.
Creating a VM on this network
🎉 Assuming nothing has failed so far, you’re ready to create a VM connected to this network.
To use this network when creating a VM, pass --network network=hostbridge
to virt-install
. Here’s a complete example which I used successfully:
virt-install \
--name altdns \
--description "alternate DNS server for the home network" \
--memory 2048 \
--vcpus 2 \
--disk path=/mnt/storage/vm/altdns/disk.qcow2,size=32 \
--cdrom /mnt/scratch/ubuntu-22.04.3-live-server-amd64.iso \
--graphics vnc \
--os-variant ubuntu22.04 \
--virt-type kvm \
--autostart \
--network network=hostbridge
(virt-install --help
can help you figure out what the other options do.)
After the machine boots, your router should see it as a new machine and issue it an IP address over DHCP just as it would anything else on the network.
Accessing the installer over VNC
The command above tells virt-install
we want to use VNC to view the VM’s display and give it keyboard/mouse input. Note that you’ll connect to the host and not to the guest’s IP address with your VNC client.
First, figure out which port to use.
$ virsh vncdisplay altdns
127.0.0.1:1
This tells us that we can connect to the VNC server on the host’s port 5900 + 1
.
It also tells us that the VNC server on this host is listening on localhost
only. You can use SSH port forwarding to create a tunnel from port 5999
on your desktop to port 5901
on the server:
ssh -L 5999:localhost:5901 my-vm-host.local
Once that’s up and running, you can open your favorite VNC client, connect to localhost:5999
(no authentication required), and walk through the Ubuntu installer to get your VM up and running.
Helpful commands
When troubleshooting or trying to understand the network state on your host VM, the following commands are useful:
virsh net-list
virsh net-info hostbridge
virsh net-dhcp-leases hostbridge
sudo brctl show br0
References
- How to Configure Network Bridge in Ubuntu
- Install KVM on Ubuntu 20.04 {+ Create a Virtual Machine}
- How to install KVM on Ubuntu 20.04 LTS Headless Server
- Bridging Network Connections
- KVM: How to make VM get IP from same DHCP as host?
- Setting up a bridge for host and vm
- Bridge Networks For KVM On Ubuntu 22.04 Server
- Network bridge
- How do I configure DHCP bridge with netplan for KVM on Ubuntu 18.04 LTS?
- NetworkConnectionBridge - Community Help Wiki
- Can I have my KVM guests on the same subnet as the host?
- Bridged network — libvirt Networking Handbook — Jamie Nguyen
- Bug 512206 - Disable net.bridge.bridge-nf-call-*tables by default
- How does iptable work with linux bridge?
- KVM Public bridge, VMs not getting IPs
- KVM client no dhcp with host bridge when docker is running
- Iptables - Bridge and Forward chain