Skip to content
/ KVM Public

A comprehensive guide to solving VM storage limitations by leveraging external drives with QEMU/KVM and Virt-Manager on Fedora

Notifications You must be signed in to change notification settings

Gr3ytrac3/KVM

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

28 Commits
 
 
 
 

Repository files navigation

External Drive VM Storage Setup for QEMU/KVM

IMAGE: HEARDER

A comprehensive guide to solving VM storage limitations by leveraging external drives with QEMU/KVM and Virt-Manager on Fedora

QEMU KVM Virt-Manager Fedora

🚀 Quick Start

Problem: Limited internal storage preventing multiple VM deployments Solution: Dedicated external drive partition for VM storage with proper libvirt integration

# Quick verification of your setup
lsblk                          # Check drive layout
virsh pool-list --all          # Verify storage pools
df -h                          # report file system space usage

📋 Prerequisites

  • Fedora Linux (tested on 42+) or any other Linux Distribution
  • External drive with sufficient space (100GB+ recommended)
  • CPU with virtualization support (Intel VT-x or AMD-V)
  • Administrative privileges

🎯 What This Guide Covers

  • QEMU/KVM installation and configuration
  • External drive partitioning without data loss
  • Libvirt storage pool setup
  • VM creation using external storage
  • Performance optimization tips
  • Common troubleshooting scenarios

📖 Table of Contents

  1. Problem
  2. System Requirements
  3. Installation & Setup
  4. External Drive Configuration
  5. Libvirt Storage Pool
  6. VM Creation Process
  7. Testing & Verification
  8. Troubleshooting
  9. Best Practices
  10. Contributing

🎯 Problem

The Challenge

  • Limited Internal Storage: System's internal drive insufficient for multiple VMs
  • Space Consumption: ISO files alone consuming significant space
  • Resource Availability: CPU capable of handling VMs, storage is the bottleneck
  • Future Scalability: Need for expandable VM storage solution

The Solution Concept

  • Utilize existing external drive for VM storage
  • Create dedicated partition for VM-related files
  • Maintain separation between personal data and VM storage
  • Leverage external drive's larger capacity

🔧 System Requirements

Hardware Requirements

  • CPU: Intel VT-x or AMD-V virtualization support
  • RAM: 8GB+ (4GB for host + VM allocations)
  • Storage: External drive with 100GB+ available space
  • USB: USB 3.0+ port for optimal performance

Software Requirements

  • OS: Fedora Linux 39+ (adaptable to other RPM-based distros) or other Distros
  • Packages: QEMU/KVM, libvirt, virt-manager
  • Permissions: User account with sudo access

Verification Commands

# Check virtualization support
lscpu | grep Virtualization

# To check if virtualization is enabled in the BIOS/UEFI on a Linux system (such as Fedora).
egrep -c '(vmx|svm)' /proc/cpuinfo
# If zero (0) is returned then you'll have to turn off your pc and log into the BIOS/UEFI to enable it.

# Verify that the KVM kernel modules are loaded by running:
lsmod | grep kvm

# KVM requires a CPU with virtualization extensions, found on most consumer CPUs. These extensions are called Intel VT or AMD-V. To check whether you have CPU support, run the following command:
grep -E '^flags.*(vmx|svm)' /proc/cpuinfo
# If this command results in nothing printed, your system does not support the relevant virtualization extensions. You can still use QEMU/KVM, but the emulator will fall back to software virtualization, which is much slower.

# Verify available space
df -h

# Check USB port speed
lsusb -t


# If the checks were positive then you're good to go.

🚀 Installation & Setup

Install Virtualization Stack

# Install complete virtualization group
sudo dnf install @virtualization

# Alternative: Install individual components
sudo dnf install qemu-kvm libvirt virt-manager virt-viewer virt-install

Configure Services

# Enable and start libvirt daemon
sudo systemctl enable --now libvirtd

# Add user to libvirt group
sudo usermod -aG libvirt $USER

# Verify installation
systemctl status libvirtd
virsh version

⚠️ Important: Log out and back in after adding user to libvirt group


💾 External Drive Configuration

1. Identify Your External Drive

# List all storage devices
lsblk

# Detailed partition information
sudo fdisk -l

Expected output example (yours won't show up another partition if you have none):

NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
sda           8:0    0 465.8G  0 disk 
├─sda1        8:1    0    16M  0 part 
├─sda2        8:2    0 186.3G  0 part /run/media/gr3ytrac3/500 GB
└─sda3        8:3    0 279.5G  0 part /mnt/vm_storage
zram0       251:0    0     8G  0 disk [SWAP]
nvme0n1     259:0    0 238.5G  0 disk 
├─nvme0n1p1 259:1    0   600M  0 part /boot/efi
├─nvme0n1p2 259:2    0     1G  0 part /boot
└─nvme0n1p3 259:3    0 236.9G  0 part /home
                                      /

sda2 is the default path of your external drive, automounted by defautlt without a proper mounting point. We'll create and properly mount sda3, which will be dedicated for the vm storage.

2. Backup Critical Data

🚨 CRITICAL: Backup all important data before proceeding with partitioning. Although not really necessary if sure of you, but preventive against the shrinking process

3. Partition Management

Using GParted (Recommended for beginners)

IMAGE: HEARDER

# Install GParted
sudo dnf install gparted

# Launch with administrative privileges  
sudo gparted

Steps in GParted:

  1. Select your external drive (top right corner as in the image below) (e.g., /dev/sda) IMAGE: HEARDER

  2. Right-click existing partition → "Resize/Move" 🚨 This is an important stage. You'll have to decide on the size of space you want to shrink and dedicate to the other partition. Please take note of the used space on your disk before entering the space you wish to shrink. If the sapce isn't enough for you then transfer or detele some unwanted data from it. Get back to GParted once you're done. If this stage is skipped, you might end up loosing important data. If you're done, then you can proceed.

IMAGE: HEARDER

VM Storage Space Calculation

Learn to calculate and convert storage units for VM partitioning

Quick Start

Need to quickly convert storage units for VM planning? Jump to the Quick Reference Table or use our Storage Calculator.

Table

  1. Understanding Storage Units
  2. Conversion Formulas
  3. Quick Reference Table
  4. VM Size Planning
  5. Storage Calculator
  6. Practical Examples

🔢 Understanding Storage Units

The Two Systems

When working with VM storage, you'll encounter two different measurement systems:

Decimal (SI Units) Binary (IEC Units)
Used by drive manufacturers Used by operating systems
Base-10 (powers of 1000) Base-2 (powers of 1024)
KB, MB, GB, TB KiB, MiB, GiB, TiB

Unit Definitions

Unit Value (Bytes) Type Common Usage
1 KB (Kilobyte) 1,000 Decimal Drive specifications
1 KiB (Kibibyte) 1,024 Binary OS reporting
1 MB (Megabyte) 1,000,000 Decimal File sizes
1 MiB (Mebibyte) 1,048,576 (1024²) Binary RAM allocation
1 GB (Gigabyte) 1,000,000,000 Decimal Drive capacity
1 GiB (Gibibyte) 1,073,741,824 (1024³) Binary Actual usable space

💡 Key Insight: Linux and virtualization tools (QEMU, virt-manager) typically use binary units (MiB, GiB)


🔄 Conversion Formulas

GB (Decimal) → MiB (Binary)

MiB = (GB × 1,000,000,000) ÷ 1,048,576

Example: Convert 20 GB to MiB

(20 × 1,000,000,000) ÷ 1,048,576 ≈ 19,073 MiB

MiB (Binary) → GB (Decimal)

GB = (MiB × 1,048,576) ÷ 1,000,000,000

Example: Convert 4096 MiB to GB

(4096 × 1,048,576) ÷ 1,000,000,000 ≈ 4.3 GB

Quick Approximation

For rough calculations, you can use these approximation factors:

Conversion Factor
GB to MiB Multiply by ~953.7
MiB to GB Divide by ~1024, then multiply by 1.0737
MiB to GiB Divide by 1024

📊 Quick Reference Table

Decimal (GB) Binary Equivalent (GiB) Binary Equivalent (MiB)
5 GB ≈ 4.66 GiB ≈ 4,768 MiB
10 GB ≈ 9.31 GiB ≈ 9,537 MiB
20 GB ≈ 18.63 GiB ≈ 19,073 MiB
50 GB ≈ 46.57 GiB ≈ 47,684 MiB
100 GB ≈ 93.13 GiB ≈ 95,367 MiB
200 GB ≈ 186.26 GiB ≈ 190,735 MiB
500 GB ≈ 465.66 GiB ≈ 476,837 MiB
1000 GB (1TB) ≈ 931.32 GiB ≈ 953,674 MiB

🖥️ VM Size Planning

Typical VM Storage Requirements

VM Type Minimum Recommended With Development Tools
Alpine Linux 2 GiB 4 GiB 8 GiB
Ubuntu Server 8 GiB 15 GiB 25 GiB
Ubuntu Desktop 15 GiB 25 GiB 40 GiB
Fedora Workstation 20 GiB 30 GiB 50 GiB
Windows 10 32 GiB 50 GiB 80 GiB
Windows 11 40 GiB 60 GiB 100 GiB
Kali Linux 15 GiB 25 GiB 40 GiB
CentOS/RHEL 10 GiB 20 GiB 35 GiB

Additional Space Considerations

Component Typical Size Notes
ISO Files 1-6 GB each Store in dedicated folder
VM Snapshots 10-50% of VM size Per snapshot
Swap Space Equal to VM RAM If enabled in guest
Log Files 1-5 GiB Over time
Growth Buffer 20-30% extra For updates and data

🧮 Storage Calculator

Planning Example: Multi-VM Setup

Scenario: Setting up a development environment with multiple VMs

Planned VMs:
├── Ubuntu Server (Web Dev)    : 20 GiB
├── Windows 11 (Testing)       : 60 GiB
├── Kali Linux (Security)      : 25 GiB
├── CentOS (Production Test)   : 20 GiB
└── Alpine (Container Test)    : 5 GiB

Additional Storage:
├── ISO Files                  : 15 GiB
├── VM Snapshots (estimated)   : 30 GiB
├── Templates                  : 10 GiB
└── Growth Buffer (25%)        : 41 GiB

Total Required: 226 GiB ≈ 243 GB

Calculation Steps

  1. Sum VM requirements: 130 GiB
  2. Add additional storage: 55 GiB
  3. Calculate subtotal: 185 GiB
  4. Add growth buffer (25%): 41 GiB
  5. Total needed: 226 GiB
  6. Convert to decimal: ~243 GB

Recommended Partition Size

For the above scenario, create a 250-300 GB partition to ensure adequate space.


💡 Practical Examples

Example 1: Converting Manufacturer Specs

Problem: You have a 500 GB external drive. How much usable space for VMs?

Solution:

500 GB × 0.9313 = 465.66 GiB usable space

Planning: You can comfortably fit 8-10 moderate-sized VMs.

Example 2: VM Disk Creation

Problem: Creating a VM with virt-manager showing "20 GB" option.

Reality:

20 GB = 18.63 GiB actual usable space in guest OS

Best Practice: Plan for slightly larger sizes than guest OS requirements.

Example 3: Existing Drive Partitioning

Problem: 1TB external drive, want to keep 400 GB for personal data.

Available for VMs:

600 GB available = 558.79 GiB for VM storage

Can Support:

  • 15-20 lightweight VMs, or
  • 8-12 full desktop VMs, or
  • 4-6 Windows VMs with development tools

⚠️ Common Pitfalls

1. Unit Confusion

# ❌ Wrong assumption
"My 1TB drive should give me 1024 GB of VM space"

# ✅ Reality  
"My 1TB drive gives me ~931 GiB of actual VM storage"

2. Insufficient Growth Planning

# ❌ Tight planning
VM Size: Exactly what guest OS needs

# ✅ Smart planning
VM Size: Guest OS needs + 30% buffer for updates/data

3. Forgetting Overhead

# ❌ Missing components
Total = Sum of VM disk sizes

# ✅ Complete calculation
Total = VM disks + ISOs + snapshots + templates + buffer

4. Sparse vs. Allocated Confusion

# qcow2 sparse allocation (default)
qemu-img create -f qcow2 disk.qcow2 20G
# Creates 20G capacity but uses minimal actual space initially

# Pre-allocated (uses full space immediately)  
qemu-img create -f qcow2 -o preallocation=full disk.qcow2 20G

🎯 Best Practices

✅ Smart Planning

  1. Always add 20-30% buffer for growth and snapshots
  2. Use sparse allocation (qcow2 default) to save initial space
  3. Monitor usage regularly to prevent space exhaustion
  4. Plan for snapshots - they can be 10-50% of VM size each

✅ Organization

/mnt/vm_storage/
├── images/          # VM disk files
├── isos/            # Installation media  
├── templates/       # Base VM templates
├── snapshots/       # VM snapshots
└── backups/         # VM backups

📚 Additional Resources


  1. Drag boundary to create unallocated space after entering the space you want to shrink and attribute to the new partition. "Before you proceed:" You need to confirm and complete the shrinking process. For that, click on the "operation pending" zone at the bottom left corner of GParted after you're done. You should see the following display. Wait until it's done IMAGE: HEARDER

  2. Right-click unallocated space → "New"

  3. Configure new partition:

    • Label: vm_storage
    • File System: ext4
    • Size: Remaining space
  4. Apply all operations (same zone at the bottom eft corner). Once the process is done, sure to mount it (Part 4)

IMAGE: HEARDER

Using CLI (Advanced users)

# Launch fdisk
sudo fdisk /dev/sda

# Create new partition (follow interactive prompts)
# n (new) -> p (primary) -> partition number -> first sector -> last sector
# w (write changes)

# Format new partition
sudo mkfs.ext4 -L vm_storage /dev/sda3

4. Configure Persistent Mounting

# Create mount point
sudo mkdir -p /mnt/vm_storage

# Get partition UUID
sudo blkid /dev/sda3

# Add to fstab for automatic mounting
echo "UUID=$(sudo blkid -s UUID -o value /dev/sda3) /mnt/vm_storage ext4 defaults 0 2" | sudo tee -a /etc/fstab

# Mount the partition
sudo mount -a

# Verify mount
df -h /mnt/vm_storage

5. Set Proper Permissions

IMAGE: HEARDER

# Change ownership to current user
sudo chown $USER:$USER /mnt/vm_storage

# Create directory structure
mkdir -p /mnt/vm_storage/{isos,images,templates}

# Verify setup
ls -la /mnt/vm_storage/

You can equally do the same from disk panel in linux


🗄️ Libvirt Storage Pool

Method 1: Using Virt-Manager (GUI)

  1. Launch virt-manager

    virt-manager
  2. Open Connection Details

    • Edit → Connection Details
    • Navigate to Storage tab
  3. Create New Storage Pool

    • Click "+" (Add Pool)
    • Name: vm_storage (your new partion name)
    • Type: dir: Filesystem Directory
    • Target Path: /mnt/vm_storage
    • Click Finish
  4. Start and Auto-start Pool

    • Select vm_storage pool
    • Click Start Pool
    • Check Autostart checkbox

Method 2: Using CLI

# Define storage pool
virsh pool-define-as vm_storage dir --target /mnt/vm_storage

# Start the pool
virsh pool-start vm_storage

# Set autostart
virsh pool-autostart vm_storage

# Verify pool creation
virsh pool-list --all
virsh pool-info vm_storage

Expected output:

Name:           vm_storage
UUID:           [uuid-string]
State:          running
Persistent:     yes
Autostart:      yes
Capacity:       279.40 GiB
Allocation:     1.20 GiB
Available:      278.20 GiB

🖥️ VM Creation Process

1. Download ISO Files

You can create a folder in your new patition to store your .iso files. Do this only if you gave enough space to your partition ( not less than 250GB) IMAGE: HEARDER

# Navigate to ISO directory
cd /mnt/vm_storage/isos

# Example downloads
wget https://releases.ubuntu.com/22.04/ubuntu-22.04.3-live-server-amd64.iso
wget https://download.fedoraproject.org/pub/fedora/linux/releases/39/Server/x86_64/iso/Fedora-Server-netinst-x86_64-39-1.5.iso

2. Create VM Using Virt-Manager

IMAGE: HEARDER

  1. Launch virt-manager and create new VM

    virt-manager
  2. VM Creation Wizard

    • Step 1: "Local install media (ISO image or CDROM)"
    • Step 2: Browse → /mnt/vm_storage/isos/ → Select ISO
    • Step 3: Memory and CPU allocation
    • Step 4: Critical - Storage configuration
  3. Storage Configuration Never change the default name given by virt-manager IMAGE: HEARDER

    • ✅ Check "Enable storage for this virtual machine"
    • Click "Manage..."
    • Select vm_storage pool
    • Click "+" to create new volume
    • Name: vm-name.qcow2
    • Format: qcow2
    • Max Capacity: As needed (e.g., 20GB)
    • Allocation: 0 (sparse allocation)
  4. Complete VM Setup

    • Step 5: Review and customize hardware
    • Click "Begin Installation" (top right)

3. Alternative CLI Method (not recommended but still an option)

# Create VM using virt-install
virt-install \
    --name ubuntu-server \
    --ram 2048 \
    --vcpus 2 \
    --disk path=/mnt/vm_storage/images/ubuntu-server.qcow2,size=20,format=qcow2 \
    --cdrom /mnt/vm_storage/isos/ubuntu-22.04.3-live-server-amd64.iso \
    --network network=default \
    --graphics spice \
    --os-variant ubuntu22.04

3.1 Sharing Partition with Vms

By default Virt-Manager allows you to share any external peripheral with your VMs. But that prompts your device to display on the VM, not on the host. The best way is to set it as a storage hardware. The below image shows you how to add your patition as a storage hardware. When you run the Vm it will display.

Note: Avoid allowing every VMs to write anything to the partition. It can corrupt its content in other Vms where you added it too. The best approach is to set it as read-only. With that set, you can copy files, docs into your VMs but not modify it, to avoid inconsistency from the main VM that has access to it. IMAGE: HEARDER

Make sure you entered the correct partition mounting point IMAGE: HEARDER

You can eddit the XML display in case of permission issues IMAGE: HEARDER

Enter your user password in order to access the added partition IMAGE: HEARDER

Enter your user password in order to access the added partition

🧪 Testing & Verification

Storage Verification

# Check storage pool status
virsh pool-info vm_storage

# List all volumes in pool
virsh vol-list vm_storage

# Check disk usage on external drive
df -h /mnt/vm_storage
du -sh /mnt/vm_storage/*

VM Operation Tests

# List running VMs
virsh list

# Check VM disk usage
ls -lah /mnt/vm_storage/images/

# Monitor VM performance
virsh dominfo vm-name

Performance Monitoring

# Monitor disk I/O during VM operation
iostat -x 1

# Check external drive performance
hdparm -t /dev/sda3

# Monitor VM resource usage
virt-top

🔧 Troubleshooting

Common Issues and Solutions

🚨 Storage Pool Not Detected

# Restart libvirt service
sudo systemctl restart libvirtd

# Redefine storage pool
virsh pool-define-as vm_storage dir --target /mnt/vm_storage
virsh pool-start vm_storage
virsh pool-autostart vm_storage

🚨 Permission Issues

# Fix ownership and permissions (set 755 or 777)
sudo chown -R $USER:libvirt /mnt/vm_storage
sudo chmod -R 755 /mnt/vm_storage

# Check SELinux context (if enabled)
sudo restorecon -R /mnt/vm_storage

# Check Groups. kvm, libvirt and quemu should be listed among other groups
groups

🚨 External Drive Not Mounting

# Check fstab entry
grep vm_storage /etc/fstab

# Manual mount
sudo mount UUID=$(sudo blkid -s UUID -o value /dev/sda3) /mnt/vm_storage

# Check filesystem for errors
sudo fsck /dev/sda3

# Mount it from GParter

🚨 VM Won't Start

# Check VM configuration
virsh dumpxml vm-name

# Verify storage path exists
ls -la /mnt/vm_storage/images/

# Check libvirt logs
sudo journalctl -u libvirtd -f

🚨 Poor VM Performance

# Enable virtio drivers in VM hardware settings
virsh edit vm-name

# Check if external drive is USB 3.0+
lsusb -t

# Monitor I/O performance
iotop -o

📋 Best Practices

🗄️ Storage Management

  • Regular backups of critical VM images
  • Monitor external drive health with smartctl
  • Use sparse allocation for VM disks to save space
  • Plan storage expansion before reaching capacity limits
# Create VM backup
virsh vol-download --pool vm_storage vm-name.qcow2 /backup/location/

# Check drive health
sudo smartctl -a /dev/sda

⚡ Performance Optimization

  • Use fastest available port (USB 3.0+ or Thunderbolt)
  • Enable virtio drivers for all VM components
  • Allocate memory wisely - don't over-commit
  • Consider SSD external drives for better I/O performance
# Optimize VM for performance
virsh edit vm-name
# Change to virtio:
# <disk type='file' device='disk'>
#   <driver name='qemu' type='qcow2' cache='none' io='native'/>
#   <target dev='vda' bus='virtio'/>

🔒 Security Considerations

  • Encrypt external drive if storing sensitive VMs
  • Regular security updates for host and guest systems
  • Network isolation for untrusted VMs
  • Backup encryption keys separately

📊 Monitoring and Maintenance

# Weekly maintenance script
#!/bin/bash
echo "=== VM Storage Health Check ==="
df -h /mnt/vm_storage
virsh pool-info vm_storage
sudo smartctl --health /dev/sda

echo "=== Running VMs ==="
virsh list --all

echo "=== Storage Pool Contents ==="
virsh vol-list vm_storage

Successfully Installed VMs

Debian13: IMAGE: HEARDER

Kali: IMAGE: HEARDER

Partition Structure with each VMs.qcow2 file: IMAGE: HEARDER

End Result in Virt-Manager: IMAGE: HEARDER


🎉 Results and Benefits

This setup successfully addresses storage limitations by:

Leveraging existing hardware - no need for expensive internal storage upgrades
Organized separation - clean distinction between personal and VM data
Scalable solution - easy to add more VMs or storage
Cost-effective - utilize external storage you likely already own
Maintainable - standard libvirt tools work seamlessly

Success Metrics

  • Storage efficiency: 50-80% reduction in internal drive usage
  • VM capacity: Support for 5-10+ VMs depending on external drive size
  • Performance: Acceptable I/O performance with USB 3.0+ drives
  • Flexibility: Easy VM management with standard tools

🤝 Contributing

Contributions are welcome! Please feel free to:

  • Submit issues for problems or questions
  • Create pull requests for improvements
  • Share your experience with different hardware/configurations
  • Add support for other Linux distributions

How to Contribute

  1. Fork this repository
  2. Create a feature branch (git checkout -b feature/improvement)
  3. Commit your changes (git commit -am 'Add some improvement')
  4. Push to the branch (git push origin feature/improvement)
  5. Create a Pull Request

📚 Additional Resources


🙋‍♂️ Questions or Issues?

If you encounter any problems or have questions:

  1. Check the Troubleshooting section
  2. Search existing Issues
  3. Create a new issue with:
    • Your system specs (Fedora version or other Linux Distro, hardware)
    • Complete error messages
    • Steps you've already tried

⭐ If this guide helped you, consider giving it a star!

About

A comprehensive guide to solving VM storage limitations by leveraging external drives with QEMU/KVM and Virt-Manager on Fedora

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published