Most KVM guides for Fedora still tell you to enable a list of libvirt sockets, define a storage pool by hand and pass --os-variant fedora44 to virt-install. On Fedora 45 and Fedora 44, the sockets are already enabled, the pool creates itself, and that os-variant makes virt-install fail with “Unknown OS name”. I rebuilt the whole setup on a Fedora 45 Workstation box, a headless Fedora 45 machine and a Fedora 44 machine to see what you actually need to type now.
The guests below were created from the CLI and from virt-manager on nested Fedora 45 and Fedora 44 hosts. The package group, socket and host validation steps were run again on a fresh Fedora 45 machine in November 2026 and gave the same result.
What changed in the Fedora KVM setup
The quick version, before the steps:
| Item | What older guides say | What Fedora 45 and 44 did on my machines |
|---|---|---|
| libvirt sockets | Enable seven sockets in a loop | Enabled by preset on install, but not started until reboot or systemctl start sockets.target |
| Default NAT network | Run net-start and net-autostart | Already active with autostart on |
| Storage pool | Define default by hand | virt-install creates default on first use |
--os-variant fedora44 | Works | “Unknown OS name”: osinfo-db stops at fedora43 |
virsh as a normal user | Talks to the system instance once you join the libvirt group | Still connects to qemu:///session unless you set a default URI |
| Fedora Workstation | Install everything | libvirt and QEMU already installed by GNOME Boxes; the group adds 12 packages |
1. Check CPU virtualization support
KVM needs Intel VT-x or AMD-V. Count the CPU threads that advertise it and check that the kernel modules loaded:
grep -Ec '(vmx|svm)' /proc/cpuinfo
lscpu | grep -iE 'virtualization|hypervisor vendor|model name'
lsmod | grep -E '^kvm'
My headless test box is itself a VM with nested virtualization enabled, so it shows the KVM hypervisor line as well as VT-x:
8
Model name: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
Virtualization: VT-x
Hypervisor vendor: KVM
Virtualization type: full
kvm_intel 557056 7
kvm 1564672 4 kvm_intel
Any number above zero is fine (vmx is Intel, svm is AMD). Zero on bare metal means virtualization is switched off in the firmware setup. Look for “Intel Virtualization Technology” or “SVM Mode”. Zero inside a VM means the parent hypervisor is not passing the flag through. On Proxmox that means CPU type host and nested=1 on the kvm_intel or kvm_amd module.
2. Install the virtualization group
The @virtualization group pulls in QEMU, libvirt, virt-install, virt-manager and virt-viewer. Check what it contains on your release first:
dnf group info virtualization
On Fedora 45, virt-manager is a default package of the group, so a plain group install brings in the GUI too:
Id : virtualization
Name : Virtualization
Description : These packages provide a graphical virtualization environment.
Installed : no
Order :
Langonly :
Uservisible : no
Repositories : fedora, updates
Mandatory packages : virt-install
Default packages : libvirt-daemon-config-network
: libvirt-daemon-kvm
: qemu-kvm
: virt-manager
: virt-viewer
Optional packages : guestfs-tools
: python3-libguestfs
: virt-top
Install it:
sudo dnf install -y @virtualization
How big that is depends on the edition. On the Fedora 45 Cloud image it was 416 packages and 227 MiB, and on Fedora 44 Cloud 441 packages and 235 MiB. virt-manager and virt-viewer account for only 12 of them, so leaving the GUI off a headless host saves very little. Fedora 45 Workstation needed just 12 packages, because GNOME Boxes ships with Workstation and already requires libvirt-daemon-kvm and QEMU.
For group IDs like @virtualization and the rest of the dnf5 syntax, see the DNF5 commands cheat sheet.
Check the versions you got:
rpm -q qemu-kvm libvirt-daemon libvirt-client virt-install virt-manager virt-viewer
Fedora 45 had these:
qemu-kvm-11.1.2-1.fc45.x86_64
libvirt-daemon-12.6.0-2.fc45.x86_64
libvirt-client-12.6.0-2.fc45.x86_64
virt-install-5.1.0-5.fc45.noarch
virt-manager-5.1.0-5.fc45.noarch
virt-viewer-11.0-20.fc45.x86_64
And Fedora 44 had these:
qemu-kvm-10.2.2-1.fc44.x86_64
libvirt-daemon-12.0.0-3.fc44.x86_64
libvirt-client-12.0.0-3.fc44.x86_64
virt-install-5.1.0-4.fc44.noarch
virt-manager-5.1.0-4.fc44.noarch
virt-viewer-11.0-18.fc44.x86_64
Fedora 44 sits one QEMU major and a few libvirt releases behind, but none of the steps below changed between the two releases.
3. Start the libvirt sockets
Fedora uses the modular libvirt daemons: virtqemud for guests, virtnetworkd for networks, virtstoraged for pools and a few more, each started on demand by a systemd socket. The packages enable those sockets through the Fedora presets, so there is nothing to enable. They are not started at install time, though:
systemctl is-enabled virtqemud.socket virtnetworkd.socket virtstoraged.socket libvirtd.socket libvirtd.service
systemctl is-active virtqemud.socket virtnetworkd.socket virtstoraged.socket
Right after the group install on Fedora 45, the sockets were enabled but still inactive, and the monolithic libvirtd was disabled:
enabled
enabled
enabled
disabled
disabled
inactive
inactive
inactive
In that state every virsh call fails, even as root:
error: failed to connect to the hypervisor
error: Operation not supported: No URI is provided and cannot identify any listening daemon socket path to attempt to connect to. Please ensure the expected daemon sockets are active and/or provide an explicit URI. For more information see https://libvirt.org/kbase/failed_connection_after_install.html
Starting only virtqemud.socket is not enough either. Guests list, but network and pool calls go to their own daemons:
Id Name State
--------------------
error: Failed to list networks
error: Failed to connect socket to '/var/run/libvirt/virtnetworkd-sock': No such file or directory
error: Failed to list pools
error: Failed to connect socket to '/var/run/libvirt/virtstoraged-sock': No such file or directory
Reboot, or start every enabled socket in one go through sockets.target:
sudo systemctl start sockets.target
systemctl is-active virtnetworkd.socket virtstoraged.socket virtnodedevd.socket virtsecretd.socket
All four came up, and the network and pool calls worked straight away:
active
active
active
active
The Fedora 44 machine behaved the same way after install, and after a reboot all three sockets were active without any extra command. On Workstation, where GNOME Boxes installed libvirt before first boot, they were already active.
4. Validate the host
virt-host-validate checks the CPU flag, the device nodes and the cgroup controllers QEMU needs:
sudo virt-host-validate qemu
Everything that matters passed on the Fedora 45 box:
QEMU: Checking for hardware virtualization : PASS
(VMX)
QEMU: Checking if device '/dev/kvm' exists : PASS
QEMU: Checking if device '/dev/kvm' is accessible : PASS
QEMU: Checking if device '/dev/vhost-net' exists : PASS
QEMU: Checking if device '/dev/net/tun' exists : PASS
QEMU: Checking for cgroup 'cpu' controller support : PASS
QEMU: Checking for cgroup 'cpuacct' controller support : PASS
QEMU: Checking for cgroup 'cpuset' controller support : PASS
QEMU: Checking for cgroup 'memory' controller support : PASS
QEMU: Checking for cgroup 'devices' controller support : PASS
QEMU: Checking for cgroup 'blkio' controller support : PASS
QEMU: Checking for device assignment IOMMU support : WARN (No ACPI DMAR table found, IOMMU either disabled in BIOS or not supported by this hardware platform)
QEMU: Checking for secure guest support : WARN (None of SEV, SEV-ES, SEV-SNP, TDX available)
The two warnings are normal on most desktops and small servers. IOMMU only matters for PCI passthrough, and secure guest support means AMD SEV or Intel TDX memory encryption. The Fedora 44 box returned the same 11 PASS lines.
5. Manage VMs without sudo
libvirt has two instances. qemu:///system runs guests as the qemu user with access to the default NAT network and the system pools, and it is what virt-manager uses. qemu:///session runs guests as your own user with user-mode networking, and GNOME Boxes uses that one. VMs in one instance are invisible in the other.
Without the libvirt group, a normal user cannot reach the system instance from SSH or any shell that has no polkit agent:
josphat adm wheel systemd-journal
error: failed to connect to the hypervisor
error: authentication unavailable: no polkit agent available to authenticate action 'org.libvirt.unix.manage'
rc=1
Add yourself to the libvirt group, then log out and back in (a new SSH login is enough):
sudo usermod -aG libvirt "$USER"
After the new login the group is there and the system instance answers. But a plain virsh still picks the session instance, which is why the guest and network lists look empty:
id -nG
virsh uri
virsh -c qemu:///system list --all
virsh -c qemu:///system net-list
The output shows qemu:///session as the default even with the group in place:
josphat adm wheel systemd-journal libvirt
qemu:///session
Id Name State
--------------------
Name State Autostart Persistent
--------------------------------------------
default active yes yes
Make the system instance the default for your user with libvirt’s client config file, which works for every libvirt tool and not only for the shell that sources an rc file:
mkdir -p ~/.config/libvirt
echo 'uri_default = "qemu:///system"' > ~/.config/libvirt/libvirt.conf
virsh uri
From then on, virsh and virt-install go to the system instance without -c:
qemu:///system
The rest of this guide assumes that file is in place.
6. Default network, storage and firewall
You do not have to create the NAT network. On both releases it was active with autostart on as soon as the sockets were running:
virsh net-list --all
The default network gives guests addresses in 192.168.122.0/24 with DHCP and DNS from libvirt’s dnsmasq:
Name State Autostart Persistent
--------------------------------------------
default active yes yes
The storage pool list starts empty, and that is fine. virt-install creates the default pool on /var/lib/libvirt/images the first time you create a disk there, as you will see in the next step. The drive behind that directory sets the I/O ceiling for every guest, and the NVMe and SSD picks for home servers compare drives that hold up with several VMs at once.
On Workstation, firewalld puts the virbr0 bridge in its own libvirt zone:
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --info-zone=libvirt | head -12
The zone’s target is ACCEPT, with DHCP, DNS and SSH listed as services, so guests reach the host without you opening anything:
FedoraWorkstation (default)
interfaces: ens18
libvirt
interfaces: virbr0
libvirt (active)
target: ACCEPT
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces: virbr0
sources:
services: dhcp dhcpv6 dns ssh tftp
ports:
protocols: icmp ipv6-icmp
forward: no
masquerade: no
On a Server or Cloud install without firewalld, libvirt writes its own nftables tables (table ip libvirt_network and table ip6 libvirt_network), and guests still get outbound NAT. A test guest fetched https://fedoraproject.org/ with HTTP 200. To publish guest services on the host’s network, the firewalld guide for Fedora covers zones and forwarding.
7. Create a VM with virt-install and cloud-init
A Fedora Cloud image boots in seconds and needs no installer. Find the newest stable release and its image on the Fedora mirror, so the commands keep working when the next release lands:
MIRROR=https://dl.fedoraproject.org/pub/fedora/linux/releases
REL=$(curl -s $MIRROR/ | grep -oE 'href="[0-9]+/"' | grep -oE '[0-9]+' | sort -n | tail -1)
IMG=$(curl -s $MIRROR/$REL/Cloud/x86_64/images/ | grep -oE 'Fedora-Cloud-Base-Generic-[^"]+\.qcow2' | head -1)
echo $REL $IMG
Before Fedora 45’s final release the newest stable tree is still 44:
44 Fedora-Cloud-Base-Generic-44-1.7.x86_64.qcow2
Download it once as a base image:
sudo curl -fL -o /var/lib/libvirt/images/fedora-cloud-base.qcow2 $MIRROR/$REL/Cloud/x86_64/images/$IMG
sudo qemu-img info /var/lib/libvirt/images/fedora-cloud-base.qcow2 | head -5
The image is a 557 MiB qcow2 with a 5 GiB virtual disk:
image: /var/lib/libvirt/images/fedora-cloud-base.qcow2
file format: qcow2
virtual size: 5 GiB (5368709120 bytes)
disk size: 557 MiB
cluster_size: 65536
Create a guest on top of it. backing_store gives the VM its own 10 GiB overlay disk and leaves the base image untouched, so you can create more guests from the same download. --cloud-init clouduser-ssh-key puts your public key into the image’s default fedora user. Without it, a cloud image boots to a login prompt you cannot get past. Create a key first with ssh-keygen -t ed25519 if ~/.ssh/id_ed25519.pub does not exist yet:
virt-install \
--name web01 \
--memory 2048 \
--vcpus 2 \
--disk size=10,backing_store=/var/lib/libvirt/images/fedora-cloud-base.qcow2 \
--import \
--osinfo fedora-unknown \
--network network=default \
--cloud-init clouduser-ssh-key=$HOME/.ssh/id_ed25519.pub \
--graphics none \
--noautoconsole
virt-install builds a small cloud-init ISO, allocates the overlay and starts the domain:
Starting install...
Allocating 'virtinst-xk87l3_y-cloudinit.iso' | 368 kB 00:00
Transferring 'virtinst-xk87l3_y-cloudinit.iso' | 368 kB 00:00
Allocating 'web01.qcow2' | 10 GB 00:00
Creating domain... | 00:00
Domain is still running. Installation may be in progress.
You can reconnect to the console to complete the installation process.
The “Installation may be in progress” line is generic. With --import there is no installer, and the guest boots straight from the disk. The --osinfo fedora-unknown part matters: on both Fedora 45 and Fedora 44, the installed osinfo-db (20251212) knows Fedora only up to 43. Check yours:
virt-install --osinfo list | grep -E '^fedora(4[2-9]|-rawhide|-unknown)'
rpm -q osinfo-db
There is no fedora44 or fedora45 in the list on either release:
fedora43
fedora42
fedora-rawhide
fedora-unknown
osinfo-db-20251212-2.fc45.noarch
And the value older guides use fails outright:
ERROR Unknown OS name 'fedora44'. See `--osinfo list` for valid values.
rc=1
fedora-unknown is libosinfo’s generic Fedora entry with current defaults (q35, virtio disk and network). Upstream osinfo-db already has a Fedora 44 entry, but the Fedora 45 and 44 packages had not picked it up when I tested. Use fedora44 or fedora45 once virt-install --osinfo list shows it.
Connect to the guest
The guest gets its address from the default network’s DHCP:
virsh domifaddr web01
It had a lease when I checked, less than a minute after creation:
Name MAC address Protocol Address
------------------------------------------------------------
vnet0 52:54:00:3b:d0:7f ipv4 192.168.122.209/24
SSH in as fedora with the key you injected:
IP=$(virsh domifaddr web01 | awk '/ipv4/{sub("/.*","",$4); print $4}')
ssh fedora@$IP 'cat /etc/fedora-release; nproc; free -m | head -2; systemd-detect-virt'
Two vCPUs, 2 GiB of RAM, running on KVM:
Fedora release 44 (Forty Four)
2
total used free shared buff/cache available
Mem: 1955 316 1599 0 175 1638
kvm
The pool list now shows the default pool that virt-install created, holding the base image and the overlay:
virsh pool-list --all
virsh vol-list default
It also added a boot-scratch pool for its temporary cloud-init ISO:
Name State Autostart
------------------------------------
boot-scratch active yes
default active yes
Name Path
----------------------------------------------------------------------------
fedora-cloud-base.qcow2 /var/lib/libvirt/images/fedora-cloud-base.qcow2
web01.qcow2 /var/lib/libvirt/images/web01.qcow2
The serial console works too, because Fedora Cloud images log to ttyS0. Attach with virsh console web01, press Enter to get a login prompt, and detach with Ctrl+].

The capture shows the whole run: virt-install building the cloud-init ISO and the overlay disk, then an SSH login to the new guest reporting Fedora 44, 2 vCPUs and kvm as its hypervisor.
8. Create a VM in virt-manager
On Workstation, open Virtual Machine Manager from the app grid. It connects to QEMU/KVM, the system instance, so VMs you made with virt-install show up here. If your account is not in the libvirt group yet, GNOME asks for an administrator password first (your own if you are in wheel, as my lab user was), and the connection opens once you enter it:

With the group in place, as in step 5, there is no prompt.
I used the newest Fedora Everything netinstall ISO for this test, downloaded into /var/lib/libvirt/images with the same mirror detection as above (Everything/x86_64/iso/ and Fedora-Everything-netinst-). Click the Create a new virtual machine button and keep Local install media:

In step 2, type or browse to the ISO path. Auto-detection reads the media and, with the current osinfo-db, picks the generic Fedora entry for a Fedora 44 ISO, which is the same fedora-unknown profile used above:

Steps 3 and 4 offered 4096 MiB of RAM, 2 vCPUs and a 20 GiB qcow2 in the default pool. On the last page, name the VM and open Network selection to confirm it uses Virtual network 'default' : NAT:

Click Finish and the console window opens. GNOME then asks whether Virtual Machine Manager may inhibit shortcuts. Allow it if you want keys such as Super and Alt+Tab to go to the guest, and press Super+Escape when you need them back on the host. The installer booted in the nested guest:

Without the customize step, virt-manager gave this guest the q35 machine type, a virtio disk and NIC, SPICE graphics and virtio-vga, and BIOS firmware rather than UEFI. Tick Customize configuration before install on the last page if you want UEFI (Overview, Firmware) or a different disk bus. Once the console is closed, the main window lists the guest with its CPU graph:

After the URI change in step 5, virt-manager and virsh talk to the same system libvirt instance, so a guest created here shows up in virsh list and takes the commands in the next two sections.
9. Snapshots and the cloud-init ISO trap
qcow2 disks support internal snapshots, which store disk and memory state in the same file:
virsh snapshot-create-as web01 clean --description "fresh cloud image"
virsh snapshot-list web01
The snapshot is taken while the guest runs:
Domain snapshot clean created
Name Creation Time State
----------------------------------------------
clean 2026-10-05 08:17:55 +0000 running
Here is the trap. virt-install deletes its temporary cloud-init ISO from /var/lib/libvirt/boot once the guest has started, and empties the CD-ROM in the saved configuration. The running domain still has the ISO attached, though, and a snapshot taken while it runs records that path. I broke the guest on purpose (deleted /usr/bin/ls) and tried to roll back:
error: Failed to revert snapshot clean
error: Cannot access storage file '/var/lib/libvirt/boot/virtinst-xk87l3_y-cloudinit.iso': No such file or directory
The failed revert also left the guest shut off. Remove the stale CD-ROM source from the snapshot’s saved configuration, then revert again. snapshot-edit opens an editor, so you can hand it a sed command instead of an interactive one:
EDITOR="sed -i /cloudinit.iso/d" virsh snapshot-edit web01 clean
virsh snapshot-revert web01 clean
virsh domstate web01
The revert went through and the guest came back running at the snapshot point, with /usr/bin/ls restored and an uptime of zero minutes:
Snapshot clean edited.
Domain snapshot clean reverted
running
To avoid this altogether, eject the cloud-init media once the guest has booted and before you take the first snapshot:
virsh change-media web02 sda --eject --live
virsh domblklist web02
With the CD-ROM empty (sda -), the same break and revert worked first time on a second guest:
Successfully ejected media.
Target Source
-----------------------------------------------
vda /var/lib/libvirt/images/web02.qcow2
sda -
UEFI guests are not a problem for this either. A guest created with --boot uefi got Secure Boot OVMF with a qcow2 NVRAM file (OVMF_VARS_4M.secboot.qcow2), and an internal snapshot of it succeeded while it was running.

Read the capture top to bottom: the first revert fails on the missing ISO, snapshot-edit drops that line from the saved XML, and the second revert brings web01 back running with SSH working.
10. Everyday virsh commands
These are the commands I use most, all tested on the Fedora 45 host:
| Task | Command |
|---|---|
| List all guests | virsh list --all |
| Start, clean shutdown, hard stop | virsh start web01, virsh shutdown web01, virsh destroy web01 |
| Start with the host | virsh autostart web01 (--disable to undo) |
| Guest details | virsh dominfo web01 |
| Guest IP | virsh domifaddr web01 |
| Serial console | virsh console web01, detach with Ctrl+] |
| Snapshot and roll back | virsh snapshot-create-as web01 NAME, virsh snapshot-revert web01 NAME |
| Delete guest and its disks | virsh undefine web01 --remove-all-storage --snapshots-metadata (add --nvram for UEFI guests) |
Autostart and dominfo looked like this, and shutdown took the second guest down cleanly within 15 seconds:
Domain 'web01' marked as autostarted
Name: web01
State: running
CPU(s): 2
Max memory: 2097152 KiB
Autostart: enable
Autostart Once: disable
Domain 'web02' is being shutdown
Id Name State
------------------------
3 web01 running
- web02 shut off
undefine refuses to remove a guest that still has snapshots unless you add --snapshots-metadata. With it, the guest and its overlay disk went, and the shared base image stayed:
Domain 'web02' has been undefined
Volume 'vda'(/var/lib/libvirt/images/web02.qcow2) removed.
Id Name State
-----------------------
3 web01 running
Name Path
----------------------------------------------------------------------------
fedora-cloud-base.qcow2 /var/lib/libvirt/images/fedora-cloud-base.qcow2
web01.qcow2 /var/lib/libvirt/images/web01.qcow2
Only the web01 overlay and the base image are left in the default pool, which is the one virt-install created on first use.
Troubleshooting
Error: No URI is provided and cannot identify any listening daemon socket path
The libvirt sockets are enabled but not running, which is the normal state right after installing the group on Server or Cloud. Run sudo systemctl start sockets.target or reboot (step 3). Do not enable the old libvirtd.service alongside the modular daemons.
Error: authentication unavailable: no polkit agent available
Your user is not in the libvirt group and the shell has no polkit agent to ask for a password, which is the case over SSH. Add the group with sudo usermod -aG libvirt "$USER" and log in again. Locally in a GNOME session, virt-manager shows an administrator password prompt instead (step 8).
virsh list is empty but virt-manager shows VMs
Your virsh is on qemu:///session. Check with virsh uri, then set uri_default in ~/.config/libvirt/libvirt.conf (step 5) or use virsh -c qemu:///system.
ERROR Unknown OS name ‘fedora44’
osinfo-db on Fedora 45 and 44 has no entries past fedora43. Use --osinfo fedora-unknown, or check virt-install --osinfo list after an osinfo-db update.
error: Cannot access storage file ‘…cloudinit.iso’: No such file or directory
You are reverting a snapshot that still references virt-install’s deleted cloud-init ISO. Remove the line with EDITOR="sed -i /cloudinit.iso/d" virsh snapshot-edit VM SNAPSHOT, and eject the media before future snapshots (step 9).
KVM and VirtualBox on the same machine
Oracle has no Fedora 45 VirtualBox repository yet, and pointing its repo at an older Fedora tree fails on a library mismatch. The Fedora 45 third-party repo 404 fixes cover the RPM Fusion VirtualBox package if you need it. If you only want desktop VMs, KVM with virt-manager does the job on its own.
Where to go from here
For containers instead of full VMs on the same host, the Podman on Fedora 45 / 44 guide or Docker on Fedora run alongside libvirt without conflicts. For throwaway per-project distros, Distrobox and Toolbx are lighter still. On a fresh system, the Fedora 45 install guide and the post-install checklist come first. If you plan to run several guests at once, the homelab RAM sizing guide applies to a KVM host just as much as to Proxmox.
Excellent tutorial. Thanx!
Excellency comes from reading further.
You did not stomp over “machines.target” in your Fedora `systemctl` for what reason?
Try “sudo systemctrl enable machines.target && sudo systemctrl start machines.target”
libvirt doesn’t use
machines.target. It ships in systemd-container and only groupssystemd-nspawn@andsystemd-vmspawn@units (the only units that reference it on Fedora 44), and Fedora’s90-systemd.presetalready enables it. KVM guests start with the host throughvirsh autostart web01, which is in the virsh table near the end of the guide. The command is alsosystemctl, not systemctrl.