Skip to main content

Command Palette

Search for a command to run...

Manage and Configure Virtual Machines in Linux

Updated
16 min readView as Markdown

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-agent installed. 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 destroy does 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 off

  • virsh 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:

  1. QEMU-KVM architecture — how QEMU emulation and KVM hardware acceleration work together

  2. virsh — the command-line VM management tool and how it relates to libvirt

  3. XML VM definitions — how VMs are defined and registered

  4. Full VM lifecycle — define, start, shutdown, destroy, undefine

  5. Autostart — ensuring VMs restart automatically after host reboots

  6. Resource management — changing vCPU counts and memory allocations

  7. 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.