Installing KVM and deploying Home Assistant OS
Since the install page only describes how to use KVM via a GUI, and I am using KVM in a server setting, I thought I’d share a quick guide to how to do this from CLI only.
NOTE: This was originally writted for Ubuntu Server LTS 20.04, but others have confirmed it to work on 22.04 and 24.04 as well, and I suspect it will work for many Debian-based systems. Please report both if you have success on other systems, and if not.
NOTE: I know very little about VMs. The reason I made this guide is because I could have used one If there is something wrong, or something that could be done smarter, please let me know!
1 - Preparation
I’ll assume you have your OS installed, and have sudo rights. I’ll also assume you are working as root. If not, add a sudo
to commands as needed.
First, check that your CPU can run VMs.
egrep -c '(vmx|svm)' /proc/cpuinfo
As long as it doesn’t return 0
, then you’re good. Next, check that it can use KVM acceleration
kvm-ok
1.1 - Install KVM and dependencies
KVM might be installed already, the same with OVMF (needed to start a VM with UEFI) but just in case.
apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils ovmf virt-manager
1.2 - Add user to libvirt and kvm groups
adduser [USER] libvirt
adduser [USER] kvm
where [USER] is the user that will deploy VMs
1.3 - Check that install was successful
systemctl status libvirtd
It should say that it is running. If not, then
systemctl enable --now libvirtd
1.4 - Create directories and download image
The image shown to download here is the one available when I tried. Find the current qcow2 image from the Home Assistant install page, and replace the link after the wget
command.
mkdir -vp /var/lib/libvirt/images/hassos-vm && cd /var/lib/libvirt/images/hassos-vm
wget https://github.com/home-assistant/operating-system/releases/download/6.6/haos_ova-6.6.qcow2.xz
1.5 - Set up a storage pool
virsh pool-create-as --name [NAME] --type dir --target /var/lib/libvirt/images/hassos-vm
where [NAME] is the name you want (for this guide, I used hassos
).
2 - Set up network
From what I’ve seen, unless you know you have a specific reason not to, you should create a new network bridge (that we’ll call br0
here).
Start by finding the network interface you are using for network access.
ifconfig
The one you’re looking for is the that has a line that starts with inet
followed by the local IP of the machine. For me, it was eno1
, so this one (with inet 192.168.0.100
):
eno1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.0.100 netmask 255.255.255.0 broadcast 192.168.0.255
inet6 fe80::bc0a:58ff:fef3:d16a prefixlen 64 scopeid 0x20<link>
ether 00:21:5e:c6:43:04 txqueuelen 1000 (Ethernet)
RX packets 6569964 bytes 18454336926 (18.4 GB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 6806881 bytes 721261424 (721.2 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
You can create bridges in different ways, if you’re familiar with others, that shouldn’t make a difference. I used Netplan. Edit the Netplan config:
nano /etc/netplan/00-installer-config.yaml
Before editing, it looked like this:
# This is the network config written by 'subiquity'
network:
ethernets:
eno1:
dhcp4: true
version: 2
Add lines for the bridge, so the file looks like this afterwards:
# This is the network config written by 'subiquity'
network:
ethernets:
eno1:
dhcp4: true
version: 2
bridges:
br0:
dhcp4: yes
interfaces:
- eno1
parameters:
stp: true
Of course replacing eno1
with your interface.
OBS! If using static IP, it might be different. See @Raul_7 's post for how to do in that case.
OBS! He also recommends doing netplan generate
to catch any errors before netplan apply
!
Check for any errors with:
netplan generate
If none, then apply changes, and check:
netplan apply
brctl show
The last command should output a list of bridges, and the newly created br0
should be among them.
bridge name bridge id STP enabled interfaces
br0 8000.00215ec64304 yes eno1
After starting the VM (see below), this command will also show vnet0
under interfaces
.
2.1 - Turn off firewall for KVM interface
NOTE This is an alternate to disabling netfilter (see crossed out section below) provided by @gacopl (see this post, or this post for details)
NOTE There is another alternative suggested by @brady in this post where you instead tell Docker that the bridge exists.
Edit the docker.service
sudo systemctl edit docker.service
and insert:
[Service]
ExecStartPost=/usr/sbin/iptables -I DOCKER-USER -i br0 -o br0 -j ACCEPT
replacing br0
with the bridge you use for KVM. Then reload the docker daemon and restart docker to take effect.
sudo systemctl daemon-reload
sudo systemctl restart docker
## 2.1 - Disable netfilter on the bridge(s)
NOTE! Be very careful about this, and read the section thoroughly before attempting!
For performance (and security?) reasons, you can choose to disable netfilter on the bridge. However, this can mess up your network so the bridge (and hence physical network interface) no longer has network. So be sure to (1) know what you are doing, (2) have physical keyboard/monitor access, or (3) have multiple network connections to the machine.
Thus, be VERY careful. It worked for me, but I’ll give no guarantees.
Create a file
</s> <s>sudo nano /etc/sysctl.d/bridge.conf</s> <s>
And insert the following:
</s> <s>net.bridge.bridge-nf-call-ip6tables=0</s> <s>net.bridge.bridge-nf-call-iptables=0</s> <s>net.bridge.bridge-nf-call-arptables=0</s> <s>
Create a file
</s> <s>sudo nano /etc/udev/rules.d/99-bridge.rules</s> <s>
And enter:
</s> <s>ACTION=="add", SUBSYSTEM=="module", KERNEL=="br_netfilter", RUN+="/sbin/sysctl -p /etc/sysctl.d/bridge.conf"</s> <s>
Reboot the machine.
3 - Install HassOS VM
Install the downloaded qcow2 image. The file type you can download has changed since I first tried, but you’ll likely need to unzip. Last I checked (HassOS v6.6), it was a .xz
file, so unzip by (replacing haos_ova-6.6.qcow2.xz
with the name of the file downloaded):
xz -d -v haos_ova-6.6.qcow2.xz
Assuming you’ve used the same names for VM (hassos
), the qcow image (haos_ova-6.6.qcow2
), and the bridge (br0
) as in this guide:
Tested on Ubuntu Server LTS 20.04
cd /var/lib/libvirt/images/hassos-vm
virt-install --import --name hassos \
--memory 4096 --vcpus 4 --cpu host \
--disk haos_ova-6.6.qcow2,format=qcow2,bus=virtio \
--network bridge=br0,model=virtio \
--osinfo detect=on,require=off \
--graphics none \
--noautoconsole \
--boot uefi
Tested on Ubuntu Server LTS 22.04
cd /var/lib/libvirt/images/hassos-vm
virt-install --import --name hass \
--memory 4096 --vcpus 4 --cpu host \
--disk haos_ova-11.1.qcow2,format=qcow2,bus=virtio \
--network bridge=br0,model=virtio \
--osinfo detect=on,require=off \
--graphics none \
--noautoconsole \
--boot uefi
After a few moments, you should see a new homeassistant
show up on your network. Navigate to the IP it shows up at, port 8123, just like any other Home Assistant instance.
NOTE If you followed the guide, you would have the *.qcow2 image in the /var/lib/libvirt/images/hassos-vm
directory. If you have unpacked it somewhere else, make sure to use the full path in the --disk
argument.
NOTE: If you’re stuck at UEFI shell, @MrksHfmn suggests that you try disable secure booting from BIOS. See this post.
NOTE: Any VM will have its own MAC address, which is different from the host, and will thus be assigned its own IP, that is different from the host IP. If you have access to your router config, you can usually see it under “connected devices” with the name “homeassistant”. You can then assign a static IP in your DHCP (probably done in your router, highly recommended). You can assign a MAC address under network with --network mac=52:54:00:XX:XX:XX
. Keep in mind it has to start with 52:54:00
.
If you don’t specify this, and need to find the MAC address via CLI in ubuntu, use:
virsh dumpxml hassos | grep "mac address" | awk -F\' '{ print $2}'
NOTE: I assigned a DHCP of 192.168.1.115
, the same IP I set for the br0
. I’m not certain that it is required to do both. If anyone tries this, could you please report back so I can update?
As noted in a comment, per the 2020-12 release, you can also add a static IP by navigating to supervisor > system > host and click on change next to the IP Address.
4 - After install
In case you want to stop (or start) the VM (e.g. for doing backups), you can do that using the virsh
command.
One that you might want to set up right away is the autostart of the VM
virsh autostart hassos
Another might be to pass USB sticks, e.g. a ZigBee or Z-wave radio. Follow this.
You might have issues where after a reboot of Ubuntu, it doesn’t show up. In that case, I have found that detatching and attaching again solves this, assuming the file is /var/lib/libvirt/images/hassos-vm/conbeeii.xml
, then do:
virsh detach-device hassos --file /var/lib/libvirt/images/hassos-vm/conbeeii.xml --persistent
virsh attach-device hassos --file /var/lib/libvirt/images/hassos-vm/conbeeii.xml --persistent
Other than that:
virsh help
shows you what you can do. Particularly useful might be the following:
To list VMs
virsh list
Or to view all (also stopped):
virsh list --all
If [VM_NAME] is the name of the VM (hassos
in our example):
To start:
virsh start [VM_NAME]
To gracefully stop, and leave inactive
virsh destroy [VM_NAME] --graceful
Remove the --graceful
to forcibly stop instead.
To shutdown VM:
virsh shutdown [VM_NAME]
Credits
Thanks to @oldrobot for reminding me to mention unzipping the downloaded HassOS qcow2 file.
Thanks to @wmaker, @oldrobot, as well as an answer on askubuntu for the update to network configuration.
Thanks to @sebkouba for pointing out that I should emphasize that a DHCP reservation is a very good idea.
Thanks to @uSlackr and @broken.pipe for correcting typos/copy-paste errors.
Thanks to @bisaflor for pointing out that you can change IP in the Hass UI.
Thanks to @Raul_7 for help with networking, especially in relation to using static IP (see his post for details) and catching some errors I made when updating the guide.
Thanks to @MrksHfmn for the suggestion about disabling secure boot if stuck at UEFI shell.
Thanks to @gacopl for an alternate suggestion instead of disabling netfilter on the bridge.
Several more at this point, but there’s a limit to the number of “mentions”. I really appreciate the rest of your comments/suggestions/test as well, even if I can’t @ mention.