Linux VPS

Back up running KVM VMs with virsh and a simple script

Back up live KVM virtual machines without downtime using external snapshots and blockcommit, save the XML definition, compress and copy off-host, schedule with cron and restore.

AdvancedKVM hosts2 min read

Plain libvirt has no built-in backup scheduler, but you can make consistent backups of running VMs with an external snapshot: new writes go to a temporary overlay while you copy the now-static base disk, then the overlay is merged back. This guide turns that into a script to back up running KVM VMs with virsh.

Before you start

  • A KVM host with file-based disks (qcow2 or raw files). For LVM or ZFS, use their snapshot tools instead.
  • The QEMU guest agent running in each VM for filesystem freeze.
  • A backup destination off the host (NFS, another server, or object storage).
  • Enough free space on the host for overlay files during backup.

How it works

  1. virsh snapshot-create-as --disk-only --quiesce freezes filesystems, creates an overlay and redirects writes to it.
  2. The original disk is now read-only and consistent, so you copy it.
  3. virsh blockcommit --active --pivot merges the overlay back and switches the VM to the original disk.
  4. Remove the overlay and snapshot metadata.

The backup script

Save as /usr/local/bin/kvm-backup.sh and adapt paths:

#!/bin/bash
set -euo pipefail
VM="$1"
DEST="/mnt/backup/$VM/$(date +%F)"
mkdir -p "$DEST"
virsh dumpxml "$VM" > "$DEST/$VM.xml"
DISK=$(virsh domblklist "$VM" --details | awk '$2=="disk"{print $3; exit}')
SRC=$(virsh domblklist "$VM" --details | awk '$2=="disk"{print $4; exit}')
virsh snapshot-create-as "$VM" bk --disk-only --atomic --quiesce --no-metadata
cp --sparse=always "$SRC" "$DEST/"
virsh blockcommit "$VM" "$DISK" --active --pivot --wait
rm -f "${SRC%.*}.bk"
echo "Backup of $VM done: $DEST"

Notes:

  • The script handles the first disk only; loop over all disks for multi-disk VMs.
  • The overlay file name depends on libvirt's default naming (the base name plus .bk); check it on your system before relying on the rm line.
  • Remove --quiesce if the agent is unavailable (the backup will be crash-consistent).

Schedule it

chmod +x /usr/local/bin/kvm-backup.sh

In root's crontab:

0 3 * * * /usr/local/bin/kvm-backup.sh web01 >> /var/log/kvm-backup.log 2>&1

Add retention, for example deleting folders older than 14 days with find /mnt/backup -mindepth 2 -maxdepth 2 -type d -mtime +14 -exec rm -rf {} +. Copy to another site too, e.g. with rclone.

Restore a VM

  1. Copy the disk back to its original path.
  2. virsh define /mnt/backup/web01/2025-08-05/web01.xml
  3. virsh start web01

Troubleshooting

  • quiesce fails: guest agent missing or not running.
  • blockcommit fails, VM still on overlay: do not delete the overlay; check virsh domblklist and retry the commit.
  • Host disk fills during backup: heavy writes grow the overlay; schedule backups at quiet times.

Frequently asked questions

Is there a ready-made tool?

Yes, tools such as virtnbdbackup use libvirt's newer backup API for incremental backups, and Proxmox includes vzdump.

Can I copy the disk without a snapshot?

Only with the VM shut down; copying a live disk gives an inconsistent image.

Should I compress backups?

Yes, with zstd or by converting to compressed qcow2 using qemu-img convert -c.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.