Home Assistant VM (HAOS on ereshkigal)#

Home Assistant used to run on the HA Green appliance. In July 2026 that appliance’s external USB data disk dropped out and the Supervisor wedged at “waiting for the Home Assistant CLI to be ready” — a ~10 h outage that also took down the MQTT broker, the tailnet subnet router, and IoT reachability, because all of it lived on that one box. Home Assistant now runs as a Home Assistant OS (HAOS) VM on ereshkigal, which is always-on, on real storage, and borg-backed.

Because it’s a full HAOS VM (not HA Core), the encrypted appliance backup — with all ~19 add-ons (Matter, Node-RED, AdGuard, InfluxDB, Grocy + BarcodeBuddy, Music Assistant, Mosquitto, ESPHome, …) — restores 1:1.

Architecture#

Piece Value
Host ereshkigal (libvirt/qemu, system connection)
Domain haos — persistent, autostart enabled (reboot-safe)
Firmware / machine UEFI (OVMF, default on 26.05) / q35 / swtpm
Resources 2 vCPU, 4 GiB RAM
Disk /dev/disk/by-uuid/434354c2-7991-4e02-afcc-6c17d25bd2fd (HAOS 18.1 OVA image on lvm)
LAN NIC virtio, bridged to vmbr0192.168.0.55 (took over the old appliance’s IP)
IoT NIC virtio, bridged to br-iot192.168.2.55 (IoT VLAN, tag 3)
Radio Nabu Casa Connect ZBT-1 (Zigbee/Thread) via VFIO passthrough of the whole 0000:41:00.0 USB controller (alone in IOMMU group 14)

The declarative side lives in modules/nixos/virtualization/haos-vm.nix (tsunaminoai.haosVm, enabled on ereshkigal). Creating/onboarding/restoring the VM is interactive and is not in a nixos switch — see below.

Access#

  • Web UI: http://192.168.0.55:8123
  • Console (onboarding / recovery): sudo virsh vncdisplay haos on ereshkigal, then ssh -L 5900:127.0.0.1:5900 ereshkigal and point a VNC client at localhost:5900.
  • HAOS CLI: the console ha > prompt; login drops to the host shell.
  • virsh needs sudo on ereshkigal (polkit blocks the system connection over non-interactive SSH).

Networking: the IoT-VLAN leg#

The VM is dual-homed. Its LAN leg (192.168.0.55) carries the default route, DNS, and the frontend. Its IoT leg (192.168.2.55) lets IoT devices on 192.168.2.0/24 discover and reach HA (mDNS, direct connections).

On the host, haosVm.iotLeg peels VLAN 3 off the LAN trunk into an L2-only bridge the VM attaches to — the host takes no IP on it, which is why this avoids the exit-node policy routing and Tailscale table-52 precedence that would otherwise fight a routed IoT leg:

bond1 (LAN trunk) ──┬── vmbr0        (untagged LAN, 192.168.0.20)
                    └── bond1.3 ──── br-iot ──── vnet (VM's 2nd NIC)

Requirements:

  • Unifi: the switch port(s) for bond1 must trunk VLAN 3. (On the USW Pro 24 the ereshkigal LAG uses Tagged VLAN Management → Allow All, so this is already satisfied.)
  • VM NIC (persistent, once): the second NIC must have a fixed MAC or HAOS treats each re-attach as a new interface and its config won’t stick:
sudo virsh attach-interface --domain haos --type bridge \
  --source br-iot --model virtio --persistent --live
  • HAOS side: set the second adapter static, no gateway (keep the default route on the LAN leg). Match it by MAC in ha network info:
ha network update <iface2> --ipv4-method static --ipv4-address 192.168.2.55/24

Recovery / gotchas#

Things that bit us during the cutover — check these first:

  • Frontend (:8123) dead but the observer (:4357) is green → HA Core’s http integration failed to start, almost always because configuration.yaml points ssl_certificate/ssl_key at cert files that aren’t present. Comment those lines (vi /mnt/data/supervisor/homeassistant/configuration.yaml from the host shell) and ha core restart, or restore the /ssl folder.
  • A hot-plugged NIC doesn’t show in ha network info → the Supervisor only enumerates interfaces at boot. core restart / net reload don’t re-scan. Reboot the VM (ha host reboot); the NIC is in the persistent config so it comes back and gets enumerated.
  • Keep the HA Green appliance powered OFF. It also claims 192.168.0.55 statically — powering it on causes an IP conflict with the VM.
  • Do not plug anything into the NEC 0000:41:00.0 controller on ereshkigal. The whole controller is VFIO-bound to the VM; anything on it vanishes into the guest (the LimeSDR was moved to mokou for this reason).
  • Don’t let HAOS re-adopt an external USB “data disk.” That dependency is what caused the original outage; keep HA’s data on the VM’s virtual disk (borg backs up ereshkigal).

Rebuild from scratch#

  1. Deploy ereshkigal with tsunaminoai.haosVm.enable = true (the haos-vm-image service fetches + verifies the pinned HAOS image).
  2. haos-vm-install on ereshkigal — creates + autostarts the domain (with the radioPci controller passthrough).
  3. Console in over VNC, onboard, restore the encrypted backup (enter the emergency-kit key). All add-ons + config come back.
  4. Add the IoT-leg NIC and configure it in HAOS (see Networking above).