Migrate from Virtualizor
The Virtualizor importer reads a Virtualizor KVM node’s own database and recreates its users, plans, storage pools, IP pools, virtual machines, disks and IPs in VirtConsole. Nothing is copied over the network: every disk stays on the node. File-based qcow2 disks are moved on the same filesystem, and LVM/ZFS volumes are renamed on the same volume group or pool - both by commands the importer prints for you.
The import runs in two halves. The agent on the Virtualizor node extracts everything to JSON files. The management server then reads those files and writes the records in one transaction, so a failed import leaves nothing behind.
Before you begin
Section titled “Before you begin”- A working VirtConsole management server with a license that covers the imported hosts. See Management server installation.
- The Virtualizor node runs KVM. OpenVZ, LXC and Xen nodes are not supported.
- Install the VirtConsole agent on the Virtualizor node itself, following Hypervisor installation. This is the one case where the agent is installed next to another control panel: the extractor needs Virtualizor’s configuration at
/usr/local/virtualizor/universal.phpand its MySQL socket. Keep Virtualizor running during the extraction. The two do not share ports. - Add the node under Infrastructure > Hypervisors so it shows Online. Do not add storage pools or subnets for it by hand; the importer creates them.
- Plan a maintenance window for the cutover. Virtual machines must be stopped in Virtualizor before their disks are moved and before they are started from VirtConsole.
- No Virtualizor customer email is already registered in VirtConsole. A user whose email already exists is skipped, but that user’s VMs are still imported and end up owned by an account that does not exist, invisible to every customer. Rename or delete the clashing VirtConsole account first, or change the email in Virtualizor.
- A fresh backup of the management server, taken with
vcli app:backup, so a bad import can be rolled back by restoring the database.
Step 1: Extract on the Virtualizor node
Section titled “Step 1: Extract on the Virtualizor node”SSH into the node and run:
vcli import:virtualizorThe command connects to the Virtualizor database, probes each storage pool (lvs for LVM thin and thick, zfs list for ZFS), and writes one JSON file per resource under the agent home directory in import/virtualizor/. It ends with a report:
=== Virtualizor Import Report ===Resource CountStorage 2Subnets 3Users 41Plans 6Instances 58Disks 61Ips 74Interfaces 58
Storage pool types (native, no conversion): LVM thin (native): 1 File qcow2 (native): 1Useful options:
vcli import:virtualizor --reportprints the report again from the existing files without touching Virtualizor.vcli import:virtualizor --cleandeletes the extracted files. Run it after a successful import, or before extracting again.
Watch for “Skipping” lines. A VPS whose owner or storage pool is missing in Virtualizor is left out, and so are its disks and IPs.
Step 2: Dry run on the management server
Section titled “Step 2: Dry run on the management server”On the management server, run the importer against the hypervisor by its panel name or ID with --dry-run:
vcli import:virtualizor node-01 --dry-runThe management server fetches the JSON over the agent’s API and prints a preview: a count per resource, the storage pool types found, and how many disks are native LVM or ZFS. No changes are made. Fix anything the preview flags (missing users, unexpected pool types) on the Virtualizor side and extract again.
Step 3: Import
Section titled “Step 3: Import”Run the same command without --dry-run and answer the confirmation prompt:
vcli import:virtualizor node-01The import writes, in order, users, plans, storage pools, subnets, instances, disks, IPs and network interfaces, all inside one database transaction. If any step fails the transaction rolls back and the panel is unchanged. When it succeeds it prints the counts and, for file-based disks, a rename list (see the next step).
What the import creates:
| Virtualizor | VirtConsole | Notes |
|---|---|---|
| User | User (customer) | Same email and name. A random password is set; the customer resets it with Forgot password. Active flag kept. |
| Plan | Instance plan | CPU, RAM, disk, bandwidth, CPU topology, NIC type, I/O mode and network speed limits carried over. Storage type set to SSD. |
| Storage | Storage pool, attached to the node, disabled | File pools keep their path. LVM pools keep the volume group and thin pool; ZFS pools keep the zpool and dataset prefix. |
| IP pool | Subnet, attached to the node | Public or private from the pool’s internal flag, routed or bridged from its routing flag, IPv4 or IPv6, bridge name kept. |
| VPS | Instance, stopped | Named h<vpsid> (the old Virtualizor domain used its own vps_name, for example v1127, not the VPS id). CPU, RAM, topology, VNC port kept (VNC password is re-encrypted; a Virtualizor VPS with no console password gets a fresh random one), suspended and network-suspended flags kept. Plan linked, OS matched to a catalog image when possible (see below). |
| Disk | Instance disk | LVM and ZFS volumes: path kept, format raw. File disks: new qcow2 path under the pool, see the rename list. |
| IP | IP on the subnet, assigned to the instance | Primary flag and MAC kept. Unassigned pool IPs are imported as free. |
| VPS network | One public interface, plus one private interface when the VPS had an internal IP | MAC kept on the public interface. |
The import also matches each VM’s reported OS against the VirtConsole image catalog: Virtualizor exports an OS name like debian-13.4-x86_64, and the importer looks for the closest catalog match (exact version first, then the same major version). On a match it finds or adds the corresponding catalog image, the same way the admin image browser’s Add button would, enables it if it was disabled, and links it to the instance. This is what lets a matched instance show its real OS instead of “unknown”, and it also supplies a cloud-init default for Step 7 below. When nothing matches, the import prints “instance <name>: OS <os_name> has no catalog match; set the image by hand” and leaves the image unset - set it yourself under the instance’s Settings.
Not migrated: OS templates and ISOs, backups, Virtualizor firewall rules, bandwidth history, and billing links (WHMCS and similar). Re-point your billing module at VirtConsole after the cutover.
Step 4: Move or rename disks
Section titled “Step 4: Move or rename disks”Virtualizor stores qcow2 files under its own naming; VirtConsole expects <pool path>/<instance id>/<disk id>.qcow2. For every such disk the import prints the commands to run on the node:
=== File-Based Disk Renames === mkdir -p /vz/kvm/6e1c…/ mv /vz/kvm/v1001-abc.img /vz/kvm/6e1c…/9f42….qcow2LVM and ZFS disks are not adopted at Virtualizor’s own volume or dataset name. VirtConsole always derives its own block-device path - /dev/<volume group>/<prefix><disk id> for LVM, /dev/zvol/<pool>/<dataset prefix>/<disk id> for ZFS - every time it reads the disk, including the first boot, so the volume or dataset has to be renamed to match. The import prints one line per disk:
=== Block Device Renames ===
Stop the VM in Virtualizor first. The rename is metadata-only and instant; Virtualizor cannot start the old domain afterwards, which is the cut-over.
lvrename vg_data v1001-abc 9f42… zfs rename tank/v1002-old tank/vsv/a83e…Stop the corresponding VM in Virtualizor before running any of these lines, then run the printed mkdir/mv commands for file-based disks and the printed lvrename/zfs rename commands for LVM/ZFS disks on the node. All of them operate on the same storage the disk already lives on, so each takes seconds regardless of disk size - but the LVM/ZFS rename is also the point of no return: once renamed, Virtualizor can no longer start the old domain for that disk.
Step 5: Cut over
Section titled “Step 5: Cut over”- Stop every imported VM in Virtualizor, then stop the Virtualizor services so they cannot start the old Virtualizor domains again (
virsh liston the node shows their names - Virtualizor names a domain after its ownvps_name, for examplev1127, not the VPS id). Leave the agent running. - In the admin panel go to Infrastructure > Storage and enable the imported pools.
- Open Instances, pick an imported instance and click Start. The agent defines a new libvirt domain from the imported disks and interfaces, with the same MAC and IPs, so the guest comes up with its old network identity.
- Check the console and network of the first few instances before starting the rest.
- Tell customers to use Forgot password on the VirtConsole login page.
Once every instance runs from VirtConsole, remove Virtualizor from the node and run vcli import:virtualizor --clean on it.
Step 6: Install the guest agent on every imported machine
Section titled “Step 6: Install the guest agent on every imported machine”One command on the node does Steps 6 and 7 together, offline, on the stopped disk: vcli import:prepare <instance> (for example vcli import:prepare h1001). For a Linux guest it needs no other arguments; for a Windows guest pass --windows-tools <path to virtio-win-guest-tools.exe> and --cloudbase-msi <path to CloudbaseInitSetup.msi>. Add --dry-run to see the commands it would run first. Skip ahead to Step 7’s panel side once it finishes, or do the same steps by hand instead:
Virtualizor VMs do not carry the QEMU guest agent by default. Install it inside each imported guest:
- Debian/Ubuntu:
apt-get install -y qemu-guest-agent && systemctl enable --now qemu-guest-agent - RHEL family (AlmaLinux, Rocky, CentOS Stream):
dnf install -y qemu-guest-agent && systemctl enable --now qemu-guest-agent - Windows: install
virtio-win-guest-tools.exefrom the virtio-win ISO (fedorapeople.org), which adds the VirtIO serial driver and the QEMU Guest Agent service; verify withGet-Service QEMU-GA.
The agent is what makes Reset Root/Administrator Password, Web SSH, network changes pushed from the panel, Docker one-click apps and Windows activation work on an imported instance. Imported machines keep whatever init system Virtualizor gave them and need no cloud-init for any of the above - see QEMU guest agent for the full reference and troubleshooting.
Step 7: Enable cloud-init (Linux) or cloudbase-init (Windows)
Section titled “Step 7: Enable cloud-init (Linux) or cloudbase-init (Windows)”If you already ran vcli import:prepare <instance> in Step 6, the guest side below is done - go straight to the panel side.
An instance whose OS was matched to a catalog image (see Step 3) inherits that image’s own cloud-init flag, so nothing here is needed for it. The panel toggles below are only for an instance the import could not match - it has no image to inherit from, so the configuration drive defaults to off. Enable it if you also want VirtConsole to push SSH keys, custom user-data, or network changes that survive without the guest agent’s live push.
Guest side
- Linux:
apt-get install -y cloud-init(Debian/Ubuntu) ordnf install -y cloud-init(RHEL family), and make sure the NoCloud datasource is allowed - check/etc/cloud/cloud.cfg.d/for adatasource_listoverride; the distro default list already includes it. Before the Stop/Start below, runcloud-init clean --logsso cloud-init treats the next boot as a first boot and re-reads the new configuration drive. - Windows: install cloudbase-init, and in
cloudbase-init.confsetmetadata_services=cloudbaseinit.metadata.services.configdrive.ConfigDriveServiceand keep the default plugin list (includingUserDataPlugin,SetHostNamePlugin,NetworkConfigPluginandSetUserPasswordPlugin) enabled - the service runs at every boot. VirtConsole builds aconfig-2labelled ISO for Windows guests, the same format the ConfigDrive service reads.
Panel side
In the admin panel, on the instance’s manage page, open Settings:
- For a Windows guest, turn on Enable Windows Settings under Windows / Hyper-V Enlightenments first - with no image row, this flag is how the platform tells a Windows guest apart on an imported machine, and it decides whether the configuration drive is built as a cloudbase-init config-2 ISO or a cloud-init NoCloud seed.
- Under Cloud-init Support, set the configuration drive to Enabled. An imported instance has no image to inherit from, so Inherit from image resolves to off and no drive is ever attached.
Apply it
Stop the instance and start it again (not Restart) so the configuration drive is built and attached. From then on, hostname, root/administrator password, SSH keys, network configuration and user scripts set from the panel apply on every boot.
What needs which
| Feature | Guest agent | Cloud-init / cloudbase-init |
|---|---|---|
| Password reset, Web SSH, Docker apps, Windows activation | Required | Not used |
| Static IP / network change pushed live, Windows | Required | Not used |
| Static IP / network change pushed live, Linux | Required | Required (reruns cloud-init init --local through the agent) |
| SSH keys and custom user-data applied on first boot | Not used | Required |
What happens next
Section titled “What happens next”Imported instances behave like any other: power actions, console, reinstall, backups, firewall and migrations all work. Plans imported from Virtualizor are ordinary instance plans; edit or retire them under Compute > Plans. See QEMU guest agent for what else the agent unlocks day to day.
Common problems
Section titled “Common problems”- “Failed to find Virtualizor config at /usr/local/virtualizor/universal.php”. The agent is not on the Virtualizor node, or Virtualizor is not a KVM install at the default path.
- “Import folder does not exist. Run php artisan import:virtualizor first.” The management server asked the node before the extraction ran. Run step 1 on the node.
- “Hypervisor ‘name’ not found”. The name or ID does not match a host under Infrastructure > Hypervisors. Copy it from the hypervisor page.
- “Skipping user x@example.com: already exists” in the output. That email is already a VirtConsole account, so the user was not created and the VMs that belonged to it are now owned by an account that does not exist. Restore the backup you took before importing, rename or delete the existing VirtConsole account (or change the email in Virtualizor), and run the import again.
- “LVM probe failed for VG” or “ZFS probe found no volumes”. The extractor could not read the pool with
lvsorzfs listand fell back to the thick variant. Installlvm2andthin-provisioning-tools, orzfsutils-linux, on the node and extract again. - An instance starts but has no network. If the import printed a “bridge not set in Virtualizor” notice for the subnet, it already defaulted the bridge to Virtualizor’s own
viifbr0- check the node actually uses that bridge name, or set the correct one on the subnet under Networking > Subnets and start the instance again. - The import fails half way. Nothing was written; the transaction rolled back. Read the error, fix the source data or extract again, and re-run.
Related
Section titled “Related”- Hypervisor installation
- Orphan VM import for adopting VMs that were not created by a control panel
- Manage storage
- Subnets and IPs
- Manage instances

