Skip to content
Commitpedia
Log in Join & edit

Run your first KVM virtual machine with libvirt and virt-install

Turn a Linux desktop or server into a KVM host: check CPU support, install libvirt, use the default NAT network, create a VM from a cloud image, take snapshots and enable autostart.

Drafted with AI from official documentation. Scripts were run in a test environment and repository links verified. Awaiting a human check. Did it work for you? Last edited Outdated?

Edit history of Run your first KVM virtual machine with libvirt and virt-install: 1 recorded edit
Edit history · 1 edit
Type
Article
Edits
1
Editors
1
First issued
15 Oct 2026
Last edit
15 Oct 2026
Reading
10 min

KVM is the virtualization feature built into the Linux kernel. On its own it is just a kernel module; QEMU provides the virtual hardware, libvirt manages VMs, networks and storage, and command-line tools like virsh and virt-install talk to libvirt. This tutorial is for anyone with a Linux machine who wants to run VMs without installing a full hypervisor distribution.

You will create a Debian VM from an official cloud image, which skips the whole OS installer and boots in under a minute. Commands are given for Debian/Ubuntu and for RHEL-family systems (RHEL, Rocky Linux, AlmaLinux, Fedora) where they differ.

What you will build

  • A KVM host with libvirt running and the built-in default NAT network active.
  • A VM called vm1 with 2 vCPUs, 2 GB RAM and a 20 GB disk, created with one virt-install command.
  • SSH access into the VM using your own key, injected by cloud-init on first boot.
  • A snapshot you can roll back to after breaking something on purpose.
  • The VM set to start automatically when the host boots.

Before you start

  • A Linux machine (physical, not itself a VM unless nested virtualization is enabled) with an x86-64 CPU that supports Intel VT-x or AMD-V. Debian 12 or newer, Ubuntu 22.04 or newer, or RHEL/Rocky/AlmaLinux 9 or newer are good choices. Red Hat’s guide asks for at least 2 GB of RAM and 6 GB of disk for the host plus the same again for each VM.
  • A user with sudo rights and internet access to download packages and a 400 MB cloud image.
  • An SSH key pair on that machine. If ls ~/.ssh/id_ed25519.pub shows nothing, create one with ssh-keygen -t ed25519.
  • Time: about 45 minutes.
  • Knowledge: comfortable in a terminal, installing packages with apt or dnf, and connecting with ssh. Knowing the difference between a hypervisor, a VM and a disk image helps.

Step 1: Check that the CPU supports virtualization

Why: KVM needs hardware virtualization extensions. Without them, VMs either refuse to start or fall back to very slow pure emulation.

grep -Ec '(vmx|svm)' /proc/cpuinfo
lscpu | grep -i virtualization
ls -l /dev/kvm

A number greater than 0 means the CPU has Intel VT-x (vmx) or AMD-V (svm). /dev/kvm appears once the KVM kernel module is loaded, which normally happens automatically. If the count is 0 or /dev/kvm is missing, reboot into the firmware (BIOS/UEFI) setup and enable the option usually called Intel Virtualization Technology or SVM Mode.

On Ubuntu you can also install the cpu-checker package and run kvm-ok, which explains the result in plain words.

Step 2: Install QEMU, libvirt and the tools

Why: these packages give you the hypervisor, the management daemon, virsh, virt-install and qemu-img. virt-install also needs an ISO tool such as xorriso to build the small cloud-init disk used in Step 5.

Ubuntu:

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo apt update
sudo apt install qemu-kvm libvirt-daemon-system virtinst qemu-utils xorriso

Debian (use --no-install-recommends on a headless server to skip graphical extras):

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo apt update
sudo apt install --no-install-recommends qemu-system libvirt-clients libvirt-daemon-system virtinst qemu-utils xorriso

RHEL, Rocky Linux, AlmaLinux (9 or newer). These releases use modular libvirt daemons that start through systemd sockets, so the loop starts each one:

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo dnf install qemu-kvm libvirt virt-install qemu-img xorriso
for drv in qemu network nodedev nwfilter secret storage interface; do sudo systemctl start virt${drv}d{,-ro,-admin}.socket; done
sudo virt-host-validate

Check: sudo virsh version prints libvirt and QEMU versions without errors. On RHEL-family hosts, virt-host-validate should show PASS for the QEMU hardware virtualization checks; WARN lines about IOMMU only matter for passing physical devices through to VMs.

This tutorial runs virsh with sudo so that every command talks to the system-wide libvirt instance (qemu:///system). As a normal user without sudo, virsh may connect to a separate per-user session and show none of your VMs. If you prefer not to type sudo, add yourself to the libvirt group, log out and back in, and set export LIBVIRT_DEFAULT_URI=qemu:///system in ~/.bashrc.

Step 3: Start the default NAT network

Why: libvirt ships a virtual network called default. It creates a bridge named virbr0 on the host (normally 192.168.122.1/24), hands out DHCP addresses to VMs, and uses NAT so VMs can reach the internet through the host. The VMs are reachable from the host, but not from other machines on your LAN, which is a safe start.

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo virsh net-list --all

If default is listed as inactive or with autostart no (Debian does not start it automatically), start it and mark it for autostart:

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo virsh net-start default
sudo virsh net-autostart default
ip addr show virbr0

Check: net-list shows default active yes, and ip addr show virbr0 shows the bridge address.

Step 4: Download a cloud image and prepare the disk

Why: distributions publish ready-made cloud images: small disk images with the OS already installed and cloud-init inside, which configures users and SSH keys at first boot. This is far quicker than clicking through an installer. Debian’s genericcloud image is built for VMs.

cd /tmp
curl -LO https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.qcow2
curl -LO https://cloud.debian.org/images/cloud/trixie/latest/SHA512SUMS
sha512sum --ignore-missing -c SHA512SUMS

Check: the last command prints debian-13-genericcloud-amd64.qcow2: OK. Now copy the image into libvirt’s default storage directory under the VM’s name and grow it to 20 GB. The original download stays untouched, so you can reuse it for more VMs.

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo cp debian-13-genericcloud-amd64.qcow2 /var/lib/libvirt/images/vm1.qcow2
sudo qemu-img resize /var/lib/libvirt/images/vm1.qcow2 20G
sudo qemu-img info /var/lib/libvirt/images/vm1.qcow2

qemu-img info should report file format: qcow2 and virtual size: 20 GiB. The disk file only uses as much real space as the data written into it. On first boot cloud-init normally grows the root partition to fill the new size.

Step 5: Create the VM with virt-install

Why: virt-install writes the VM definition for libvirt and starts it in one go. --import says the disk already contains an installed system, and --cloud-init builds a tiny configuration disk that is attached for the first boot only.

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo virt-install \
  --name vm1 \
  --memory 2048 \
  --vcpus 2 \
  --osinfo debian13 \
  --import \
  --disk path=/var/lib/libvirt/images/vm1.qcow2,bus=virtio \
  --network network=default,model=virtio \
  --graphics none \
  --noautoconsole \
  --cloud-init clouduser-ssh-key=$HOME/.ssh/id_ed25519.pub
  • --osinfo debian13 lets libvirt pick good defaults for that OS. If your host’s OS database is older and rejects the name, list what it knows with virt-install --osinfo list | grep -i debian, or use the generic linux2022.
  • bus=virtio and model=virtio use paravirtualized devices, which are much faster than emulated ones.
  • --graphics none skips a graphical display; you will use SSH and the serial console instead.
  • clouduser-ssh-key installs your public key for the image’s default user, which is debian on Debian cloud images (ubuntu on Ubuntu images). The $HOME is expanded by your shell before sudo runs, so it points at your own key.
  • --cloud-init was added in virt-install 3.0. Older versions report an unknown option; update the host or use a newer distribution.

Check: the command ends with a message that the domain creation completed, and the VM is running:

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo virsh list --all

Step 6: Find the VM's address and log in

Why: the VM got its address from libvirt’s DHCP server on the default network. libvirt can tell you which lease it handed out.

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo virsh domifaddr vm1
sudo virsh net-dhcp-leases default

Give it 20 to 60 seconds after creation for the first boot and cloud-init to finish. Then connect with the address shown, for example:

ssh [email protected]

Inside the VM, check that cloud-init finished and look around:

cloud-init status --wait
hostnamectl
df -h /
ping -c 3 deb.debian.org

Check: cloud-init status reports status: done, the root filesystem is close to 20 GB, and the VM can reach the internet through NAT. If SSH does not work, attach to the serial console with sudo virsh console vm1 to see boot messages; press Ctrl+] to leave the console.

Step 7: Stop, start and inspect the VM

Why: these are the commands you will use every day. shutdown asks the guest OS to power off cleanly. destroy is the equivalent of pulling the power cable: it does not delete anything, but the guest gets no chance to save data, so use it only when shutdown fails.

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo virsh shutdown vm1
sudo virsh list --all
sudo virsh start vm1
sudo virsh dominfo vm1

Check: after shutdown, list --all shows shut off (it can take a few seconds); after start it shows running again. dominfo shows memory, vCPUs and the autostart setting.

Step 8: Take a snapshot and roll back

Why: a snapshot saves the VM’s disk state (and optionally memory) so you can return to it after a failed upgrade or experiment. With a qcow2 disk, libvirt can store the snapshot inside the same file. Taking it while the VM is shut off is the simplest and most reliable way.

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo virsh shutdown vm1
sudo virsh list --all
sudo virsh snapshot-create-as vm1 clean-install "Fresh Debian after first boot"
sudo virsh snapshot-list vm1

Now break something on purpose: start the VM, log in, and create a file that should disappear after the rollback.

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo virsh start vm1
ssh [email protected] 'touch ~/i-was-here && ls ~'

Shut the VM down again and revert. Warning: reverting is destructive; every change made since the snapshot is lost.

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo virsh shutdown vm1
sudo virsh snapshot-revert vm1 clean-install
sudo virsh start vm1
ssh [email protected] 'ls ~'

Check: the file i-was-here is gone. Snapshots in the same qcow2 file are not backups: if the disk file is lost, the snapshots go with it. When you no longer need one, remove it with sudo virsh snapshot-delete vm1 clean-install.

If snapshot creation fails with an error mentioning firmware or pflash, the VM uses UEFI firmware, which limits this simple kind of snapshot. Read the error message and the snapshot-create-as section of the virsh manual for external snapshot options.

Step 9: Start the VM automatically at boot

Why: by default VMs stay off after the host reboots. Autostart tells libvirt to start the VM when the libvirt service starts.

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo virsh autostart vm1
sudo virsh list --all --autostart

To turn it off again later, use sudo virsh autostart --disable vm1. The default network must also be set to autostart (Step 3), otherwise the VM cannot start because its network is missing.

Check that it works

  1. Reboot the host: sudo reboot.
  2. After it is back, run sudo virsh list --all; vm1 should be running without you starting it.
  3. sudo virsh net-list shows default as active.
  4. ssh debian@<address from virsh domifaddr vm1> logs you in with your key and no password.
  5. sudo virsh snapshot-list vm1 still lists clean-install, unless you deleted it.

If something goes wrong

  • virsh list --all shows nothing, although the VM exists: you are connected to the per-user session. Run the command with sudo, or use virsh --connect qemu:///system list --all.
  • VM creation fails because network ‘default’ is not active: run sudo virsh net-start default and sudo virsh net-autostart default. If the network does not exist at all, the libvirt network daemon or package is missing; reinstall libvirt-daemon-system (Debian/Ubuntu) or check that the virtnetworkd socket is running (RHEL family).
  • No hardware virtualization: virt-host-validate shows a FAIL for the hardware virtualization check, or /dev/kvm is missing. Enable VT-x/AMD-V in the firmware; inside a VM, enable nested virtualization on the outer hypervisor.
  • virt-install cannot create the cloud-init disk: install xorriso (or genisoimage), which virt-install uses to build the ISO.
  • SSH asks for a password or refuses the key: check that you used the right user name for the image (debian for Debian), and look at the serial console (sudo virsh console vm1) for cloud-init errors during boot.
  • Permission denied reading the disk image: keep VM disks under /var/lib/libvirt/images. Files in your home directory may not be readable by the QEMU process, and on RHEL-family systems SELinux labels images in that directory correctly.

Clean up

Warning: the last command below deletes the VM’s disk file permanently, including all snapshots inside it. First run sudo virsh domblklist vm1 to see exactly which file will be removed, and make sure you do not need anything from the VM.

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo virsh domblklist vm1
sudo virsh destroy vm1
sudo virsh undefine vm1 --snapshots-metadata --remove-all-storage
sudo virsh list --all
rm /tmp/debian-13-genericcloud-amd64.qcow2 /tmp/SHA512SUMS

destroy only stops the VM (it prints an error if the VM is already off, which is fine). undefine removes the definition, snapshot metadata and, with --remove-all-storage, the disk volume. Keep the libvirt packages installed if you want to create more VMs; the downloaded cloud image can be reused for that.

Next steps

  • Install virt-manager on a desktop for a graphical view of the same VMs, including remote hosts over SSH.
  • Create a Linux bridge on the host so VMs get addresses from your LAN instead of NAT.
  • Write your own cloud-init user-data file and pass it with --cloud-init user-data=... to install packages and create users automatically.
  • Use qemu-img create -f qcow2 -b base.qcow2 -F qcow2 vm2.qcow2 to make thin VM disks that share one base image.
  • Back up VMs by copying the disk files while the VM is shut off, or explore virsh backup-begin.

Official documentation

Did this work for you?

No votes yet. Be the first.

If it did not work, the report form below tells the editors what went wrong.

See also

  • 0098 What Proxmox VE is: KVM virtual machines, LXC containers and a web UI Proxmox VE is an open source virtualization platform based on Debian. It runs KVM virtual machines and LXC containers and is managed… Beginner · Explains an idea · Linux Article Basics · Installation & first steps 15 Oct 2026
  • 0100 Create a VM and a cloud-init template with qm Create KVM virtual machines from the command line with qm, then build a reusable cloud-init template from a cloud image and clone… Intermediate · Step by step · Linux Article Basics · VMs & containers 15 Oct 2026
  • 0123 KVM vs QEMU vs libvirt: how Linux virtualization fits together KVM is the Linux kernel part that uses CPU virtualization extensions, QEMU is the program that emulates a full machine around it,… Beginner · Explains an idea · Linux Article Basics 15 Oct 2026
  • 0124 virsh cheat sheet: everyday libvirt commands A quick reference for virsh: list, start, stop and inspect VMs, change CPUs and memory, manage networks, storage pools and snapshots, with… Intermediate · Cheat sheet · Linux Article Basics 15 Oct 2026
  • 0125 Create a KVM virtual machine with virt-install Use virt-install to create libvirt/KVM guests: install from an ISO, run a text-only install over the serial console, or import a cloud… Intermediate · Step by step · Linux Article Basics 15 Oct 2026
  • 0126 KVM snapshots and cloning with virsh and virt-clone Take, list, revert and delete libvirt snapshots with virsh, understand internal vs external and disk-only snapshots, and clone a stopped VM with… Advanced · Step by step · Linux Article Basics 15 Oct 2026

Repos in the wild

History

Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.

  1. Dominik +13,973 chars

Report a problem

Something wrong, unsafe or copied? Tell the editors.
What is wrong?