Bare-metal to Proxmox with no downtime
How to move production services from physical hardware into virtualisation so nobody notices.
The client had four physical servers, one application each. A classic 2015–2018 setup: one server = one service, no virtualisation, no backups beyond rsync to a NAS.
The brief: get it onto Proxmox, gain snapshots and live migration, and keep downtime under a few minutes per service.
The plan
The approach we use almost every time:
- Build a new Proxmox cluster alongside (three nodes, Ceph pool).
- For each service create a VM and deploy from configuration management — not by cloning the old disk.
- Run both instances in parallel, synchronise data one-way.
- Switch DNS / load balancer, watch, keep the old instance on standby for a week.
Point 2 matters. Cloning a physical disk into a VM (P2V) is fast, but it carries ten years of sediment with it — old packages, manual /etc edits nobody documented. If you have Ansible, rebuild instead.
What surprised us
A licence server. One application had its licence tied to a physical NIC’s MAC address. Fix: set the same MAC on the virtual interface. It worked, but we found out on migration day.
Ceph IOPS. A database that ran fine on local NVMe slowed noticeably on a three-replica Ceph pool. We moved it to local-lvm on one node and handle redundancy at the database layer instead of the storage layer.
# Measure before deciding — always worth it
fio --name=randwrite --ioengine=libaio --iodepth=32 \
--rw=randwrite --bs=4k --direct=1 --size=4G \
--numjobs=4 --runtime=60 --group_reporting
Result
The migration took three weeks in total, of which the actual cutovers were four windows of ~4 minutes. The client now has snapshots before every update, deduplicated daily backups via Proxmox Backup Server, and the ability to move VMs between nodes during maintenance with no downtime.