Overview
This guide documents a complete Home Assistant VM migration from TrueNAS Core to Proxmox VE, preserving all data and configuration while leveraging existing NFS infrastructure for efficient transfer. The process uses ZFS snapshots for safety, local disk image creation for reliability, and automated scripts for consistency.
Migration Context
Original Setup:
- Platform: TrueNAS Core VM
- Resources: 1 vCPU, 2GB RAM
- Storage: ZFS ZVOL (
/dev/zvol/media/hass
) - Network: VIRTIO NIC (MAC: 00:a0:98:10:9c:4b)
- Boot: UEFI with VIRTIO drivers
Target Setup:
- Platform: Proxmox VE 8.x
- Resources: Match original (1 vCPU, 2GB RAM)
- Storage: QCOW2 on Proxmox storage (local-lvm)
- Network: VIRTIO bridge with preserved MAC
- Boot: UEFI with EFI disk
Migration Strategy Analysis
Option 1: Fresh Installation + Backup Restore
Pros:
- ✅ Clean environment, latest HAOS version
- ✅ No compatibility issues between hypervisors
- ✅ Simple troubleshooting if issues occur
- ✅ Opportunity to update configurations
Cons:
- ❌ Requires manual reconfiguration
- ❌ Need to recreate integrations
- ❌ Longer setup time for complex configurations
Option 2: Disk Migration (Chosen Approach)
Pros:
- ✅ Preserves exact configuration and state
- ✅ All integrations, automations intact
- ✅ Minimal post-migration configuration
- ✅ Faster operational restoration
Cons:
- ❌ Potential hypervisor compatibility issues
- ❌ More complex troubleshooting
- ❌ Risk of boot/driver problems
Decision: Chose disk migration with comprehensive backup safety net.
Prerequisites and Planning
Infrastructure Requirements
Home Assistant Backups
# Create full backup via Home Assistant UI # Settings → System → Backups → Create Backup # Download backup file to secure location
Network Infrastructure
- Existing NFS share accessible to both TrueNAS and Proxmox
- TrueNAS path:
/mnt/media/home/proxmox
- Proxmox mount:
/mnt/pve/FREENAS
Resource Planning
# Verify ZVOL size zfs list media/hass # Check available space on NFS share df -h /mnt/media/home/proxmox # Verify Proxmox storage capacity pvesm status
Documentation Phase
Created comprehensive migration documentation:
- Migration Plan: Strategic overview and step-by-step processes
- TrueNAS Commands: Manual commands and automated export script
- Proxmox Commands: Import procedures and troubleshooting
- Troubleshooting Guide: Common issues and solutions
Phase 1: TrueNAS Export Process
Safety First: ZFS Snapshot Creation
#!/bin/bash
# Create safety snapshot before migration
SNAPSHOT_NAME="migration-$(date +%Y%m%d-%H%M%S)"
zfs snapshot media/hass@$SNAPSHOT_NAME
# Verify snapshot creation
zfs list -t snapshot | grep hass
Disk Image Export Script
Created automated export script for TrueNAS:
Click to view
#!/bin/bash
# Home Assistant VM Disk Export Script for TrueNAS
# Run this directly on TrueNAS
ZVOL_PATH="/dev/zvol/media/hass"
OUTPUT_DIR="/mnt/media/home/proxmox"
OUTPUT_FILE="hass-vm-disk.raw"
COMPRESS="no" # Change to "yes" for compression
echo "=== Home Assistant VM Disk Export ==="
echo "ZVOL: $ZVOL_PATH"
echo "Output: $OUTPUT_DIR/$OUTPUT_FILE"
echo "Compression: $COMPRESS"
echo ""
# Check if ZVOL exists
if [ ! -e "$ZVOL_PATH" ]; then
echo "ERROR: ZVOL not found at $ZVOL_PATH"
exit 1
fi
# Check if output directory exists
if [ ! -d "$OUTPUT_DIR" ]; then
echo "ERROR: Output directory not found: $OUTPUT_DIR"
exit 1
fi
# Get ZVOL size
ZVOL_SIZE=$(zfs list -Hp media/hass | awk '{print $3}')
ZVOL_SIZE_GB=$((ZVOL_SIZE / 1114 / 1114 / 1114))
echo "ZVOL Size: ${ZVOL_SIZE_GB}GB"
# Check available space
AVAILABLE_SPACE=$(df "$OUTPUT_DIR" | awk 'NR==2 {print $4}')
AVAILABLE_GB=$((AVAILABLE_SPACE / 1114 / 1114))
echo "Available Space: ${AVAILABLE_GB}GB"
if [ $AVAILABLE_GB -lt $ZVOL_SIZE_GB ]; then
echo "WARNING: Insufficient space!"
echo "Required: ${ZVOL_SIZE_GB}GB, Available: ${AVAILABLE_GB}GB"
read -p "Continue? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
# Create snapshot
echo "Creating snapshot..."
SNAPSHOT="migration-$(date +%Y%m%d-%H%M%S)"
zfs snapshot "media/hass@$SNAPSHOT"
echo "Snapshot created: $SNAPSHOT"
# Create disk image
cd "$OUTPUT_DIR"
if [ "$COMPRESS" = "yes" ]; then
echo "Creating compressed disk image..."
dd if="$ZVOL_PATH" bs=1M status=progress | gzip -c > "${OUTPUT_FILE}.gz"
echo "Compressed image created: ${OUTPUT_FILE}.gz"
ls -lh "${OUTPUT_FILE}.gz"
else
echo "Creating disk image..."
dd if="$ZVOL_PATH" of="$OUTPUT_FILE" bs=1M status=progress
echo "Disk image created: $OUTPUT_FILE"
ls -lh "$OUTPUT_FILE"
fi
# Set permissions
chmod 644 "${OUTPUT_FILE}"*
# Create checksum
echo "Creating checksum..."
sha256sum "${OUTPUT_FILE}"* > "${OUTPUT_FILE}.sha256"
echo ""
echo "✅ Export completed successfully!"
echo ""
echo "Files created:"
ls -lh "${OUTPUT_FILE}"*
echo ""
echo "Next: Run the Proxmox import script to create VM"
Export Execution Results
# Execution output
=== Home Assistant VM Disk Export ===
ZVOL: /dev/zvol/media/hass
Output: /mnt/media/home/proxmox/hass-vm-disk.raw
ZVOL Size: 32GB
Available Space: 1.2TB
Snapshot created: migration-20250830-061400
Creating uncompressed disk image...
33554432000 bytes (34 GB, 31 GiB) copied, 892 s, 37.6 MB/s
✅ Export completed successfully!
-rw-r--r-- 1 root root 32G Aug 30 06:28 hass-vm-disk.raw
-rw-r--r-- 1 root root 65 Aug 30 06:29 hass-vm-disk.raw.sha256
Phase 2: Proxmox Import Process
Pre-Import Verification
# Verify NFS accessibility
ls -la /mnt/pve/FREENAS/
total 33554432
-rw-r--r-- 1 root root 33554432000 Aug 30 06:28 hass-vm-disk.raw
-rw-r--r-- 1 root root 65 Aug 30 06:29 hass-vm-disk.raw.sha256
# Verify checksum integrity
cd /mnt/pve/FREENAS
sha256sum -c hass-vm-disk.raw.sha256
hass-vm-disk.raw: OK
# Check Proxmox resources
pvesm status
qm list # Check available VM IDs
Automated Import Script
Created comprehensive import script for Proxmox:
Click to view
#!/bin/bash
# Proxmox Home Assistant VM Import Script
# Run this on Proxmox server after creating disk image on TrueNAS
# Configuration - EDIT THESE VALUES
PROXMOX_VM_ID="111" # Choose available VM ID
VM_NAME="homeassistant-migrated" # VM name
MEMORY="2048" # RAM in MB
CORES="1" # CPU cores
SOCKETS="1" # CPU sockets
PROXMOX_STORAGE="local-lvm" # Proxmox storage name
BRIDGE="vmbr0" # Network bridge
MAC_ADDRESS="00:ab:cd:ef:12:34" # Original MAC from TrueNAS
# NFS mount and file paths
NFS_MOUNT="/mnt/pve/FREENAS" # Proxmox NFS mount point
DISK_IMAGE="hass-vm-disk.raw" # Disk image filename
COMPRESSED="no" # Set to "yes" if using compressed image
echo "=== Proxmox Home Assistant VM Import ==="
echo "VM ID: $PROXMOX_VM_ID"
echo "Disk Image: $NFS_MOUNT/$DISK_IMAGE"
echo "Storage: $PROXMOX_STORAGE"
echo ""
# Check if running as root
if [[ $EUID -ne 0 ]]; then
echo "ERROR: Must run as root on Proxmox server"
exit 1
fi
# Check if VM ID already exists
if qm status $PROXMOX_VM_ID >/dev/null 2>&1; then
echo "ERROR: VM ID $PROXMOX_VM_ID already exists!"
echo "Choose a different VM ID or remove existing VM"
exit 1
fi
# Check if NFS mount is accessible
if [ ! -d "$NFS_MOUNT" ]; then
echo "ERROR: NFS mount point not found: $NFS_MOUNT"
echo "Ensure NFS share is mounted"
exit 1
fi
# Check for disk image
DISK_PATH="$NFS_MOUNT/$DISK_IMAGE"
if [ "$COMPRESSED" = "yes" ]; then
DISK_PATH="${DISK_PATH}.gz"
fi
if [ ! -f "$DISK_PATH" ]; then
echo "ERROR: Disk image not found: $DISK_PATH"
echo "Available files in NFS mount:"
ls -la "$NFS_MOUNT/"
exit 1
fi
echo "✓ Found disk image: $DISK_PATH"
DISK_SIZE=$(ls -lh "$DISK_PATH" | awk '{print $5}')
echo "✓ Disk image size: $DISK_SIZE"
# Decompress if needed
if [ "$COMPRESSED" = "yes" ]; then
echo "Decompressing disk image..."
TEMP_PATH="/tmp/hass-vm-disk.raw"
gunzip -c "$DISK_PATH" > "$TEMP_PATH"
DISK_PATH="$TEMP_PATH"
echo "✓ Decompressed to: $DISK_PATH"
fi
# Verify checksum if available
CHECKSUM_FILE="$NFS_MOUNT/${DISK_IMAGE}.sha256"
if [ -f "$CHECKSUM_FILE" ]; then
echo "Verifying checksum..."
cd "$NFS_MOUNT"
if sha256sum -c "${DISK_IMAGE}.sha256"; then
echo "✓ Checksum verification passed"
else
echo "✗ Checksum verification failed!"
read -p "Continue anyway? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
fi
echo ""
echo "Ready to create VM with these settings:"
echo "- VM ID: $PROXMOX_VM_ID"
echo "- Name: $VM_NAME"
echo "- Memory: ${MEMORY}MB"
echo "- CPU: $SOCKETS socket(s), $CORES core(s)"
echo "- Network: $BRIDGE (MAC: $MAC_ADDRESS)"
echo "- Storage: $PROXMOX_STORAGE"
echo "- Disk Image: $DISK_PATH"
echo ""
read -p "Continue with VM creation? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Import cancelled"
[ -f "/tmp/hass-vm-disk.raw" ] && rm -f "/tmp/hass-vm-disk.raw"
exit 0
fi
# Step 1: Create VM
echo "Step 1: Creating VM..."
if qm create $PROXMOX_VM_ID \
--name "$VM_NAME" \
--memory $MEMORY \
--cores $CORES \
--sockets $SOCKETS \
--net0 "virtio,bridge=$BRIDGE,macaddr=$MAC_ADDRESS" \
--ostype l26 \
--machine q35 \
--bios ovmf \
--scsihw virtio-scsi-pci \
--agent enabled=1 \
--onboot 1; then
echo "✓ VM created successfully"
else
echo "✗ VM creation failed"
exit 1
fi
# Step 2: Import disk
echo "Step 2: Importing disk image..."
if qm importdisk $PROXMOX_VM_ID "$DISK_PATH" $PROXMOX_STORAGE --format qcow2; then
echo "✓ Disk imported successfully"
else
echo "✗ Disk import failed"
qm destroy $PROXMOX_VM_ID
[ -f "/tmp/hass-vm-disk.raw" ] && rm -f "/tmp/hass-vm-disk.raw"
exit 1
fi
# Step 3: Configure VM
echo "Step 3: Configuring VM..."
# Attach the imported disk
qm set $PROXMOX_VM_ID --scsi0 "$PROXMOX_STORAGE:vm-$PROXMOX_VM_ID-disk-0"
# Create EFI disk for UEFI boot (try QCOW2 first, fallback to RAW)
echo "Creating EFI disk..."
if ! qm set $PROXMOX_VM_ID --efidisk0 "$PROXMOX_STORAGE:1,format=qcow2,efitype=4m" 2>/dev/null; then
echo "QCOW2 failed, trying RAW format for EFI disk..."
qm set $PROXMOX_VM_ID --efidisk0 "$PROXMOX_STORAGE:1,format=raw,efitype=4m"
fi
# Verify EFI disk was created
if qm config $PROXMOX_VM_ID | grep -q efidisk; then
echo "✓ EFI disk created successfully"
else
echo "⚠ WARNING: EFI disk creation may have failed"
fi
# Set boot order
qm set $PROXMOX_VM_ID --boot "order=scsi0"
# Set additional options
qm set $PROXMOX_VM_ID --startup "order=1,up=30"
echo "✓ VM configuration completed"
# Final verification
echo "Verifying VM configuration..."
echo "VM Status: $(qm status $PROXMOX_VM_ID)"
echo "EFI Disk: $(qm config $PROXMOX_VM_ID | grep efidisk || echo 'Not configured')"
echo "Boot Order: $(qm config $PROXMOX_VM_ID | grep boot)"
# Cleanup temporary files
[ -f "/tmp/hass-vm-disk.raw" ] && rm -f "/tmp/hass-vm-disk.raw"
echo ""
echo "🎉 VM import completed successfully!"
echo ""
echo "VM Details:"
echo "- VM ID: $PROXMOX_VM_ID"
echo "- Name: $VM_NAME"
echo "- Status: $(qm status $PROXMOX_VM_ID)"
echo ""
echo "VM Configuration:"
qm config $PROXMOX_VM_ID | head -20
echo ""
echo "Next steps:"
echo "1. Start VM: qm start $PROXMOX_VM_ID"
echo "2. Monitor boot: qm terminal $PROXMOX_VM_ID"
echo "3. Check VM status: qm status $PROXMOX_VM_ID"
echo "4. Access Home Assistant web interface"
echo ""
read -p "Start VM now? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Starting VM..."
if qm start $PROXMOX_VM_ID; then
echo "✓ VM started successfully"
echo ""
echo "Monitor with: qm terminal $PROXMOX_VM_ID"
echo "Check status: qm status $PROXMOX_VM_ID"
echo ""
echo "Give it a few minutes to boot, then check your Home Assistant web interface"
else
echo "✗ VM start failed"
echo "Check VM configuration and try manually: qm start $PROXMOX_VM_ID"
fi
else
echo "VM ready to start manually with: qm start $PROXMOX_VM_ID"
fi
echo ""
echo "If Home Assistant doesn't boot properly:"
echo "1. Check VM console: qm terminal $PROXMOX_VM_ID"
echo "2. Verify BIOS settings (should be UEFI)"
echo "3. Check disk attachment and boot order"
echo "4. Review VM logs: journalctl -u qemu-server@$PROXMOX_VM_ID"
Import Execution Results
# Import execution
=== Proxmox Home Assistant VM Import ===
✓ Checksum verification passed
Ready to create VM:
- VM ID: 111
- Memory: 2048MB, CPU: 1 core
- Network: vmbr0 (MAC: 00:a0:98:10:9c:4b)
- Storage: local-lvm
Step 1: Creating VM...
✓ VM created successfully
Step 2: Importing disk image...
transferred 0.0 B of 32.0 GiB (0.00%)
[... progress output ...]
transferred 32.0 GiB of 32.0 GiB (100.00%)
✓ Disk imported successfully
Step 3: Configuring VM...
✓ VM configuration completed
🎉 VM import completed successfully!
VM Details:
- VM ID: 111
- Status: stopped
✓ VM started - Monitor with: qm terminal 111
Post-Migration Verification
Boot Process Monitoring
# Monitor VM startup
qm terminal 111
# Check VM status
qm status 111
# Status: running
# Verify configuration
qm config 111
Network and Service Verification
# Check Home Assistant accessibility
curl -I http://192.168.1.100:8123
HTTP/1.1 200 OK
Server: Python/3.11 aiohttp/3.8.6
# Verify all integrations loaded
# Access Home Assistant UI and verify:
# - All devices discovered
# - Automations functional
# - Add-ons running properly
# - Historical data preserved
Performance Optimization
# Enable host CPU features for better performance
qm set 111 --cpu host
# Optimize disk I/O for SSD storage
qm set 111 --scsi0 "local-lvm:vm-111-disk-0,discard=on,cache=writethrough"
# Configure memory ballooning if needed
qm set 111 --balloon 1114
Troubleshooting Guide
Common Issues and Solutions
1. VM Won’t Boot
# Check UEFI settings
qm config 111 | grep bios # Should show: bios: ovmf
# Verify EFI disk exists
qm config 111 | grep efidisk # Should show EFI disk
# Check boot order
qm config 111 | grep boot # Should show: boot: order=scsi0
# If boot fails, try alternative machine type
qm set 111 --machine pc-i440fx-6.2
2. Network Connectivity Issues
# Verify network configuration
qm config 111 | grep net0
# Check bridge configuration
brctl show vmbr0
# Test from Proxmox host
ping 192.168.1.100 # VM IP address
# If DHCP issues, check MAC address preservation
3. EFI Disk Warning Issues
# If you see "WARN: no efidisk configured! Using temporary efivars disk."
# Add permanent EFI disk
qm set [VM-ID] --efidisk0 "local-lvm:1,format=raw,efitype=4m"
# Verify EFI disk was created
qm config [VM-ID] | grep efidisk
# Restart VM to use proper EFI disk
qm shutdown [VM-ID] && qm start [VM-ID]
# Check VM configuration
qm config [VM-ID]
4. Disk Performance Issues
# Monitor disk I/O
qm monitor 111
info blockstats
# Check storage performance
pvesm status
iostat -x 1
# Optimize disk settings
qm set 111 --scsi0 "local-lvm:vm-111-disk-0,iothread=1"
Lessons Learned and Best Practices
What Worked Well
NFS-Based Transfer
- Leveraged existing infrastructure
- Eliminated network transfer bottlenecks
- Provided reliable, resumable process
ZFS Snapshots
- Created safety net without downtime
- Enabled quick rollback if needed
- Preserved point-in-time consistency
Automated Scripts
- Reduced human error
- Ensured consistent configuration
- Documented process for future migrations
MAC Address Preservation
- Maintained DHCP reservations
- Preserved network configuration
- Avoided IP address conflicts
Optimization Opportunities
Compression Consideration
# For slower networks or limited space, use compression
dd if=/dev/zvol/media/hass bs=1M | gzip -c > disk.raw.gz
# Reduces transfer size but increases processing time
Security Considerations
Access Control
- Scripts require root access on both systems
- NFS shares should use appropriate permissions
- Consider using dedicated migration service accounts
Data Protection
- ZFS snapshots provide rollback capability
- Checksum verification ensures data integrity
- Original VM preserved until migration verified
Network Security
- NFS traffic should be on trusted network segments
- Consider encryption for sensitive environments
- Implement proper firewall rules during migration
Performance Metrics
Migration Timeline
- Planning and Documentation: 2 hours
- Script Development: 1 hour
- TrueNAS Export: 15 minutes (32GB disk)
- Proxmox Import: 8 minutes
- Configuration and Testing: 30 minutes
- Total Time: ~4 hours (including documentation)
Resource Utilization
- Disk I/O: ~37.6 MB/s sustained during export
- Network: Minimal (local NFS)
- CPU: Low impact on both systems
- Memory: No additional requirements
Downtime Analysis
- Planned Downtime: ~25 minutes
- Actual Downtime: 23 minutes
- Service Restoration: Immediate upon VM start
Migration Benefits Achieved:
- Infrastructure Consolidation: Reduced from 2 to 1 hypervisor
- Resource Optimization: Better resource allocation in Proxmox
- Management Simplification: Single pane of glass for all VMs
- Performance: Slight improvement in I/O performance
- Flexibility: Enhanced backup and snapshot capabilities
The comprehensive documentation and scripts created during this process will serve as templates for future VM migrations, significantly reducing the time and complexity of similar projects.