diff --git a/configurations/nixos/defiant/configuration.nix b/configurations/nixos/defiant/configuration.nix
index f7131fd..7209aa9 100644
--- a/configurations/nixos/defiant/configuration.nix
+++ b/configurations/nixos/defiant/configuration.nix
@@ -91,10 +91,10 @@
         };
       };
     };
-    home-assistant = {
-      enable = false;
-      subdomain = "home";
-    };
+    # home-assistant = {
+    #   enable = false;
+    #   subdomain = "home";
+    # };
     adguardhome = {
       enable = false;
     };
@@ -178,6 +178,12 @@
       enable = true;
       subdomain = "search";
     };
+
+    virt-home-assistant = {
+      enable = false;
+      networkBridge = "bond0";
+      hostDevice = "0x10c4:0xea60";
+    };
   };
 
   # disable computer sleeping
diff --git a/modules/nixos-modules/server/default.nix b/modules/nixos-modules/server/default.nix
index 956ad9e..6c3ba8e 100644
--- a/modules/nixos-modules/server/default.nix
+++ b/modules/nixos-modules/server/default.nix
@@ -8,7 +8,7 @@
     ./jellyfin.nix
     ./forgejo.nix
     ./searx.nix
-    ./home-assistant.nix
+    ./virt-home-assistant.nix
     ./adguardhome.nix
     ./immich.nix
   ];
diff --git a/modules/nixos-modules/server/home-assistant.nix b/modules/nixos-modules/server/home-assistant.nix
index 254e183..a90bd6d 100644
--- a/modules/nixos-modules/server/home-assistant.nix
+++ b/modules/nixos-modules/server/home-assistant.nix
@@ -1,6 +1,7 @@
 {
   lib,
   config,
+  inputs,
   ...
 }: let
   configDir = "/var/lib/hass";
@@ -16,81 +17,114 @@ in {
 
   config = lib.mkIf config.host.home-assistant.enable (lib.mkMerge [
     {
-      systemd.tmpfiles.rules = [
-        "f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass"
-      ];
-      services.home-assistant = {
-        enable = true;
-        configDir = configDir;
-        extraComponents = [
-          "met"
-          "radio_browser"
-          "isal"
-          "zha"
-          "jellyfin"
-          "webostv"
-          "tailscale"
-          "syncthing"
-          "sonos"
-          "analytics_insights"
-          "unifi"
-          "openweathermap"
-        ];
-        config = {
-          http = {
-            server_port = 8082;
-            use_x_forwarded_for = true;
-            trusted_proxies = ["127.0.0.1" "::1"];
-            ip_ban_enabled = true;
-            login_attempts_threshold = 10;
-          };
-          # recorder.db_url = "postgresql://@/${db_user}";
-          "automation manual" = [];
-          "automation ui" = "!include automations.yaml";
-        };
-        extraPackages = python3Packages:
-          with python3Packages; [
-            hassil
-            numpy
-            gtts
+      virtualisation.libvirt = {
+        swtpm.enable = true;
+        connections."qemu:///session" = {
+          networks = [
+            {
+              definition = inputs.nix-virt.lib.network.writeXML (inputs.nix-virt.lib.network.templates.bridge
+                {
+                  uuid = "d57e37e2-311f-4e5c-a484-97c2210c2770";
+                  subnet_byte = 71;
+                });
+              active = true;
+            }
+          ];
+          domains = [
+            {
+              definition = inputs.nix-virt.lib.domain.writeXML (inputs.nix-virt.lib.domain.templates.linux
+                {
+                  name = "Home Assistant";
+                  uuid = "c5cc0efc-6101-4c1d-be31-acbba203ccde";
+                  memory = {
+                    count = 4;
+                    unit = "GiB";
+                  };
+                  # storage_vol = {
+                  #   pool = "MyPool";
+                  #   volume = "Penguin.qcow2";
+                  # };
+                });
+            }
           ];
-      };
-      host = {
-        reverse_proxy.subdomains.${config.host.home-assistant.subdomain} = {
-          target = "http://localhost:${toString config.services.home-assistant.config.http.server_port}";
-
-          websockets.enable = true;
-          forwardHeaders.enable = true;
-
-          extraConfig = ''
-            add_header Upgrade $http_upgrade;
-            add_header Connection \"upgrade\";
-
-            proxy_buffering off;
-
-            proxy_read_timeout 90;
-          '';
         };
       };
+
+      # systemd.tmpfiles.rules = [
+      #   "f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass"
+      # ];
+      # services.home-assistant = {
+      #   enable = true;
+      #   configDir = configDir;
+      #   extraComponents = [
+      #     "met"
+      #     "radio_browser"
+      #     "isal"
+      #     "zha"
+      #     "jellyfin"
+      #     "webostv"
+      #     "tailscale"
+      #     "syncthing"
+      #     "sonos"
+      #     "analytics_insights"
+      #     "unifi"
+      #     "openweathermap"
+      #   ];
+      #   config = {
+      #     http = {
+      #       server_port = 8082;
+      #       use_x_forwarded_for = true;
+      #       trusted_proxies = ["127.0.0.1" "::1"];
+      #       ip_ban_enabled = true;
+      #       login_attempts_threshold = 10;
+      #     };
+      #     # recorder.db_url = "postgresql://@/${db_user}";
+      #     "automation manual" = [];
+      #     "automation ui" = "!include automations.yaml";
+      #   };
+      #   extraPackages = python3Packages:
+      #     with python3Packages; [
+      #       hassil
+      #       numpy
+      #       gtts
+      #     ];
+      # };
+      # host = {
+      #   reverse_proxy.subdomains.${config.host.home-assistant.subdomain} = {
+      #     target = "http://localhost:${toString config.services.home-assistant.config.http.server_port}";
+
+      #     websockets.enable = true;
+      #     forwardHeaders.enable = true;
+
+      #     extraConfig = ''
+      #       add_header Upgrade $http_upgrade;
+      #       add_header Connection \"upgrade\";
+
+      #       proxy_buffering off;
+
+      #       proxy_read_timeout 90;
+      #     '';
+      #   };
+      # };
     }
     (lib.mkIf config.host.impermanence.enable {
-      assertions = [
-        {
-          assertion = config.services.home-assistant.configDir == configDir;
-          message = "home assistant config directory does not match persistence";
-        }
-      ];
-      environment.persistence."/persist/system/root" = {
-        enable = true;
-        hideMounts = true;
-        directories = [
-          {
-            directory = configDir;
-            user = "hass";
-            group = "hass";
-          }
-        ];
-      };
+      # assertions = [
+      #   {
+      #     assertion = config.services.home-assistant.configDir == configDir;
+      #     message = "home assistant config directory does not match persistence";
+      #   }
+      # ];
+      # environment.persistence."/persist/system/root" = {
+      #   enable = true;
+      #   hideMounts = true;
+      #   directories = [
+      #     {
+      #       directory = configDir;
+      #       user = "hass";
+      #       group = "hass";
+      #     }
+      #   ];
+      # };
     })
   ]);
 }
diff --git a/modules/nixos-modules/server/virt-home-assistant.nix b/modules/nixos-modules/server/virt-home-assistant.nix
new file mode 100644
index 0000000..4212668
--- /dev/null
+++ b/modules/nixos-modules/server/virt-home-assistant.nix
@@ -0,0 +1,155 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}: {
+  options.services.virt-home-assistant = {
+    enable = lib.mkEnableOption "Wether to enable home assistant virtual machine";
+    networkBridge = lib.mkOption {
+      type = lib.types.str;
+      description = "what network bridge should we attach to the image";
+    };
+    hostDevice = lib.mkOption {
+      type = lib.types.str;
+      description = "what host devices should be attached to the image";
+    };
+    initialVersion = lib.mkOption {
+      type = lib.types.str;
+      description = "what home assistant image version should we pull for initial instal";
+      default = "15.0";
+    };
+    imageName = lib.mkOption {
+      type = lib.types.str;
+      description = "where should the image be installed to";
+      default = "home-assistant.qcow2";
+    };
+    installLocation = lib.mkOption {
+      type = lib.types.str;
+      description = "where should the image be installed to";
+      default = "/etc/hass";
+    };
+    virtualMachineName = lib.mkOption {
+      type = lib.types.str;
+      description = "what name should we give the virtual machine";
+      default = "home-assistant";
+    };
+    subdomain = lib.mkOption {
+      type = lib.types.str;
+      description = "subdomain of base domain that home-assistant will be hosted at";
+      default = "home-assistant";
+    };
+  };
+  config = lib.mkIf config.services.virt-home-assistant.enable (lib.mkMerge [
+    {
+      # environment.systemPackages = with pkgs; [
+      #   virt-manager
+      # ];
+
+      # TODO: move this to external module and just have an assertion here that its enabled
+      # enable virtualization on the system
+      virtualisation = {
+        libvirtd = {
+          enable = true;
+          qemu.ovmf.enable = true;
+        };
+      };
+
+      # TODO: deactivation script?
+      # create service to install and start the container
+      systemd.services.virt-install-home-assistant = let
+        # TODO: all of these need to be escaped to be used in commands reliably
+        bridgedNetwork = config.services.virt-home-assistant.networkBridge;
+        hostDevice = config.services.virt-home-assistant.hostDevice;
+        virtualMachineName = config.services.virt-home-assistant.virtualMachineName;
+        imageName = config.services.virt-home-assistant.imageName;
+        installLocation = config.services.virt-home-assistant.installLocation;
+        installImage = "${installLocation}/${imageName}";
+        initialVersion = config.services.virt-home-assistant.initialVersion;
+
+        home-assistant-qcow2 = pkgs.fetchurl {
+          name = "home-assistant.qcow2";
+          url = "https://github.com/home-assistant/operating-system/releases/download/${initialVersion}/haos_ova-${initialVersion}.qcow2.xz";
+          hash = "sha256-V1BEjvvLNbMMKJVyMCmipjQ/3owoJteeVxoF9LDHo1U=";
+          postFetch = ''
+            cp $out src.xz
+            rm -r $out
+            ${pkgs.xz}/bin/unxz src.xz --stdout > $out/${imageName}
+          '';
+        };
+
+        # Write a script to install the Home Assistant OS qcow2 image
+        virtInstallScript = pkgs.writeShellScriptBin "virt-install-hass" ''
+          # Copy the initial image out of the package store to the install location if we don't have one yet
+          if [ ! -f ${installImage} ]; then
+            cp ${home-assistant-qcow2} ${installLocation}
+          fi
+
+          # Check if VM already exists, and other pre-conditions
+          if ! ${pkgs.libvirt}/bin/virsh list --all | grep -q ${virtualMachineName}; then
+            ${pkgs.virt-manager}/bin/virt-install --name ${virtualMachineName} \
+              --description "Home Assistant OS" \
+              --os-variant=generic \
+              --boot uefi \
+              --ram=2048 \
+              --vcpus=2 \
+              --import \
+              --disk ${installImage},bus=sata \
+              --network bridge=${bridgedNetwork} \
+              --host-device ${hostDevice} \
+              --graphics none
+            ${pkgs.libvirt}/bin/virsh autostart ${virtualMachineName}
+          fi
+        '';
+      in {
+        description = "Install and start Home Assistant";
+        wantedBy = ["multi-user.target"];
+        after = ["local-fs.target"];
+        requires = ["libvirtd.service"];
+        serviceConfig.Type = "oneshot";
+        serviceConfig = {
+          ExecStart = "${virtInstallScript}/bin/virt-install-hass";
+        };
+      };
+
+      # TODO: figure out what we need to proxy to the virtual image
+      # host = {
+      #   reverse_proxy.subdomains.${config.services.virt-home-assistant.subdomain} = {
+      #     target = "http://localhost:${toString config.services.home-assistant.config.http.server_port}";
+
+      #     websockets.enable = true;
+      #     forwardHeaders.enable = true;
+
+      #     extraConfig = ''
+      #       add_header Upgrade $http_upgrade;
+      #       add_header Connection \"upgrade\";
+
+      #       proxy_buffering off;
+
+      #       proxy_read_timeout 90;
+      #     '';
+      #   };
+      # };
+    }
+    (lib.mkIf config.services.fail2ban.enable {
+      # TODO: figure out how to write a config for this, prob based on nginx proxy logs?
+    })
+    (lib.mkIf config.host.impermanence.enable {
+      # assertions = [
+      #   {
+      #     assertion = config.services.virt-home-assistant.installLocation == configDir;
+      #     message = "home assistant install location does not match persistence";
+      #   }
+      # ];
+      environment.persistence."/persist/system/root" = {
+        enable = true;
+        hideMounts = true;
+        directories = [
+          {
+            directory = config.services.virt-home-assistant.installLocation;
+          }
+        ];
+      };
+    })
+  ]);
+}