Manage and Configure Virtual Machines in Linux
Series: Learning Linux Basics — Virtualization | Topic: Manage and Configure Virtual Machines
Introduction: What Are Virtual Machines and Why Do They Matter?
Imagine you have a powerful physical server sitting in a data centre — 64 CPU cores and 1,024 GB of RAM. If you hand that entire machine to one customer, you're dramatically underutilising it and charging a lot for something most workloads don't fully use. But what if you could carve it into 32 smaller, independent computers — each with 2 virtual CPUs and 32 GB of RAM — and rent each one to a different customer?
That's exactly what cloud providers like Amazon Web Services, Google Cloud, and DigitalOcean do. What their customers receive as a "cloud server" is almost always a virtual machine — a fully isolated, software-simulated computer running on shared physical hardware.
This isn't just useful for cloud providers. Virtual machines are valuable anywhere you need to:
Run multiple isolated environments on one physical server
Test software in a clean, disposable environment
Simulate different operating systems on the same hardware
Consolidate workloads to reduce hardware costs
Create reproducible server configurations for development and testing
In this lesson, we'll learn how Linux creates and manages virtual machines, and how to control them entirely from the command line using a powerful tool called virsh.
Understanding QEMU-KVM: The Engine Behind Linux Virtualisation
In Linux, the dominant virtualisation stack is QEMU-KVM. This is actually two pieces of software that work together:
QEMU (Quick Emulator)
QEMU is a software emulator that simulates the hardware components of a computer — CPU, memory, disk controllers, network cards, and more. It creates the virtual computer that your guest operating system believes it's running on.
Think of QEMU as a very sophisticated piece of software that pretends to be a physical machine. The guest OS (the one running inside the VM) has no idea it's talking to a simulation rather than real hardware.
KVM (Kernel-based Virtual Machine)
KVM is code built directly into the Linux kernel that leverages hardware virtualisation extensions available in modern CPUs (Intel VT-x and AMD-V). These CPU features allow virtual machines to run with near-native performance by executing many guest instructions directly on the real CPU rather than emulating them in software.
Without KVM, virtualisation is entirely done in software by QEMU — accurate but slow. With KVM, the Linux kernel acts as a hypervisor and the CPU does much of the heavy lifting, making virtual machines much faster and more efficient.
Physical Hardware (CPU, RAM, Disk)
↑
Linux Kernel + KVM
↑
QEMU (emulates virtual hardware)
↑
Virtual Machine (guest OS)
Together, QEMU and KVM give you a complete, performant virtualisation solution that is the foundation for most Linux-based virtualisation in production environments today.
Meet virsh: The Command-Line VM Manager
If you've used VirtualBox, you know the experience: click to create a VM, click to configure it, click to start it. It's intuitive but requires a graphical interface.
virsh (pronounced "ver-sh") does everything VirtualBox's GUI does, but through commands in a terminal. This is essential for server environments that have no graphical interface — which is most production Linux servers.
virsh is part of the libvirt ecosystem — a collection of tools and APIs that provide a unified interface for managing different virtualisation technologies. Whether you're using QEMU-KVM, Xen, or other hypervisors, libvirt (and virsh) can often manage them through the same commands.
Getting virsh Installed
The easiest way to install virsh and all its supporting utilities on Ubuntu is:
sudo apt install virt-manager
Wait — why install virt-manager (a graphical tool) just to use virsh (a command-line tool) on a server without a GUI?
Because virt-manager pulls in a comprehensive set of dependency packages —
libvirt
QEMU
KVM drivers
all the command-line utilities needed for VM management.
On a server without a GUI, you will not use the virt-manager application itself, but installing it is still the fastest way to pull in all the required dependencies with a single command.
Getting Familiar with virsh Help
virsh has an excellent built-in help system:
virsh help
The output is extensive but well-organised. Commands are grouped by category. The most important category for this lesson is Domain Management. In virsh terminology, a domain and a virtual machine are the same thing — the terms are interchangeable.
To get detailed help for any specific command:
virsh help <command>
# Example:
virsh help undefine
virsh help setvcpus
This is invaluable when you forget the exact syntax or available options for a command.
Part 1: Defining a Virtual Machine from an XML File
In virsh, virtual machines are defined using XML configuration files. XML (Extensible Markup Language) is a structured text format that describes the virtual hardware of the VM — how much RAM it has, how many virtual CPUs, what storage it uses, what network cards it has, and so on.
Creating a Minimal VM Definition
Let's create a simple XML file to define a test virtual machine:
vim test-machine.xml
Add the following content:
<domain type='qemu'>
<name>test-machine</name>
<memory unit='GiB'>1</memory>
<vcpu placement='static'>1</vcpu>
<os>
<type arch='x86_64' machine='pc'>hvm</type>
</os>
</domain>
Let's break down what each line means:
| Element | Value | Meaning |
|---|---|---|
type='qemu' |
qemu | Use QEMU as the virtualisation engine |
<name> |
test-machine | The name of this VM |
<memory unit='GiB'>1 |
1 GiB | 1 gigabyte of RAM |
<vcpu>1 |
1 | One virtual CPU core |
arch='x86_64' |
x86_64 | 64-bit architecture |
hvm |
hvm | Hardware Virtual Machine — use CPU hardware extensions |
💡 Important note: This is a minimal, educational example. A real, bootable virtual machine would also include storage device definitions (virtual disk images), network interface definitions, and a boot device. We're keeping it minimal here to focus on the management commands themselves.
Registering the VM with virsh
The define command reads the XML file and registers the virtual machine with libvirt:
virsh define test-machine.xml
This creates a persistent VM definition — the configuration is stored and survives reboots. The VM now exists in libvirt's knowledge, but it is not yet running.
Part 2: Listing and Inspecting Virtual Machines
Viewing Running VMs
virsh list
After just defining our VM (not starting it), this command shows nothing — it only displays active (running) domains by default.
Viewing All VMs (Running and Stopped)
virsh list --all
Sample output:
Id Name State
-------------------------------
- test-machine shut off
Now we see our VM listed with a state of shut off. The - in the Id column indicates it has no running instance ID yet — it's not started.
Part 3: Starting, Stopping, and Rebooting Virtual Machines
Starting a VM
virsh start test-machine
If the VM name contains spaces, wrap it in double quotes:
virsh start "my test machine"
After starting, virsh list shows the VM with a running state and an assigned ID number.
Graceful Reboot
virsh reboot test-machine
This sends a reboot signal to the operating system running inside the VM. The guest OS handles the reboot gracefully — processes close normally, applications save their data, filesystems are properly unmounted. This is equivalent to clicking "Restart" on a real computer.
Force Reset (Hard Restart)
virsh reset test-machine
This is the equivalent of pressing the physical Reset button on a desktop computer — or unplugging the power cord and plugging it back in. The VM immediately restarts without giving the guest OS any chance to save state or close processes cleanly. Use this only when the guest is frozen and unresponsive.
Graceful Shutdown
virsh shutdown test-machine
Sends a shutdown signal to the guest operating system. The OS handles the shutdown gracefully — just like clicking "Shut Down" on a real computer. Applications have time to save data, services stop cleanly, and the filesystem is properly closed.
⚠️ For graceful shutdown and reboot to work, the guest OS must have the ACPI (Advanced Configuration and Power Interface) support properly configured, and the VM must have
qemu-guest-agentinstalled. Our minimal test VM has no OS, so graceful commands won't have the expected effect, but they work correctly in real setups.
Force Power Off (Hard Shutdown)
virsh destroy test-machine
⚠️ Don't let the name mislead you! Despite the alarming name,
virsh destroydoes not delete the virtual machine. It is the equivalent of pulling the power cord from a running computer — the VM stops immediately with no warning to the guest OS. Data that wasn't flushed to disk may be lost. Use this only when the machine is unresponsive.
Think of it this way:
virsh shutdown= politely asking the computer to turn offvirsh destroy= yanking the power cable — the machine stops, but its definition and storage remain intact
After virsh destroy, running virsh list --all confirms the VM is shut off — still defined, still exists, just not running.
Part 4: Deleting Virtual Machines Permanently
Remove the VM Definition (Keep Storage)
virsh undefine test-machine
This removes the VM's definition from libvirt — the XML configuration is deleted. However, any storage volumes (virtual disk images) associated with the VM are not deleted. This is the safe default — you probably want to keep the data even if you're removing the VM configuration.
Remove Everything Including Storage
virsh undefine test-machine --remove-all-storage
This deletes both the VM definition and all storage volumes associated with it. Use this when you want a completely clean removal. Always double-check before running this — there is no undo.
💡 To see all options for any command:
virsh help undefine
Part 5: Autostart — Surviving Server Reboots
By default, when your physical server restarts, virtual machines on it do not automatically start back up. They remain in a shut off state until someone manually starts them.
For production workloads — databases, web servers, application services — you almost always want the VMs to restart automatically when the host boots.
Enable Autostart
virsh autostart test-machine
Now if the host server reboots, test-machine will automatically start during the boot process.
Disable Autostart
virsh autostart --disable test-machine
Removes the autostart configuration. The VM will stay off after a host reboot.
Part 6: Inspecting VM Resources with dominfo
To see the current resource allocation for a virtual machine:
virsh dominfo test-machine
Sample output:
Id: -
Name: test-machine
UUID: a1b2c3d4-e5f6-7890-abcd-ef1234567890
OS Type: hvm
State: shut off
CPU(s): 1
Max memory: 1048576 KiB
Used memory: 1048576 KiB
Persistent: yes
Autostart: disable
This gives you a complete snapshot of the VM's current configuration: its state, CPU count, memory allocation, whether it persists across reboots, and whether autostart is enabled.
Part 7: Changing Virtual CPU (vCPU) Count
Step 1 — Discover the Right Command
If you forget the exact command name, virsh's tab completion helps:
virsh set<TAB><TAB>
This displays all commands starting with set, including setvcpus, setmem, setmaxmem, and others.
Step 2 — Check the Help
virsh help setvcpus
You'll see the syntax requires: domain name, count, and an option flag. The key options are:
| Flag | Effect |
|---|---|
--config |
Apply the change the next time the VM boots (safe for running VMs) |
--live |
Apply the change immediately to a running VM |
--maximum |
Set the maximum allowed vCPU count (ceiling) |
Step 3 — Increase the Maximum vCPU Ceiling
Before you can assign 2 vCPUs, the VM's maximum must be set to at least 2. The maximum is the upper bound defined in the configuration:
virsh setvcpus test-machine 2 --config --maximum
Step 4 — Set the Actual vCPU Count
virsh setvcpus test-machine 2 --config
This queues the change to take effect on the next boot. It does not change a currently running VM.
Step 5 — Apply the Change (Restart the VM)
virsh destroy test-machine # Force power off (since our VM has no OS)
virsh start test-machine # Start it back up
In a real scenario with a guest OS, you'd use:
virsh shutdown test-machine # Graceful shutdown
virsh start test-machine # Start with new configuration
Step 6 — Verify the Change
virsh dominfo test-machine
# CPU(s): 2 ← confirmed
Part 8: Changing Memory Allocation
Adjusting memory follows the same pattern as vCPUs — you must first change the maximum, then set the actual allocation, then restart the VM.
Step 1 — Increase the Maximum Memory
virsh setmaxmem test-machine 2048M --config
This sets the maximum allowable memory to 2,048 MB (2 GiB). Memory values can be specified in KB, MB, GB, or KiB/MiB/GiB.
Step 2 — Set the Actual Memory Allocation
virsh setmem test-machine 2048M --config
Step 3 — Apply the Change
virsh destroy test-machine # or: virsh shutdown test-machine
virsh start test-machine
Step 4 — Verify
virsh dominfo test-machine
# Max memory: 2097152 KiB ← 2 GiB confirmed
# Used memory: 2097152 KiB
💡 Why set maximum AND actual separately? The maximum acts as an upper safety ceiling. The actual allocation is what the VM actually uses. This two-level system lets you set a conservative actual allocation while leaving room to increase it later without having to reconfigure the maximum. It also prevents a VM from accidentally being allocated more than its maximum allows.
Complete Command Reference
VM Lifecycle
# Define a VM from an XML file
virsh define test-machine.xml
# List running VMs
virsh list
# List all VMs (running and stopped)
virsh list --all
# Start a VM
virsh start test-machine
# Graceful reboot (sends signal to guest OS)
virsh reboot test-machine
# Force hard reset (like pressing Reset button)
virsh reset test-machine
# Graceful shutdown (sends signal to guest OS)
virsh shutdown test-machine
# Force hard power off (like pulling the power cord)
virsh destroy test-machine
# Remove VM definition (keep storage)
virsh undefine test-machine
# Remove VM definition AND all storage
virsh undefine test-machine --remove-all-storage
Autostart
# Enable autostart on host boot
virsh autostart test-machine
# Disable autostart
virsh autostart --disable test-machine
Resource Management
# View VM resource info
virsh dominfo test-machine
# Set maximum vCPU count
virsh setvcpus test-machine 2 --config --maximum
# Set actual vCPU count (takes effect on next boot)
virsh setvcpus test-machine 2 --config
# Set maximum memory
virsh setmaxmem test-machine 2048M --config
# Set actual memory allocation (takes effect on next boot)
virsh setmem test-machine 2048M --config
Getting Help
# List all virsh commands grouped by category
virsh help
# Get detailed help for a specific command
virsh help <command>
virsh help setvcpus
virsh help undefine
virsh Command Cheat Sheet
| Command | What It Does | Real-World Analogy |
|---|---|---|
virsh define |
Register a VM from XML | Setting up a new computer |
virsh start |
Power on a VM | Pressing the power button |
virsh shutdown |
Request graceful shutdown | Clicking "Shut Down" in the OS |
virsh destroy |
Force immediate power off | Pulling the power cord |
virsh reboot |
Request graceful reboot | Clicking "Restart" in the OS |
virsh reset |
Force immediate restart | Pressing the Reset button |
virsh undefine |
Delete VM configuration | Deregistering a computer |
virsh autostart |
Start VM when host boots | Setting startup programs |
virsh dominfo |
View VM resource allocation | Checking System Properties |
virsh list --all |
See all VMs and their states | Checking Task Manager |
Common Questions Answered
Q: What's the difference between virsh destroy and virsh undefine?virsh destroy is a hard power-off — the VM stops running immediately but its configuration and storage are preserved. You can start it again with virsh start. virsh undefine removes the VM's registration from libvirt — the configuration is deleted. Without --remove-all-storage, the disk image files remain. Think of destroy as "turn off" and undefine as "delete".
Q: Why do changes to vCPUs and memory require a restart? Most resource changes using --config modify the VM's stored configuration file rather than the live, running state. The guest OS allocated memory and scheduled processes at boot time; changing these resources while the VM is running would require the guest OS's cooperation (hot-plugging). For the --live flag, some changes can be applied without a restart — but this is more complex and not all hypervisor configurations support it.
Q: What is HVM and why is it used? HVM (Hardware Virtual Machine) means the VM uses the CPU's hardware virtualisation extensions (Intel VT-x or AMD-V) to run guest code directly on the CPU, rather than emulating every instruction in software. HVM VMs run at near-native performance. The alternative — full software emulation — is much slower and is only used when hardware extensions are unavailable.
Q: Can I manage VMs on a remote server with virsh? Yes. virsh can connect to a remote libvirt daemon using SSH. For example: virsh -c qemu+ssh://user@remotehost/system list --all. This is how tools like virt-manager manage VMs on remote servers from a local graphical interface.
What's Next?
You now have a solid foundation in Linux virtualisation management:
✅ QEMU-KVM architecture — how QEMU emulation and KVM hardware acceleration work together
✅ virsh — the command-line VM management tool and how it relates to libvirt
✅ XML VM definitions — how VMs are defined and registered
✅ Full VM lifecycle — define, start, shutdown, destroy, undefine
✅ Autostart — ensuring VMs restart automatically after host reboots
✅ Resource management — changing vCPU counts and memory allocations
✅ The maximum/actual pattern — why you set ceiling and allocation separately
Coming up in the Virtualisation chapter: VM Disk Images and Storage Pools — creating and managing the virtual disk images that give your VMs persistent storage, and understanding how libvirt organises storage into pools and volumes.
This post is part of the Learning Linux Basics series — a beginner-friendly journey through the essential skills every Linux user and administrator should know.