VorticPanel

Migrating

Migrating from VirtFusion or Virtualizor

Imports (/admin/imports) bring servers, packages, IP pools and customers over from VirtFusion or Virtualizor. Imports read the source panel’s API without changing anything, then copy or adopt each server.

Two ways to move a server

Copy Adopt
Where it ends up On one of your nodes Stays on the same hypervisor
Needs SSH as root from your node to the source hypervisor This panel’s agent installed on the source hypervisor
Downtime While the disk copies, roughly a minute per 6 GB One restart
What happens The server shuts down on its hypervisor, its disk is pulled over SSH and it starts here with the same MAC and addresses The disk is renamed into the node’s storage (lvrename, zfs rename or a file rename) and the server restarts once
Rollback The copy goes, and the original starts again The original definition is put back

Step by step

1. Make an API credential on the source panel

  • VirtFusion: an API token (Settings → API).
  • Virtualizor: an admin API key and pass, from API Key Pairs (Configuration → API Credentials on older versions). Copy both in full; a key or pass Virtualizor doesn’t accept shows as “sent the request to its sign-in page”. If the key pair limits which addresses may use it, allow the controller’s address. The import works with both ways Virtualizor versions take the key.

2. Start the import

Imports → New import. Pick the panel and enter its address, e.g. https://vz.example.com:4085, and the key (plus the pass for Virtualizor). It can be on your private network, but not a link-local address such as 169.254.169.254.

Give it a name if you like, such as DFW batch 2 or test import: it’s shown in the list of imports, at the top of the import and in the audit log, to tell imports from the same panel apart. Change or clear it at any time, even after the import has finished, with the pencil next to its title (or PATCH /admin/migrations/{id} with {"name": "…"}).

Virtualizor uses a self-signed certificate by default. The panel shows its SHA-256 fingerprint. Compare it on the Virtualizor server, then choose trust it and connect:

openssl x509 -noout -fingerprint -sha256 -in <its certificate file>

3. Discovery

The import lists the source’s hypervisors, packages, IP pools and servers.

Until migrating starts, Discover again (top of the import) reads the source again, for example after you change something there or update this panel; the mappings start afresh. Cancel import deletes an import nothing has moved in yet, with its saved API credentials, so you can start a new one from the same panel.

4. Map

Choose:

  • which of your packages each source package becomes, or Leave out of this import to keep its servers on the source
  • what happens to each source IP range (see IP addresses below)
  • where each hypervisor’s servers go: a node group of yours. Copies are spread over its nodes by the group’s placement rule, one after another, the same way new orders are, so a batch fills the group as orders would rather than all landing on one node. The dry run shows the node each server goes to.
  • how to settle each conflict, such as an address range that overlaps one of yours

IP addresses

A copied server only keeps working on its old address if that range is routed to the node it’s copied to. Usually the range is routed to the source hypervisor, so ask your provider to move it first, or give the copies new addresses. For each source range, choose:

  • Keep the addresses: add as a new pool. Servers keep their addresses, and a pool for the range is added when its first server moves. Use this when the range is (or will be) routed to your nodes.
  • Give copies new addresses from their new node. Each copy gets IPv4 addresses from the IP pools of the node it lands on; IPv6 addresses from the source are dropped. After the copy starts, the node switches the server over inside through its guest agent (qemu-guest-agent), the same way as when you move a server to a node outside its pools. If the guest has no agent, the import says so and the node keeps trying once one answers; until then, set the address from the console. With Email customers… on, owners are emailed their new addresses. The dry run checks there are enough free addresses on each node. Adopted servers stay where they are, so they always keep their addresses.
  • Part of your pool …: only offered for one of your pools the range falls in. Servers keep their addresses.
  • Leave out of this import: servers with addresses in the range stay on the source.

Rolling a server back gives its new addresses back to the pool, and the original runs again with its old ones.

Owners who already have an account here

Servers only go into an existing account you chose. When an owner’s email already has an account in this panel, the import asks:

  • A customer: merge into that account, or import as a separate account (name+vf@… or name+vz@…).
  • A reseller: the same, and the choice says it’s a reseller’s account.
  • A staff member: their servers never go into the staff account itself. You can put them in that person’s own client area (the one Client area opens), or import them separately.

If the separate address (or imports@<source host>, for servers whose owner the source didn’t say) is already taken by an account this import didn’t make, that choice isn’t offered. The servers can only stay on the source until you rename that account.

Accounts are checked again at the dry run and when you start. If one was added since with an importing owner’s email, starting is refused and the conflict shows, waiting for your choice. A server whose owner gets an account here during the run fails instead of joining it, and stays on the source.

5. Give your nodes access (copy mode)

Copies are pulled over SSH as root, so the nodes that copy need their keys in /root/.ssh/authorized_keys on each source hypervisor. Under Let your nodes sign in to the source hypervisors on the mapping page:

  • Add keys with root password (the easy way): enter root’s password for that hypervisor. A node that copies off it signs in once, on SSH port 22, and adds every copying node’s key. Keys already there aren’t added twice. The password is used for that one sign-in and isn’t saved anywhere: not in the database, the logs or the audit log.
  • Or add them yourself: if root can’t sign in with a password there (PermitRootLogin prohibit-password, or PasswordAuthentication no in /etc/ssh/sshd_config), copy the one command shown and run it as root on each source hypervisor.

Then run the dry run: it checks every server from the node that will copy it.

For adopt mode, enroll the source hypervisor as a node of this panel instead. The import recognises it by address: the hypervisor’s address in the source panel has to be the node’s management address or one of its own addresses. Virtualizor lists the server it’s installed on as localhost / 127.0.0.1; the import uses the panel’s address for it. Servers’ names are never used to recognise a node, since different machines can have servers of the same name (Virtualizor calls them v1001, v1002…).

6. Dry run

The dry run checks every server from the node that will do the work:

  • it can log in over SSH
  • the domain exists
  • there’s one raw or qcow2 disk. VirtFusion’s cloud-init drive (/home/vf-data/server/<uuid>/cloud-drive.img) doesn’t count: it’s VirtFusion’s settings for the server, not its data, and stays on the source
  • it boots with BIOS, not UEFI
  • for VirtFusion, that the server is running: VirtFusion runs its servers as transient libvirt domains, so a stopped one isn’t on the hypervisor at all. Start it in VirtFusion first. The import keeps each domain’s definition before shutting it down, so after a failed copy or a rollback it creates the original again, running, the way VirtFusion would
  • what its MAC address is

Fix anything it reports, then Run dry run again at the bottom of the dry run: for example after freeing addresses in a pool, making room on a node or adding a node’s key on a source hypervisor. Your mappings are kept. A server added or removed on the source panel itself needs Discover again (top of the import) instead, since the dry run works from what discovery read.

7. Migrate

During the run, each server shows its progress. A server that fails can be retried; retrying is safe.

Each server shows its operating system under its name, on the dry run and here: what the source panel says it runs (marked per VirtFusion or per Virtualizor) until it runs on your node, then what its guest agent reports, as on the server’s own page. So a Windows server failing its ping check is easy to spot: Windows blocks ping by default.

Each server’s copy or adoption is also a job (kind Import) under Operations → Jobs, on the node doing the work and on the imported server’s page, with a live log of every command the node runs on the source hypervisor. When one fails, its job log shows exactly which step and what the source said. Each retry is a new job. The import as a whole stays on its own page under Imports: discovery, mapping and the dry run aren’t jobs, since nothing runs on your nodes until migrating starts.

8. Verify and roll back if needed

Each migrated server lists its checks with ✓ or ✗: it runs on its node, its first address answers ping, and, for a server given new addresses, that it switched to them inside. Fix what a failed check says, then click Check again: it switches the server to its new addresses first if it hasn’t yet, then runs the checks again. A node whose agent is older than the panel says so; update the agent on the node’s page first.

Windows guests: whether a server runs Windows is asked of its guest agent, so new addresses are set with PowerShell even when the source panel didn’t say it’s Windows. Windows blocks ping by default, so for a Windows server Remote Desktop (port 3389) answering counts as reachable too; with both off, check it from the console.

Check each server works on the new side. Roll back removes the copy and starts the original again where it was.

An imported server shows the operating system the source panel named (Virtualizor’s template, such as almalinux-9-x86_64, becomes “AlmaLinux 9”), or “Imported from …” when it didn’t say. Once the server’s guest agent (qemu-guest-agent) answers, the node reads the real one, such as “AlmaLinux 9.4”, and the panel shows that instead, within a minute. Staff with the Settings, root password and rescue permission can also click Detect OS next to Image on any running server’s Overview, for example after an upgrade inside it. Both are in the server’s activity and the audit log.

9. Finish

Finish the import. It deletes the stored API credential.

10. Remove Virtualizor from adopted nodes (optional)

After a Virtualizor import with servers adopted in place, the finished import asks, for each of those nodes, whether to take Virtualizor off it. Keep Virtualizor leaves it alone. Yes, show me how offers two ways.

Remove Virtualizor now has the node’s agent do it. It changes nothing while libvirt still has a server that isn’t the panel’s, or a server uses a file in Virtualizor’s folders. It stops Virtualizor’s panel service and takes its lines out of root’s crontab (keeping a copy in /root/crontab-before-virtualizor-removal). Only when every bridge the servers plug into is in the node’s own network settings does it also turn off Virtualizor’s network service and move its folders to /root/virtualizor-removed-<time>; otherwise it leaves them and says why. It then checks the servers that were running still are and their bridges are still there, and if not, puts everything back and starts them again. Nothing is deleted. When it leaves them, it works out from the node exactly what to write so the node builds the bridge itself (same port, MAC and addresses, in netplan, /etc/network/interfaces or /etc/sysconfig/network-scripts), and shows the commands: they keep a copy of the old files in /root/network-before-<bridge>, write the new ones and, with netplan, check them with netplan generate. Don’t run netplan try or netplan apply: the bridge is already up, the new settings are for the next boot, and netplan can’t undo bridge settings. Where the bridge’s address now differs from your settings (Virtualizor often sets a wider netmask than the provider’s), it says so: the settings’ address is what the node gets from the next boot. After running them, Run it again finishes the job; then reboot the node with its console at hand.

Or run the commands yourself lists the same as commands to run as root on the node, one step at a time:

  1. See what Virtualizor runs there. This changes nothing.
  2. When the node’s servers plug into a bridge other than br-public (on Virtualizor nodes, viifbr0): check whether that bridge is in your network settings, or only built at boot by Virtualizor’s network service (virtnetwork).
  3. Stop Virtualizor’s panel and its cron jobs. The servers, libvirt and the network service keep running, and the step says how to undo it.
  4. Move its files (/usr/local/virtualizor, /usr/local/emps) to /root/virtualizor-removed. Only do this once the bridge check passes, or the servers lose their network at the next reboot. Delete the folder once the node has rebooted and its servers are back.

It warns first when servers are still on Virtualizor there, when Virtualizor’s own panel runs on the node (its other hypervisors lose it too), and while rollback is still open, since rolling back hands a server back to Virtualizor. The choice can be changed. Through the API: POST /admin/migrations/{id}/source-removal records it, and POST /admin/migrations/{id}/source-removal/run has the panel do it.

11. Remove VirtFusion from adopted nodes (optional)

After a VirtFusion import with servers adopted in place, the finished import asks the same question for each of those nodes, and offers the same two ways.

VirtFusion’s hypervisor layout isn’t documented, so nothing is assumed: the node finds what VirtFusion left by name. That’s systemd services whose unit file names or mentions VirtFusion, Docker containers named after it (its control panel, when that runs on the node), cron jobs, the SSH key its control server signs in with (a line in /root/.ssh/authorized_keys that says virtfusion), and /opt/virtfusion. Run the first manual step, See what VirtFusion left here, to see the list before anything changes.

  • Remove VirtFusion now has the node’s agent do it. It changes nothing while libvirt still has a server that isn’t the panel’s (VirtFusion’s servers are transient, so that’s any of its servers still running there). It stops and disables VirtFusion’s services, stops its containers and keeps them from starting again (they aren’t deleted), takes its cron jobs and its control server’s SSH key out (copies in /root/crontab-before-virtfusion-removal and /root/authorized_keys-before-virtfusion-removal), and moves /opt/virtfusion and its unit and cron files to /root/virtfusion-removed-<time>. If a server stops or its bridge goes, everything is put back.
  • Never touched: libvirt, qemu, SSH, Docker itself, networking and this panel’s agent, even if their settings mention VirtFusion; and /home/vf-data, since adopted servers keep their disks in /home/vf-data/disk. The rest of /home/vf-data (VirtFusion’s cloud-init drives, ISOs and settings) isn’t used by this panel: delete it yourself once you’re sure, but never the disk folder.
  • When nothing has VirtFusion’s name, it says so and changes nothing. If its control server’s key isn’t marked, it says to look for it in authorized_keys yourself.
  • VirtFusion doesn’t build the servers’ bridge, but if that bridge isn’t in the node’s own network settings, it shows what to write so it comes back after a reboot, as for Virtualizor.

Moving a fleet a hypervisor at a time

Always connect to the source’s panel itself: Virtualizor’s master (the control server) or VirtFusion’s panel. That’s the only place with an API. An import lists every hypervisor it manages; the nodes themselves aren’t connected to separately.

  1. Under Hypervisors on the mapping page, click Leave out of this import on every hypervisor but the one you’re moving now. Their servers stay on the source.
  2. Migrate, verify and finish. Then take Virtualizor off that hypervisor if you like: a hypervisor that isn’t the master only loses Virtualizor’s node software.
  3. Start a new import from the same panel for the next hypervisor. Servers an earlier import moved are skipped (“Already moved by an earlier import”).
  4. Do the master last. The panel won’t take Virtualizor off the master while any server on its other hypervisors is still on Virtualizor: those servers would lose their panel, and later imports connect to it.

If something goes wrong

Collect:

  • the error text on the import page
  • the What the API returned text
  • journalctl -u panel-agent -n 100 from the node that did the work
Message Usual cause
Couldn’t log in over SSH The copying node’s key isn’t in root’s authorized_keys on the source hypervisor. Use Add keys with root password on the mapping page
“root on … didn’t accept that password” The password is wrong, or root can’t sign in with a password there. Use Or add them yourself instead
“OpenVZ or LXC container. Stays on the source panel.” Containers can’t run on KVM. They keep working on the source panel.
“Windows guest. Stays on the source panel.” Windows servers aren’t supported by imports in this version.
“It boots with UEFI; only BIOS servers can be imported for now.” Only BIOS-booted servers are imported for now.

Every word has to appear. ↑ ↓ to move, Enter to open.