Home Assistant (Supervised) on Incus/LXC: a lightweight installation for the post-AI economy

Home Assistant has really let itself go. Only a couple of years ago, you were able to run Home Assistant on a Raspberry Pi 3B with 1GB of RAM. Now it struggles with 2GB, and some users even recommend 4GB-8GB for comfort. To add insult to injury, the two most lightweight installation methods were recently retired. You are now forced to dedicate a whole computer to Home Assistant OS, create a virtual machine with RAM reserved for Home Assistant OS, or choose the Container method and sacrifice the ability to manage add-ons seamlessly. This is obviously a deplorable state of affairs in the post-AI economy.

It doesn’t have to be this way. I’m going to show you one weird trick to cut the fat, discovered by a stay-at-home mom cosplaying as a sysadmin, that Big Pharma doesn’t want you to know.

Here, I document the easy process to add a Home Assistant Supervised installation to an existing Linux server with Incus/LXC. The result is a near-HAOS experience, complete with add-on management UI, that shares resources with the rest of your homelab. This is ideal for testing instances. LXC does not offer as much isolation as full virtualization, of course, but I would hope you trust the software that controls your home. This installation method is also unsupported, unfortunately, and this is my vote to bring Supervised back.

  1. Start with Incus on a Linux server. You could do this any way you want. This should work with vanilla LXC if you’re willing to do some extra work.

  2. Create a Debian container. You’re going to want a privileged container that supports nested containers.

host# incus create images:debian/13 homeassistant -c security.privileged=true -c security.nesting=true
  1. Configure the network. You could forward port 8123 to the container or set up a bridge. If you had separate VLANs for your trusted devices and your smart devices, you could add the container to both. You could mix and match:
host# incus config device add homeassistant proxy-8123 proxy listen=tcp:0.0.0.0:8123 connect=tcp:127.0.0.1:8123
host# incus config device add homeassistant eth0 nic nictype=bridged parent=br0
host# incus config device add homeassistant eth1 nic nictype=bridged parent=br1
  1. Install Home Assistant (Supervised) in the container. During the installation process, homeassistant-supervised.deb is going to try and fail to set /proc/sys/kernel/dmesg_restrict. The “right” way is to patch that out of the preinst script. We’re going to take the quick and dirty way of protecting /proc/sys/kernel with a tmpfs. We’ll also need a little script to start Home Assistant on boot.
host# incus start homeassistant
host# incus exec homeassistant bash

homeassistant# apt update && apt install -y lsb-release curl
homeassistant# source /etc/os-release
homeassistant# curl -fsSL https://download.docker.com/linux/${ID}/gpg -o /etc/apt/keyrings/docker.asc
homeassistant# echo "deb [signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/${ID} ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list
homeassistant# curl -LO https://github.com/home-assistant/supervised-installer/releases/download/4.0.1/homeassistant-supervised.deb
homeassistant# curl -LO https://github.com/home-assistant/os-agent/releases/download/1.8.1/os-agent_1.8.1_linux_x86_64.deb

homeassistant# mount -t tmpfs none /proc/sys/kernel
homeassistant# apt update && apt install -y ./homeassistant-supervised.deb ./os-agent_1.8.1_linux_x86_64.deb
homeassistant# umount /proc/sys/kernel
homeassistant# systemctl restart systemd-resolved
homeassistant# dpkg --configure -a
homeassistant# rm homeassistant-supervised.deb os-agent_1.8.1_linux_x86_64.deb

homeassistant# echo '#!/bin/sh' > /etc/rc.local
homeassistant# echo 'while ! /usr/bin/ha core start; do sleep 2; done' >> /etc/rc.local
homeassistant# echo '/usr/bin/ha network reload' >> /etc/rc.local
homeassistant# echo 'exit 0' >> /etc/rc.local
homeassistant# chmod +x /etc/rc.local
  1. Restart the container. Although the web UI appears to be up, there are some subtle issues that linger until restarting.
host# incus restart homeassistant

Bonus: Assign optional peripherals, such as Zigbee or Z-Wave dongles:

host# incus config device add homeassistant sonoff-zbdongle-e unix-char required=false source=/dev/serial/by-id/usb-Itead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_V2... path=/dev/ttyUSB0
host# incus config device add homeassistant zooz-zst39 unix-char required=false source=/dev/serial/by-id/usb-Zooz_800_Z-Wave_Stick... path=/dev/ttyACM0

Problem: /usr/bin/ha fails with “OCI runtime exec failed: exec failed: unable to start container process: error executing setns process: exit status 1”.

Try restarting the container.

Problem: Docker container hassio_supervisor fails with “ERROR (MainThread) [supervisor.host.logs] Unable to connect to systemd-journal-gatewayd”.

You might have encountered this issue. Try updating the host or applying this workaround in the guest:

homeassistant# sed -ri 's/^(User=)/#\1/' /lib/systemd/system/systemd-journal-gatewayd.service
homeassistant# sed -ri 's/^(DynamicUser=)/#\1/' /lib/systemd/system/systemd-journal-gatewayd.service
homeassistant# systemctl daemon-reload
homeassistant# systemctl restart systemd-journal-gatewayd
homeassistant# docker restart hassio_supervisor

Problem: Home Assistant does not start on boot.

Start it with ha core start, or create the startup script as above.

Problem: Home Assistant is unable to install add-ons because “‘AddonManager.install’ blocked from execution, no host internet connection”. ha network info shows “host_internet: false”.

It was DNS. Restart it with ha network reload, or create the startup script as above.