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 is for Ubuntu Server LTS 20.04, but I suspect it will work for many Debian-based systems. Please report both is 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
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
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 - Crete 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. Also change the file name used in the
mv commands to the name of the file downloaded.
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/4.16/hassos_ova-4.16.qcow2.gz gunzip hassos_ova-4.16.qcow2.gz mv hassos_ova-4.16.qcow2 hassos.qcow2
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
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
Start by finding the network interface you are using for network access.
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
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:
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.
Apply change, 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
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
sudo nano /etc/sysctl.d/bridge.conf
And insert the following:
net.bridge.bridge-nf-call-ip6tables=0 net.bridge.bridge-nf-call-iptables=0 net.bridge.bridge-nf-call-arptables=0
Create a file
sudo nano /etc/udev/rules.d/99-bridge.rules
ACTION=="add", SUBSYSTEM=="module", KERNEL=="br_netfilter", RUN+="/sbin/sysctl -p /etc/sysctl.d/bridge.conf"
Reboot the machine.
3 - Install HassOS VM
Install the downloaded qcow2 image. The file type you download has varied, but you’ll likely need to unzip. Last I checked (HassOS v5.9), it was a
.xz file, so unzip by::
xz -d -v hassos_ova-5.9.qcow2.xz
Assuming you’ve used the same names as in this guide:
cd /var/lib/libvirt/images/hassos-vm virt-install --import --name hassos \ --memory 4096 --vcpus 4 --cpu host \ --disk hassos.qcow2,format=qcow2,bus=virtio \ --network bridge=br0,model=virtio \ --os-variant=rhel8.1 \ --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: 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). 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
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?
4 - After install
In case you want to stop (or start) the VM (e.g. for doing backups), you can do that using the
shows you what you can do. Particularly useful might be the following:
To list VMs
Or to view all (also stopped):
virsh list --all
If [VM_NAME] is the name of the VM (
hassos in our example):
virsh start [VM_NAME]
To gracefully stop, and leave inactive
virsh destroy [VM_NAME] --graceful
--graceful to forcibly stop instead.
To shutdown VM:
virsh shutdown [VM_NAME]