Home Assistant OS VM Deployment on Proxmox with Ceph Storage¶
Summary¶
A Home Assistant OS virtual machine was deployed on a Proxmox cluster and its disk was placed on shared Ceph RBD storage to support cluster portability and future Proxmox HA use. The work session focused on choosing the correct storage location for the Home Assistant image, staging the QCOW2 image on file-based storage, importing it into Ceph RBD, configuring the VM, troubleshooting a boot failure, and clarifying Proxmox console behavior.
Environment¶
- Platform: Proxmox VE cluster
- Hypervisor host used during this session:
pve1 - VM created:
150(homeassistant) - Guest OS image:
haos_ova-16.3.qcow2 - Shared VM storage:
cephpool(Ceph RBD) - Shared file storage:
snips(CephFS) - Staging file locations used:
/var/lib/vz/template/qemu//mnt/pve/snips/iso/- VM network bridge:
vmbr0 - VM CPU model:
x86-64-v3 - VM memory:
4096 MB - VM vCPUs:
2 - Proxmox console methods discussed:
- VGA console via GUI
Console/noVNC - Serial console via
qm terminal - Router/firewall context: OPNsense
- User workstation used for image transfer: Windows PowerShell with
scp
Problem¶
A Home Assistant OS VM needed to be created in a way that supports shared storage and future HA behavior. There was confusion around where the image file should live, whether cloud-init was required, how to upload or move the image, and why the VM would not boot after initial creation.
Symptoms¶
- Uncertainty about whether the Home Assistant image itself should be stored on Ceph RBD or CephFS.
- GUI upload/import flow was not working as expected.
scpupload failed because the destination directory did not exist.- The VM appeared to be running but
qm terminal 150only showed:text starting serial terminal on interface serial0 (press Ctrl+O to exit) - The VGA console showed the VM stuck at:
text Booting from hard disk... - Uncertainty about whether Home Assistant required a cloud-init drive.
- Uncertainty about how to identify the VM IP address after boot.
Actions Taken¶
- Determined that the Home Assistant VM disk should live on shared Ceph RBD storage (
cephpool) for HA compatibility, while image files should remain on file-based storage. - Clarified that Ceph RBD is block storage and CephFS is file-based storage.
- Evaluated whether image files should be kept on CephFS and concluded that CephFS is a good shared library location for QCOW2 and ISO files.
- Decided to keep the existing CephFS storage ID
snipsrather than renaming it, to avoid breaking existing cloud-init snippet references. - Created or used a shared image library path under CephFS:
bash mkdir -p /mnt/pve/snips/isoPurpose: create a shared location for ISO and QCOW2 files. - Moved the Home Assistant QCOW2 file into the CephFS ISO folder:
bash mv /var/lib/vz/template/qemu/haos_ova-16.3.qcow2 /mnt/pve/snips/iso/Purpose: place the image in shared file storage. - Discussed downloading Debian cloud images into the same shared CephFS library for future VM creation.
- Confirmed that Home Assistant OS does not use cloud-init and does not need a cloud-init drive.
- Created a Proxmox VM shell for Home Assistant:
bash qm create 150 \ --name homeassistant \ --memory 4096 \ --cores 2 \ --net0 virtio,bridge=vmbr0 \ --ostype l26Purpose: create the base VM definition before importing the disk. - Imported the Home Assistant image into Ceph RBD:
bash qm importdisk 150 /mnt/pve/snips/iso/haos_ova-16.3.qcow2 cephpool --format rawPurpose: create a real Ceph-backed VM disk from the QCOW2 source file. - Attached the imported Ceph disk to the VM and set boot order:
bash qm set 150 --scsihw virtio-scsi-single --scsi0 cephpool:vm-150-disk-0 qm set 150 --boot order=scsi0Purpose: attach the Ceph-backed disk as the VM boot disk. - Changed the CPU model to a cluster-compatible modern baseline instead of host passthrough:
bash qm set 150 --cpu x86-64-v3Purpose: standardize CPU features for migration/HA compatibility across nodes. - Added serial console support and standard VGA output:
bash qm set 150 --serial0 socket --vga stdPurpose: keep both serial and VGA console options available. - Verified the VM status:
bash qm status 150Purpose: confirm that the VM process was actually running. - Checked the VM configuration:
bash qm config 150Purpose: confirm the attached boot disk, CPU model, console devices, and boot order. - Diagnosed the boot problem after the console showed
Booting from hard disk.... - Determined that the Home Assistant image expected UEFI boot, not legacy BIOS.
- Stopped the VM and converted it to UEFI boot:
bash qm stop 150 qm set 150 --bios ovmf --machine q35 qm set 150 --efidisk0 cephpool:1,pre-enrolled-keys=1 qm set 150 --boot order=scsi0Purpose: switch firmware to OVMF/UEFI and add the required EFI vars disk. - Restarted the VM:
bash qm start 150Purpose: boot the VM using UEFI firmware. - Used the Proxmox GUI VGA console rather than relying only on
qm terminalto watch the actual boot process and confirm the guest came up. - Clarified the difference between VGA console, serial console,
qm terminal, and the Proxmox GUI Console tab.
Key Findings¶
cephpoolis appropriate for the VM disk because it is shared block storage used for running VMs.snipsis CephFS and is suitable for storing QCOW2, ISO, and snippet files because it is file-based shared storage.qm importdiskdoes not move the QCOW2 file onto Ceph as a file; it reads the source file and creates a new VM disk volume in Ceph RBD.- Home Assistant OS does not require cloud-init.
- The VM was running even when
qm terminaldid not show a useful prompt. qm terminalconnects only toserial0; it does not show VGA output.- The initial boot failure was caused by firmware mismatch:
- VM firmware was legacy BIOS / SeaBIOS
- Home Assistant OS image required UEFI / OVMF
- After switching to
bios: ovmfand adding an EFI disk, the imported Home Assistant disk booted successfully. x86-64-v3is a better fit thanhostwhen consistency across cluster nodes matters.
Resolution¶
The Home Assistant VM was successfully deployed by:
- storing the image file on CephFS (/mnt/pve/snips/iso/haos_ova-16.3.qcow2)
- importing it into Ceph RBD (cephpool) as the actual VM disk
- configuring the VM to use x86-64-v3
- switching the VM from legacy BIOS boot to UEFI boot with OVMF and an EFI disk
The VM then booted successfully.
Validation¶
Success was confirmed by:
- qm status 150 returning status: running
- qm config 150 showing:
- scsi0: cephpool:vm-150-disk-0
- cpu: x86-64-v3
- serial0: socket
- vga: std
- the Proxmox VGA console showing successful boot after the OVMF change
- Home Assistant becoming accessible through its web interface after boot
Follow-Up Tasks¶
- Add VM
150to a Proxmox HA group only if Ceph cluster health is stable enough for critical services. - Confirm Home Assistant receives a consistent IP address, preferably through DHCP reservation in OPNsense.
- Consider removing unused or unnecessary devices if the VM configuration should be minimized.
- Decide whether to keep
serial0enabled long-term or rely only on VGA console access. - Keep
snipsas the shared image/snippet library and expand its use for ISO/QCOW2 storage. - Back up the VM through Proxmox and also configure Home Assistant internal backups.
- If USB Zigbee/Z-Wave devices will be used, add USB passthrough to the VM and test device persistence after reboot or failover.
Lessons Learned¶
- Shared VM disks belong on Ceph RBD; source images belong on file-based storage such as CephFS.
qm importdiskcreates a VM disk from an image file; it does not store the image file itself on RBD.- Many appliance-style QCOW2 images, including Home Assistant OS, may require UEFI boot.
- A VM can be healthy even if
qm terminallooks empty; console type matters. - Keep storage naming stable when it is already referenced in cloud-init or automation.
- For shared homelab image libraries, CephFS is a practical place to keep QCOW2 and ISO files.
- Use VGA console for BIOS/UEFI and early boot troubleshooting; use
qm terminalonly when the guest is known to expose a serial console.
Command Reference¶
Command¶
mkdir -p /var/lib/vz/template/qemu
What it does¶
Creates the directory used as a local staging path for QEMU image files.
Important arguments¶
-p: creates parent directories as needed and does not fail if the directory already exists.
Why it was used¶
The scp upload initially failed because the destination path did not exist.
Expected result¶
The directory becomes available for file upload.
Success vs. failure¶
- Success: the path exists and
scpcan write into it. - Failure: upload continues to fail because the path is missing or permissions are wrong.
Risk¶
Low.
Safer alternative¶
None needed.
Command¶
scp "$env:USERPROFILE\Downloads\haos_ova-16.3.qcow2" root@192.168.16.12:/var/lib/vz/template/qemu/
What it does¶
Copies the Home Assistant QCOW2 image from the Windows workstation to the Proxmox node over SSH.
Important arguments¶
"$env:USERPROFILE\Downloads\haos_ova-16.3.qcow2": source file on Windows.root@192.168.16.12: destination SSH user and Proxmox node.:/var/lib/vz/template/qemu/: destination directory on the node.
Why it was used¶
The Home Assistant image had to be staged on the Proxmox side before being moved or imported.
Expected result¶
The file appears in the target directory on the Proxmox host.
Success vs. failure¶
- Success: file is present on the node.
- Failure: authentication, path, or permissions problem.
Risk¶
Moderate because it uses the root account.
Safer alternative¶
Use a non-root SSH account with delegated permissions where possible.
Command¶
mkdir -p /mnt/pve/snips/iso
What it does¶
Creates a shared CephFS directory for ISO and QCOW2 image storage.
Important arguments¶
-p: create parents if necessary.
Why it was used¶
To establish a shared image library under the existing snips storage.
Expected result¶
The iso directory exists on CephFS.
Success vs. failure¶
- Success: shared path exists and is writable.
- Failure: the CephFS mount may be unavailable.
Risk¶
Low.
Safer alternative¶
None needed.
Command¶
mv /var/lib/vz/template/qemu/haos_ova-16.3.qcow2 /mnt/pve/snips/iso/
What it does¶
Moves the Home Assistant image from local staging into the shared CephFS image library.
Important arguments¶
- Source path: local staging copy.
- Destination path: shared CephFS library.
Why it was used¶
To centralize images on shared file-based storage rather than leaving them only on one host.
Expected result¶
The file disappears from the local staging path and appears on CephFS.
Success vs. failure¶
- Success: image is accessible from the CephFS path.
- Failure: source file missing, destination unavailable, or permissions issue.
Risk¶
Low to moderate. A move removes the original source from the local path.
Safer alternative¶
Use cp first, confirm the copy, then delete the original.
Command¶
wget https://cdimage.debian.org/cdimage/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2
What it does¶
Downloads the Debian 12 generic cloud QCOW2 image.
Important arguments¶
- URL: direct link to the Debian cloud image.
Why it was used¶
To populate the shared image library with additional reusable VM source images.
Expected result¶
A Debian QCOW2 file is written into the current working directory.
Success vs. failure¶
- Success: download completes and the file exists.
- Failure: network, DNS, TLS, or remote file availability issue.
Risk¶
Low.
Safer alternative¶
Verify checksums after download.
Command¶
qm create 150 \
--name homeassistant \
--memory 4096 \
--cores 2 \
--net0 virtio,bridge=vmbr0 \
--ostype l26
What it does¶
Creates the initial Proxmox VM definition.
Important arguments¶
150: VMID.--name homeassistant: VM name.--memory 4096: RAM in MB.--cores 2: CPU core count.--net0 virtio,bridge=vmbr0: attach one virtio NIC tovmbr0.--ostype l26: modern Linux guest type.
Why it was used¶
A VM shell must exist before importing and attaching disks.
Expected result¶
A new VM config is created in Proxmox.
Success vs. failure¶
- Success:
qm config 150returns a valid VM config. - Failure: VMID conflict or invalid parameters.
Risk¶
Low.
Safer alternative¶
Create the VM in the GUI if preferred, then inspect with qm config.
Command¶
qm importdisk 150 /mnt/pve/snips/iso/haos_ova-16.3.qcow2 cephpool --format raw
What it does¶
Reads the QCOW2 file and creates a new VM disk volume in Ceph RBD for VM 150.
Important arguments¶
150: target VMID./mnt/pve/snips/iso/haos_ova-16.3.qcow2: source image file.cephpool: target Ceph RBD storage.--format raw: preferred format for RBD-backed VM disks.
Why it was used¶
This is the actual step that turns a source appliance image into a real Proxmox VM disk on shared storage.
Expected result¶
A disk such as cephpool:vm-150-disk-0 is created and may appear as an unused disk until attached.
Success vs. failure¶
- Success: import completes and Proxmox reports a created RBD volume.
- Failure: source file path wrong, storage unavailable, or insufficient space.
Risk¶
Moderate because it allocates shared storage space.
Safer alternative¶
Verify source path and available storage before import.
Command¶
qm set 150 --scsihw virtio-scsi-single --scsi0 cephpool:vm-150-disk-0
What it does¶
Attaches the imported Ceph-backed disk to the VM as scsi0 and sets the SCSI controller type.
Important arguments¶
--scsihw virtio-scsi-single: efficient paravirtualized SCSI controller.--scsi0 cephpool:vm-150-disk-0: attach the imported Ceph disk as the primary disk.
Why it was used¶
The imported disk must be attached before the VM can boot from it.
Expected result¶
qm config 150 shows a scsi0 disk entry.
Success vs. failure¶
- Success: disk appears in VM config.
- Failure: disk identifier wrong or storage unavailable.
Risk¶
Low.
Safer alternative¶
Attach through the GUI if preferred.
Command¶
qm set 150 --boot order=scsi0
What it does¶
Sets the VM boot order so the primary SCSI disk is attempted first.
Important arguments¶
--boot order=scsi0: boot from the attached Home Assistant disk.
Why it was used¶
Without correct boot order, Proxmox may try to boot from the wrong device.
Expected result¶
The VM firmware attempts to boot from the imported OS disk.
Success vs. failure¶
- Success:
qm config 150showsboot: order=scsi0. - Failure: the VM may still boot from the wrong device.
Risk¶
Low.
Safer alternative¶
Change boot order in the GUI Options tab.
Command¶
qm set 150 --cpu x86-64-v3
What it does¶
Sets the VM CPU model to the x86-64-v3 baseline.
Important arguments¶
x86-64-v3: a modern CPU feature level intended to be portable across compatible nodes.
Why it was used¶
The goal was to avoid host passthrough and use a consistent cluster-friendly CPU model.
Expected result¶
The VM sees a modern but controlled CPU feature set.
Success vs. failure¶
- Success:
qm config 150showscpu: x86-64-v3. - Failure: invalid CPU model or unsupported host capabilities.
Risk¶
Low to moderate. Migration will fail if target hosts do not support the selected CPU level.
Safer alternative¶
Use host only when migration consistency is not required.
Command¶
qm set 150 --serial0 socket --vga std
What it does¶
Adds a serial console device and keeps a standard VGA display device.
Important arguments¶
--serial0 socket: creates a host-side serial socket for the VM.--vga std: creates a standard VGA device for graphical console output.
Why it was used¶
To make both console paths available:
- VGA for boot troubleshooting
- serial for optional CLI access through qm terminal
Expected result¶
The VM exposes both a VGA console and a serial port.
Success vs. failure¶
- Success: both entries appear in
qm config. - Failure: console access remains limited.
Risk¶
Low.
Safer alternative¶
None needed.
Command¶
qm status 150
What it does¶
Shows the runtime state of the VM.
Important arguments¶
150: VMID.
Why it was used¶
To confirm whether the VM process was actually running when console output was unclear.
Expected result¶
A status line such as status: running.
Success vs. failure¶
- Success: the VM is running or stopped as reported.
- Failure: invalid VMID or Proxmox issue.
Risk¶
Low.
Safer alternative¶
Check the VM state in the GUI.
Command¶
qm terminal 150
What it does¶
Connects to the VM’s serial0 console.
Important arguments¶
150: VMID.
Why it was used¶
To try to access the Home Assistant CLI from the Proxmox shell.
Expected result¶
A serial terminal attaches and may show a guest login prompt if the guest outputs to serial.
Success vs. failure¶
- Success: useful guest serial output appears.
- Failure: blank session or no prompt does not necessarily mean the VM is down.
Risk¶
Low.
Safer alternative¶
Use the GUI VGA console for early boot troubleshooting.
Command¶
qm config 150
What it does¶
Prints the VM configuration.
Important arguments¶
150: VMID.
Why it was used¶
To verify the boot disk, CPU model, console devices, and boot order.
Expected result¶
The current VM config is displayed.
Success vs. failure¶
- Success: config output reflects intended settings.
- Failure: wrong VMID or Proxmox issue.
Risk¶
Low.
Safer alternative¶
Inspect the VM Hardware and Options tabs in the GUI.
Command¶
qm stop 150
What it does¶
Stops the VM.
Important arguments¶
150: VMID.
Why it was used¶
The VM had to be powered off before changing firmware settings.
Expected result¶
The VM transitions to a stopped state.
Success vs. failure¶
- Success:
qm status 150shows stopped. - Failure: the guest may hang or require a forced stop.
Risk¶
Moderate because it interrupts the guest immediately if not shut down gracefully.
Safer alternative¶
Use a graceful guest shutdown first if the guest is responsive.
Command¶
qm set 150 --bios ovmf --machine q35
What it does¶
Changes the VM firmware to UEFI and uses the q35 machine type.
Important arguments¶
--bios ovmf: use UEFI firmware.--machine q35: modern PCIe-based machine type often paired with OVMF.
Why it was used¶
The Home Assistant image would not boot with legacy BIOS and required UEFI.
Expected result¶
The VM firmware can detect and boot the EFI bootloader inside the Home Assistant disk.
Success vs. failure¶
- Success: the guest proceeds past the firmware stage and boots.
- Failure: boot remains stuck or the EFI disk is still missing.
Risk¶
Moderate. Firmware changes can make an existing VM unbootable if the guest expects the old firmware mode.
Safer alternative¶
Verify appliance image firmware requirements before building the VM.
Command¶
qm set 150 --efidisk0 cephpool:1,pre-enrolled-keys=1
What it does¶
Creates and attaches an EFI variables disk on Ceph RBD.
Important arguments¶
--efidisk0: attach EFI variables storage.cephpool:1: allocate the EFI disk on shared Ceph storage.pre-enrolled-keys=1: create it with pre-enrolled keys.
Why it was used¶
OVMF requires an EFI vars disk for normal UEFI boot behavior in Proxmox.
Expected result¶
A small additional VM disk is created and attached for EFI data.
Success vs. failure¶
- Success: the VM can boot under OVMF.
- Failure: OVMF may not boot the guest properly without this disk.
Risk¶
Low.
Safer alternative¶
Add the EFI disk from the GUI Hardware tab if preferred.
Command¶
qm start 150
What it does¶
Starts the VM.
Important arguments¶
150: VMID.
Why it was used¶
To boot the VM after import and again after firmware correction.
Expected result¶
The VM enters the running state and begins guest boot.
Success vs. failure¶
- Success: VM boots and becomes reachable.
- Failure: boot loops, hangs, or remains inaccessible.
Risk¶
Low.
Safer alternative¶
Start from the GUI if preferred.
Likely command used¶
ls -lh /var/lib/vz/template/qemu/haos_ova-16.3.qcow2
What it does¶
Checks whether the source image file exists and shows its size.
Important arguments¶
-l: long format.-h: human-readable sizes.
Why it was used¶
To confirm the upload or file placement succeeded before import.
Expected result¶
The file path, ownership, and size are shown.
Success vs. failure¶
- Success: image file is visible and nonzero.
- Failure: file missing or unexpectedly small.
Risk¶
Low.
Safer alternative¶
None needed.
Likely command used¶
ls -lh /mnt/pve/snips/iso/haos_ova-16.3.qcow2
What it does¶
Confirms that the image file exists in shared CephFS storage.
Important arguments¶
-l: long format.-h: human-readable sizes.
Why it was used¶
To verify the image had been moved into the shared image library before import.
Expected result¶
The file is listed with its size.
Success vs. failure¶
- Success: shared source image is available for import.
- Failure: move failed or CephFS is unavailable.
Risk¶
Low.
Safer alternative¶
None needed.