HAOS on Arch host via KVM

Following the virt-install route in Linux - Home Assistant I have spun up a VM for the qcow2 image, which boots fine and after enabling dropbear from virsh -e '^c' console haos I can access the virtual machine via SSH.

The VM successfully binds 192.168.122.121 and I can curl it after various HA startup processes. The problem I have now is that the /auth/token and /api/websocket endpoints refuse to work in any capacity. They return 400 and 401 respectively.

My nginx config is:

server {
  listen 443 ssl;
  listen [::]:443 ssl;
  http2 on;

  server_name ha.mini.lan;

  ssl_certificate /etc/ssl/nginx/mini.lan.crt;
  ssl_certificate_key /etc/ssl/nginx/mini.lan.key;

  proxy_buffering off;

  location / {
    # Various iterations of proxy goop

    proxy_pass http://192.168.122.121:8123;
  }
}

No matter what I try in nginx, these endpoints refuse to work.

I have also tried poking reverse proxy settings in /mnt/data/supervisor/homeassistant/configuration.yaml (after creating it), but nothing. I also get no usable logs from ha core logs to begin troubleshooting.

I tried searching, but there doesn’t seem to be a recent enough thread about installation on a headless server with an nginx reverse proxy.

Something like this in your configuration.yaml?

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 192.168.122.XXX

It’s no longer in configuration.yaml anymore

Sorry for that, was the old version of doing the rev proxy configuration.
Remove the http section from configuration.yaml, before you type in the rev proxy in the GUI.

Settings → System → Network → Reverse Proxy

My problem is that I can’t access anything. I have https://ha.mini.lan proxied to the VM’s IP, the page loads, but the 2 endpoints mentioned fail with 401 and 400 errors. I tried proxying in a way that makes it look like the request isn’t being proxied. Like I mentioned even curl fails on the endpoints with Bad Request response.

I’m running the haos_ova-18.2.qcow2 image linked in the Linux install page that I downloaded 8 hours ago.

I have been messing around and got different results now. I have this network for virtsh:

$ sudo virsh net-dumpxml default
<network connections='1'>
  <name>default</name>
  <uuid>3355001d-8a93-436d-82b2-4c1b81121997</uuid>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='virbr0' stp='on' delay='0'/>
  <mac address='52:54:00:59:f1:b4'/>
  <dns enable='no'/>
  <ip address='192.168.122.1' netmask='255.255.255.0'/>
</network>

Installed the image with this command:

sudo virt-install \
  --name haos \
  --memory memory=4096,currentMemory=1024 \
  --vcpus 2 \
  --cpu host \
  --machine q35 \
  --disk /var/lib/libvirt/images/haos_ova-18.2.qcow2,format=qcow2,bus=virtio \
  --os-variant generic \
  --network network=default,model=virtio \
  --graphics none \
  --video none \
  --console pty,target_type=serial \
  --boot uefi \
  --memballoon virtio \
  --import --noautoconsole

After waiting a bit I can enter the console of the VM:

sudo virsh -e '^c' console haos

Inside the VM I do some setup to assign an IP and setup DNS, because on the host I am running Technitium DNS Server and dnsmasq would otherwise conflict with that:

(
  c=$(nmcli c show | awk '$NF != "lo" && $NF != "DEVICE" { a = $1; for (i = 2; i < NF; i++) { if (length($i) == 36) break; a = a " " $i } print a }')
  nmcli c modify "$c" \
    ipv4.method manual \
    ipv4.addresses 192.168.122.121/24 \
    ipv4.gateway 192.168.122.1 \
    ipv4.dns 192.168.122.1 \
    ipv4.ignore-auto-dns yes \
    autoconnect yes \
  && nmcli c down "$c" && nmcli c up "$c"
)
mkdir .ssh 2> /dev/null; printf %s\\n 'ssh-ed25519 ...' > .ssh/authorized_keys
systemctl enable --now dropbear
ha dns options --fallback=false && ha dns options --servers dns://192.168.122.1

This also makes the server accessible with ssh -t -p 22222 [email protected].

The exact server block in nginx:

server {
  listen 443 ssl;
  listen [::]:443 ssl;
  http2 on;

  server_name ha.mini.lan;

  ssl_certificate /etc/ssl/nginx/mini.lan.crt;
  ssl_certificate_key /etc/ssl/nginx/mini.lan.key;

  proxy_buffering off;

  location / {
    proxy_redirect http:// https://;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    proxy_read_timeout 60s;
    proxy_connect_timeout 60s;
    proxy_send_timeout 60s;

    proxy_pass http://192.168.122.121:8123;
  }
}

Now my issue is that HA gives me a redirect loop:

$ curl -s -k -I https://ha.mini.lan | grep -ie location: # via nginx
location: https://ha.mini.lan/
$ curl -s -I http://192.168.122.121:8123 | grep -ie location: # direct
Location: http://192.168.122.121/
$ curl http://192.168.122.121:80 # prints nothing

Alright, I managed to figure out that HA is running just fine, but on port 80 instead of 8123, because that just redirects to 80.

To access HA in the VM I tunneled my connection via SSH:

ssh -L 0.0.0.0:7123:localhost:80 -p 22222 [email protected] -N

This worked like a charm and I managed to finish the onboarding and set the reverse proxy settings. Now in nginx I proxy to the IP of the guest VM:

proxy_pass http://192.168.122.121;

With that I can access HA via my preferred URL.

I have created a bridge interface via nmcli and slaved my ethernet interface to it. Now I can reassign the static lease to the new MAC of the host machine and create a static lease for HA OS guest VM on my OpenWrt router.

This enables the VM to discover devices on the LAN.

I will receive my Reolink camera soon, so I’ll report back here in case that also needs some further setup to get Frigate and HA to cooperate.

I have decided to host Frigate on the host via systemd quadlets and installed the Frigate Proxy addon in HA OS. That solves access to the GPU. I think that concludes the purpose of this thread.