forked from jan-leila/nix-config
		
	drafted out virt home assistant
This commit is contained in:
		
							parent
							
								
									ba5d5a1487
								
							
						
					
					
						commit
						77f1aa30b7
					
				
					 4 changed files with 270 additions and 75 deletions
				
			
		|  | @ -8,7 +8,7 @@ | |||
|     ./jellyfin.nix | ||||
|     ./forgejo.nix | ||||
|     ./searx.nix | ||||
|     ./home-assistant.nix | ||||
|     ./virt-home-assistant.nix | ||||
|     ./adguardhome.nix | ||||
|     ./immich.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"; | ||||
|       #     } | ||||
|       #   ]; | ||||
|       # }; | ||||
|     }) | ||||
|   ]); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										155
									
								
								modules/nixos-modules/server/virt-home-assistant.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								modules/nixos-modules/server/virt-home-assistant.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
|           } | ||||
|         ]; | ||||
|       }; | ||||
|     }) | ||||
|   ]); | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue