NFS (Network Filesystem) is the go-to shared storage option for KVM environments where you need multiple hypervisors accessing the same VM images. It is the simplest way to enable live migration between KVM hosts, share ISO libraries, and centralize VM storage without investing in SAN infrastructure. This guide covers setting up an NFS server, exporting a directory, configuring the NFS pool in libvirt, creating volumes, and using NFS as shared storage for live migration.
Why NFS for KVM Storage
NFS has been a reliable choice for shared storage in virtualization for decades. For KVM specifically, it offers several advantages:
- Simple to deploy – no special hardware or complex protocols required
- Enables live migration of VMs between KVM hosts without downtime
- Centralizes VM disk images for easier backup and management
- Works over standard Ethernet networking
- Supported natively by libvirt as a storage pool type
Prerequisites
- An NFS server (can be a dedicated storage server or another Linux machine)
- One or more KVM hosts running RHEL 10 or Ubuntu 24.04
- All servers on the same network with reliable connectivity
- Root or sudo access on all machines
- Firewall configured to allow NFS traffic (ports 2049, 111)
Step 1 – Set Up the NFS Server
Install the NFS server packages on the machine that will host the shared storage.
Ubuntu 24.04
sudo apt update
sudo apt install -y nfs-kernel-server
RHEL 10
sudo dnf install -y nfs-utils
sudo systemctl enable --now nfs-server
Verify the NFS server is running.
systemctl status nfs-server
Step 2 – Create and Export the Shared Directory
Create a directory that will hold VM disk images and ISO files.
sudo mkdir -p /srv/nfs/kvm
sudo chown nobody:nogroup /srv/nfs/kvm
sudo chmod 755 /srv/nfs/kvm
On RHEL-based systems, use nobody:nobody instead of nobody:nogroup.
sudo chown nobody:nobody /srv/nfs/kvm
Add the export to /etc/exports. This example exports the directory to an entire subnet with read-write access. Adjust the network range to match your environment.
echo "/srv/nfs/kvm 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports
Key export options explained:
rw– Read and write accesssync– Write data to disk before acknowledging – safer against corruptionno_subtree_check– Disables subtree checking for better performanceno_root_squash– Allows root on the client to act as root on the NFS share, which libvirt needs to manage VM files
Apply the export configuration.
sudo exportfs -rav
Verify the exports.
sudo exportfs -v
Step 3 – Configure the Firewall on the NFS Server
Open the necessary ports for NFS.
RHEL 10 with firewalld
sudo firewall-cmd --permanent --add-service=nfs
sudo firewall-cmd --permanent --add-service=rpc-bind
sudo firewall-cmd --permanent --add-service=mountd
sudo firewall-cmd --reload
Ubuntu 24.04 with ufw
sudo ufw allow from 192.168.1.0/24 to any port nfs
sudo ufw allow from 192.168.1.0/24 to any port 111
Step 4 – Mount the NFS Share on the KVM Host
On each KVM host, install the NFS client utilities.
# Ubuntu
sudo apt install -y nfs-common
# RHEL
sudo dnf install -y nfs-utils
Test the mount manually first. Replace 192.168.1.50 with your NFS server IP.
sudo mkdir -p /mnt/nfs-kvm
sudo mount -t nfs 192.168.1.50:/srv/nfs/kvm /mnt/nfs-kvm
Verify the mount.
df -hT /mnt/nfs-kvm
mount | grep nfs
Unmount it after testing – libvirt will handle the mounting when you define the pool.
sudo umount /mnt/nfs-kvm
Step 5 – Define the NFS Storage Pool in libvirt
Define an NFS-type storage pool in libvirt. This tells libvirt to mount the NFS share automatically.
virsh pool-define-as nfs-pool netfs \
--source-host 192.168.1.50 \
--source-path /srv/nfs/kvm \
--target /var/lib/libvirt/images/nfs-pool
Start the pool and set it to auto-start.
virsh pool-start nfs-pool
virsh pool-autostart nfs-pool
Verify the pool.
virsh pool-list --all
virsh pool-info nfs-pool
Confirm the mount is active.
df -hT /var/lib/libvirt/images/nfs-pool
Step 6 – Create Volumes on the NFS Pool
Create VM disk images in the NFS-backed pool.
virsh vol-create-as nfs-pool webserver.qcow2 20G --format qcow2
virsh vol-create-as nfs-pool dbserver.qcow2 50G --format qcow2
List volumes in the pool.
virsh vol-list nfs-pool
Check a specific volume.
virsh vol-info webserver.qcow2 --pool nfs-pool
Step 7 – Create a VM Using NFS Storage
virt-install \
--name webserver \
--ram 4096 \
--vcpus 2 \
--disk vol=nfs-pool/webserver.qcow2,bus=virtio \
--os-variant ubuntu24.04 \
--network bridge=br0 \
--cdrom /var/lib/libvirt/images/nfs-pool/ubuntu-24.04.iso
Step 8 – Live Migration with Shared NFS Storage
The primary reason to use NFS for KVM storage is enabling live migration. When both KVM hosts mount the same NFS share, VMs can move between hosts without any disk copying because both hosts access the same files.
Set up the same NFS pool on the second KVM host by repeating Steps 4 and 5 on that host. Both hosts must have the pool defined with the same source path.
Make sure both hosts can SSH to each other without a password (or configure libvirt to use TLS).
ssh-copy-id root@kvm-host2
Perform the live migration from the source host.
virsh migrate --live --persistent --undefinesource \
webserver qemu+ssh://kvm-host2/system
Verify the VM is running on the destination host.
ssh kvm-host2 "virsh list --all"
The migration happens in-memory since the disk files do not need to be transferred – both hosts already see them on the NFS share. This makes migration fast, typically completing in seconds for VMs with moderate memory usage.
NFS Performance Tuning for KVM
For production KVM environments using NFS, consider these optimizations.
Use NFSv4.2 for better performance and features.
# On the client, specify the NFS version in mount options
# Edit /etc/fstab if mounting manually:
192.168.1.50:/srv/nfs/kvm /var/lib/libvirt/images/nfs-pool nfs4 rw,hard,intr,rsize=1048576,wsize=1048576 0 0
Increase the NFS read and write buffer sizes to 1MB for better throughput with large sequential I/O.
Use a dedicated network interface or VLAN for NFS traffic to avoid competition with VM traffic and management traffic.
Use the hard mount option so NFS operations are retried indefinitely on network issues, rather than returning errors to the VM.
Summary
NFS provides a straightforward path to shared storage for KVM environments. The setup is simple – export a directory from the NFS server, define an NFS pool on each KVM host, and create VM volumes in that pool. The real payoff comes with live migration, where VMs move between hosts seamlessly because both access the same disk images over NFS. For small to mid-size deployments where a full SAN is overkill, NFS delivers the shared storage capabilities you need with minimal complexity. Pair it with a dedicated storage network and proper NFS tuning, and it performs well enough for most production KVM workloads.