Direct VHDX access without Export-VM, change tracking via RCT (Resilient Change Tracking), near-CDP RCT-Push replication, cross-hypervisor conversion (vSphere/Proxmox → Hyper-V), and multi-adapter architecture.
Technical companion to the PodHeitor Hyper-V plugin page.
1. The problem: Hyper-V backup without a plugin is expensive or fragile
Production Hyper-V VMs present three fundamental problems to stock Bacula:
- VHDX is locked while the VM is running — direct file reading is impossible without a production checkpoint. Stock Bacula doesn’t know about this.
- Export-VM doubles storage — requiring an
Export-VMbefore backup doubles the fleet on disk and doesn’t scale. - No native change tracking in Bacula — every “incremental” degrades to re-reading the entire VHDX. 2 GB modified within 100 GB becomes 100 GB transferred.
The PodHeitor Hyper-V Plugin tackles all three with in-place VHDX reading (zero extra staging), block-level RCT via WMI, and near-CDP delta replication to secondary sites.
2. Architectural model
The plugin uses the PodHeitor pattern of cdylib + standalone backend, with PTCOMM on stdin/stdout. On Windows the cdylib is a DLL (podheitor-hyperv-fd.dll) loaded by bacula-fd, and the backend is podheitor-hyperv-backend.exe.
Bacula FD (Windows)
└─ podheitor-hyperv-fd.dll (metaplugin adapter)
│ PTCOMM (stdin/stdout)
▼
podheitor-hyperv-backend.exe (Rust)
├─ Get-VM / Checkpoint-VM (PowerShell + WMI)
├─ Msvm_VirtualSystemReferencePointService (RCT API)
├─ Direct VHDX reader (no Export-VM)
├─ CBT delta encoder (proprietary binary format)
├─ RCT-Push replication driver
└─ Cross-hypervisor convert (qemu-img.exe wrapper)
2.1 Multi-adapter design
A single backend engine serves multiple cdylib DLLs, each with a distinct Bacula namespace:
| cdylib DLL | Bacula namespace | Function |
|---|---|---|
podheitor-hyperv-fd.dll |
@hyperv/ |
Native Hyper-V backup/restore |
podheitor-vsphere-fd.dll |
@vsphere/ |
Restore VMware backups → Hyper-V |
podheitor-proxmox-fd.dll |
@proxmox_/ |
Restore Proxmox/KVM backups → Hyper-V |
Operationally: one Bacula FD host can be the destination for migration from any hypervisor — no re-provisioning, no installing three different products.
3. Direct VHDX + RCT — why it matters
| Problem | PodHeitor approach |
|---|---|
| VHDX locked at runtime | Production checkpoint freezes the parent VHDX — consistent reads |
| Inconsistent app state | VSS quiesce via Hyper-V Integration Services — application-consistent |
| Export-VM doubles disk | Plugin reads VHDX in-place, zero extra space |
| Whole VHDX re-sent | RCT (Resilient Change Tracking) flags dirty regions; only those go |
| Slow incremental on big disks | 100 GB with 2 GB modified → 2 GB transferred |
| Manual snapshot management | Plugin creates and removes checkpoint automatically, even on failure |
| No file catalog | Bacula catalog tracks every file — granular restore possible |
4. RCT — Resilient Change Tracking
RCT is the native Microsoft API (Windows Server 2016+) for virtual disk change tracking. The plugin consumes it via WMI:
- Reference points are persistent markers (survive Hyper-V host reboot) registered with
Msvm_VirtualSystemReferencePointService. - On every incremental/differential, the plugin asks Hyper-V for the diff between two reference points and gets a list of
{offset, length}extents that changed. - The plugin reads only those extents from the VHDX and wraps them in the proprietary CBT delta format (binary stream with offset header).
- On restore, the cdylib applies the deltas in chronological order over the full base.
When RCT isn’t available (legacy generation 1, old host), the plugin automatically falls back to full VHDX streaming rather than failing — documented behavior as Gen1 fallback.
5. RCT-Push replication (near-CDP)
With mode=rct-push, the plugin runs continuous replication cycles directly to a secondary Hyper-V host, bypassing the Bacula SD per cycle.
| Parameter | Default | Function |
|---|---|---|
push_interval |
300 | Cycle interval (seconds) |
push_cycles |
1 | Number of cycles (0 = infinite) |
rpo_seconds |
900 | Target Recovery Point Objective |
dr_host |
— | Destination Hyper-V host |
dr_port |
9847 | Receiver TCP port |
dr_psk |
— | Pre-shared key (HMAC) for the channel |
bandwidth |
0 | Throttle in bytes/s (0 = unlimited) |
max_restore_points |
5 | Restore points retained on DR |
push_apply_remote |
no | Apply deltas directly on DR (bypass Bacula SD) |
network_map |
— | Network mapping for failover (src=dst,...) |
reip_rules |
— | Re-IP at failover (vm:ip/mask/gw,...) |
With push_apply_remote=yes, the channel goes directly from source FD to DR, no trip through Bacula SD — useful when goal is purely DR and not centralized retention. With =no, deltas go through the SD (cataloged) and are reapplied on DR in the next cycle.
6. Cross-hypervisor conversion (vSphere / Proxmox → Hyper-V)
Restore VMs backed up by sister PodHeitor plugins directly into Hyper-V — no manual disk reconversion.
| Source | Adapter DLL | Conversion |
|---|---|---|
| VMware vSphere | podheitor-vsphere-fd.dll |
VMDK / raw → VHDX (via qemu-img.exe) |
| Proxmox / KVM | podheitor-proxmox-fd.dll |
raw / qcow2 → VHDX (via qemu-img.exe) |
VM configuration translation (network adapters, boot order, Gen1/Gen2 detection) is automatic. Prerequisite: qemu-img.exe in %BACULA_DIR%tools or in %PATH%; temporary disk space ~1.5× the compressed VM size.
7. Granular restore (file-level)
Compatible with PodHeitor Granular Restore:
- Browse the Bacula catalog (BVFS) to locate VM VHDX files.
- Restore only the base VHDX + relevant CBT deltas to the Storage Daemon.
- Reconstruct the full disk state by applying CBT deltas onto the base VHDX.
- Mount the guest filesystem (NTFS, ext4, XFS, etc.) via libguestfs or
qemu-nbd. - Browse and extract individual files.
8. Validated platforms
| OS | Plugin version | Tested scenarios |
|---|---|---|
| Windows Server 2016 Datacenter | 1.2.0 | Full, Incremental, Restore, RCT-Push, Cross-Hypervisor |
| Windows Server 2025 Standard | 1.2.0 | Full, Incremental, Restore, RCT-Push |
| Bacula FD 15.0.3 | — | All scenarios above |
9. Documented anti-patterns
- Do not disable
quiesceon stateful-app VMs. Without VSS quiesce the snapshot is crash-consistent — restore may boot, but DBs may need recovery. - Do not run two concurrent plugin jobs against the same VM. RCT reference points are per-VM globals; concurrency creates reference-point churn.
- Don’t trust RCT on Gen1 VMs or hosts < Windows Server 2016. The plugin transparently falls back to full VHDX streaming, but the operator must know to size bandwidth/storage.
10. License posture
Plugin under LicenseRef-PodHeitor-Proprietary. No Bacula AGPLv3 source is statically linked into the cdylib DLL. Binding is via the bacula-fd-abi crate (pure PodHeitor) with independent extern "C" declarations.
Ready to evaluate?
30-day free trial for production Hyper-V fleets. Guaranteed at minimum 50% discount vs Bacula Enterprise, Veeam or Commvault, with more capabilities included.
Heitor Faria — Founder, PodHeitor International
✉ [email protected]
☎ +1 (789) 726-1749 · +55 (61) 98268-4220 (WhatsApp)
🔗 PodHeitor Hyper-V plugin page
Disponível em:
Português (Portuguese (Brazil))
English
Español (Spanish)