NeuroDynamic.Tech
Sign inJoin

Your first virtual machine: KVM on Ubuntu, no drama

A small Ubuntu virtual machine running inside your Ubuntu machine: create it, log into it, switch it off and on, and delete it — all in the terminal, with free tools.

The founder · 16 min read ·

BASIC

Tested for real: I ran every command in this guide top-to-bottom on a fresh Ubuntu 24.04 virtual machine (4 CPUs, 8 GB RAM) on 13 August 2026. Versions at test time: Ubuntu 24.04.4 LTS, libvirt 10.0.0, QEMU 8.2.2, virt-manager 4.1.0, virt-install 4.1.0.

Found a problem? Tell me via the contact page.

Placeholders: this guide has nothing in CAPS-WITH-DASHES for you to replace — every command is copy-paste-safe as written. The one variable, $USER, is filled in by the shell automatically, as explained where it appears.

What you'll end up with

A small Ubuntu virtual machine running inside your Ubuntu machine. You will create it, log into it, switch it off and on, and delete it. Everything happens in the terminal, with free tools that Ubuntu itself ships.

Here is the finished state from my test run — me, logged into a machine that did not exist two minutes earlier:

first-vm login: ubuntu
Password:
Welcome to Ubuntu 24.04.4 LTS (GNU/Linux 6.8.0-136-generic x86_64)

ubuntu@first-vm:~$ hostname
first-vm

Who this is for

BASIC. One path, copy-paste-safe, nothing to edit mid-line. For a desktop or laptop Ubuntu user who has never made a virtual machine before.

Time and cost

The commands took me about 4 minutes of actual run time, measured. The big install is 143 MB and took 85 seconds. The Ubuntu image is 596 MB and took 9 seconds on my line — your download times depend on your connection. Budget an hour to read and understand as you go.

Cost: nothing. Every tool here is free and comes from Ubuntu's own archive.

One honesty note: my test machine is itself a virtual machine, which is the slowest way to do this. On real hardware this may be faster, but disk, network, and CPU vary.

Words you'll meet

  • Virtual machine (VM) — a complete computer, made of software, running inside your real one. Also called a guest. Your real machine is the host. (basics)
  • Hypervisor — the software that creates and runs virtual machines. On Linux it is called KVM, and it is built into the kernel you are already running. (basics)
  • Disk image — one big file on your host that the guest sees as its hard drive. Ours ends in .qcow2. (basics)
  • Cloud image — a ready-installed Ubuntu disk image, published by Ubuntu. Using one skips the whole installer. (basics)
  • cloud-init — the first-boot setup tool inside cloud images. We hand it a tiny settings file and it sets our password. (basics)
  • Console — the guest's own screen and keyboard, reached from your terminal. Like plugging a monitor into the virtual machine. (basics)
  • Snapshot — a saved moment of a VM you can return to. Not in this guide — the next one covers it properly. (basics)
  • sudo — "do this as the administrator". Ubuntu asks for your password when you use it. (basics)

Before you start

  • An Ubuntu machine (I tested 24.04) with a user that can use sudo.
  • About 1.5 GB of free disk space (625 MB of tools, 596 MB of image, plus the VM's disk).
  • 8 GB of RAM or more is comfortable. The guest takes 2 GB while it runs.

The steps

Step 1 — check your machine can do this

Your CPU needs hardware virtualisation support. Most modern CPUs have it. Ubuntu has a tiny tool that gives a straight yes or no.

Install it:

sudo apt-get install -y cpu-checker

The important line is:

Setting up cpu-checker (0.7-1.3build2) ...

Check it worked. Ask the question:

kvm-ok

You should see something like:

INFO: /dev/kvm exists
KVM acceleration can be used

KVM acceleration can be used is the green light. If it says KVM can NOT be used, virtualisation is probably switched off in your machine's firmware settings (often called VT-x or AMD-V) — turn it on there and re-run kvm-ok before going further.

Step 2 — install the virtualisation tools

Four packages give us everything: the emulator (qemu-kvm), the management service (libvirt-daemon-system), the graphical manager (virt-manager) and the terminal creation tool (virtinst). All from Ubuntu's own archive — no third-party repositories.

sudo apt-get update
sudo apt-get install -y qemu-kvm libvirt-daemon-system virt-manager virtinst

Your output will vary, but look for:

11 upgraded, 239 newly installed, 0 to remove and 15 not upgraded.
Need to get 143 MB of archives.
After this operation, 625 MB of additional disk space will be used.
[...snipped...]

This was the longest wait of my whole test: 85 seconds.

Check it worked. Ask the management tool for its version:

virsh --version

You should see something like:

10.0.0

Your version may be newer — that's fine.

Step 3 — join the libvirt group, then log out and back in

This step has a trap that confused me too, so let me spell it out. There are actually two hypervisors after install: a system-wide one where real work happens, and a private per-user one. Until your user joins the libvirt group, the tools quietly talk to the private one. Commands "work", but your machines end up in the wrong place, or seem to vanish.

Add yourself to the group. $USER fills in your username automatically — nothing to edit:

sudo adduser $USER libvirt

The important line is:

info: Adding user `tester' to group `libvirt' ...

Now the part everyone skips: log out and log back in. Group changes only apply to new logins. (Same dance as the docker group, if you have met that.)

After logging back in, point the tools at the system hypervisor by default, permanently:

echo 'export LIBVIRT_DEFAULT_URI=qemu:///system' >> ~/.bashrc

Load it into your current terminal:

source ~/.bashrc

Check it worked. Two quick questions:

groups

Your output will vary, but look for:

tester libvirt

libvirt must be in the list. Then:

virsh uri

The important line is:

qemu:///system

qemu:///system — the system hypervisor. If it says qemu:///session, the .bashrc line did not load; log out and in once more.

Step 4 — check the VM network is on

Guests reach the internet through a small private network that libvirt manages. On Ubuntu 24.04 it came switched on and set to start at boot — this step only confirms it.

virsh net-list --all

You should see something like:

 Name      State    Autostart   Persistent
--------------------------------------------
 default   active   yes         yes

Check it worked. The default row says active and Autostart yes. If State says inactive, run virsh net-start default and virsh net-autostart default, then look again.

Step 5 — download Ubuntu, pre-installed

Here is the trick that makes this guide drama-free. Ubuntu publishes cloud images: disk images with Ubuntu already installed. We download one instead of clicking through an installer for half an hour.

wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img

Your output will vary, but look for:

[...snipped: progress bar...]
589824K ........ ........ ...              100% 72.9M=8.2s

It is 596 MB — mine took 9 seconds on a fast line, yours may take a few minutes.

Check it worked. Inspect the file:

qemu-img info noble-server-cloudimg-amd64.img

A passing run includes:

image: noble-server-cloudimg-amd64.img
file format: qcow2
virtual size: 3.5 GiB (3758096384 bytes)
disk size: 595 MiB

file format: qcow2 — a real disk image, ready to boot.

Step 6 — put the disk in place and give it room

Copy the image into libvirt's image folder, under the name our VM will use:

sudo cp noble-server-cloudimg-amd64.img /var/lib/libvirt/images/first-vm.qcow2

The image ships with a tiny 3.5 GB virtual disk. Grow it to 10 GB — the guest expands into it on first boot:

sudo qemu-img resize /var/lib/libvirt/images/first-vm.qcow2 10G

The important line is:

Image resized.

Check it worked. List the folder — note the sudo, the folder is private to root:

sudo ls -lh /var/lib/libvirt/images/

You should see something like:

-rw-r--r-- 1 root root 596M Aug 13 16:50 first-vm.qcow2

Step 7 — write the first-boot settings

Cloud images have no password set — on purpose. We pass one in with a small cloud-init settings file. Make a folder and the file:

mkdir -p ~/first-vm

Create the file with one copy-paste block:

printf '#cloud-config\nhostname: first-vm\npassword: MyFirstVM2026\nchpasswd:\n  expire: false\n' > ~/first-vm/user-data

That sets the machine's name to first-vm and the password for the built-in ubuntu user to MyFirstVM2026. It is a practice password for a practice machine. Do not reuse this password. This VM is reachable from your libvirt private network. Change it after your first login if you keep the VM around.

Now pack the file into a tiny seed image the VM can read at boot. Ubuntu ships a purpose-built tool for exactly this:

sudo apt-get install -y cloud-image-utils
cloud-localds ~/first-vm/seed.img ~/first-vm/user-data

Put it next to the disk:

sudo cp ~/first-vm/seed.img /var/lib/libvirt/images/first-vm-seed.img

Check it worked. Ask what the seed file is:

file ~/first-vm/seed.img

A passing run includes:

/home/tester/first-vm/seed.img: ISO 9660 CD-ROM filesystem data 'cidata'

'cidata' is the label cloud-init looks for.

Step 8 — create the virtual machine

One command creates and starts the VM: 1 CPU, 2 GB of RAM, our disk, and the seed attached like a CD. The \ at each line end lets one command span several lines — copy the whole block as one:

virt-install \
  --name first-vm \
  --memory 2048 \
  --vcpus 1 \
  --disk path=/var/lib/libvirt/images/first-vm.qcow2 \
  --disk path=/var/lib/libvirt/images/first-vm-seed.img,device=cdrom \
  --osinfo ubuntu24.04 \
  --import \
  --network network=default \
  --graphics none \
  --noautoconsole

You should see something like:

WARNING  Requested memory 2048 MiB is less than the recommended 3072 MiB for OS ubuntu24.04

Starting install...
Creating domain...                                          |    0 B  00:00
Domain creation completed.

That WARNING is real and safe to ignore here — 2 GB boots and runs fine for a learning VM. In my test the whole creation took 6 seconds, and the guest was on the network 35 seconds later.

Check it worked. List your machines:

virsh list --all

A passing run includes:

 Id   Name       State
--------------------------
 1    first-vm   running

running — you own a virtual machine.

Step 9 — log in on the console

Give it about a minute after creation — the guest needs to boot and cloud-init needs to set your password. Then connect to its console:

virsh console first-vm

You should see something like:

Connected to domain 'first-vm'
Escape character is ^] (Ctrl + ])

If the screen then sits empty, press Enter once — that wakes the login prompt. This caught me too. Log in with user ubuntu, password MyFirstVM2026:

first-vm login: ubuntu
Password:
Welcome to Ubuntu 24.04.4 LTS (GNU/Linux 6.8.0-136-generic x86_64)

Have a look around — it is a complete Ubuntu machine:

hostname

The important line is:

first-vm

To leave: type exit to log out, then hold Ctrl and press ] to drop back to your own terminal.

Check it worked. You saw the first-vm hostname from inside the guest, and you are back at your own prompt.

Step 10 — switch it off and on

A polite shutdown, like pressing the power button:

virsh shutdown first-vm

You should see something like:

Domain 'first-vm' is being shutdown

Mine took 4 seconds to stop. Confirm with virsh list --all — the State shows shut off. Start it again any time:

virsh start first-vm

The important line is:

Domain 'first-vm' started

Check it worked. virsh list --all shows running again. Full boot back to a login prompt takes about half a minute.

That completes part one: you built, entered, and power-cycled a virtual machine, all in the terminal. Part two below covers the optional graphical view, the problems I hit, and the full undo.

Part two — the graphical view, and cleaning up

Everything above was the tested terminal path. This part is shorter: what virt-manager gives you, the failure modes I actually hit, and how to remove it all. Come back to it whenever suits — the VM from part one keeps running either way.

What about the graphical way?

virt-manager, which we installed in Step 2, is the point-and-click version of everything above. Honesty first: my test machine has no desktop. I verified the program is installed (virt-manager --version answered 4.1.0). I could not test the GUI itself, and I will not fake screenshots.

Documented behaviour, not tested in my run: virt-manager normally shows a window listing your machines — first-vm among them — with usage graphs. Double-clicking a VM should open its screen, and the toolbar carries the usual start, pause and stop controls; the hardware details live in the VM's own window. The exact layout can differ between versions, so treat this as orientation, not a map. Everything this guide did in the terminal, virt-manager can do with clicks — and the VM you built here will already be in its list.

Something went wrong?

Everything below is something I actually hit or provoked during testing.

  • You see an empty list from virsh list --all but you created a VM → it means your tools are talking to the per-user hypervisor, not the system one → run virsh uri; if it says qemu:///session, redo Step 3, including the log-out.
  • You see Failed to connect socket ... libvirt-sock: Permission denied → it means you are not in the libvirt group yet in this session → redo Step 3 and genuinely log out and back in.
  • You see WARNING Requested memory 2048 MiB is less than the recommended 3072 MiB → it means virt-install is being cautious → nothing to do; the VM runs fine for learning.
  • You see ls: cannot open directory '/var/lib/libvirt/images/': Permission denied → it means that folder is root-only, which is normal → put sudo in front of the ls.
  • You see a blank screen after virsh console → it means the login prompt already scrolled past or has not printed → press Enter once; if the guest is still booting, wait 30 seconds and press Enter again.

Undo all of this

Destructive if this machine already had VMs: the package purge and the final folder deletion remove libvirt's data for every VM on the machine, not just first-vm. Follow the whole section only on a machine where libvirt exists just for this guide.

Tested for real, in this order. It removes the VM, its disks, the tools, and the group change.

Force the VM off (fine for a throwaway):

virsh destroy first-vm

Delete it, including both disk files:

virsh undefine first-vm --remove-all-storage

A passing run includes:

Domain 'first-vm' has been undefined
Volume 'vda'(/var/lib/libvirt/images/first-vm.qcow2) removed.
Volume 'sda'(/var/lib/libvirt/images/first-vm-seed.img) removed.

Remove the downloaded image and the settings folder:

rm -r ~/first-vm ~/noble-server-cloudimg-amd64.img

Remove the .bashrc line and leave the group:

sed -i '/LIBVIRT_DEFAULT_URI/d' ~/.bashrc
sudo gpasswd -d $USER libvirt

Remove the packages:

sudo apt-get remove --purge -y qemu-kvm libvirt-daemon-system virt-manager virtinst cloud-image-utils cpu-checker
sudo apt-get autoremove --purge -y

Now an honest wrinkle I hit: the qemu engine packages survive that sweep — apt does not count them as removable leftovers. Purge them explicitly:

sudo apt-get remove --purge -y qemu-system-x86 qemu-system-gui qemu-system-common qemu-utils qemu-block-extra ipxe-qemu
sudo apt-get autoremove --purge -y

Remove the leftover network bridge and data folders. Only do this if libvirt was installed just for this guide — these folders hold the disks and configs of every VM on the machine:

sudo ip link delete virbr0
sudo rm -r /var/lib/libvirt /etc/libvirt

Check it worked. Ask for the tools one last time:

virsh --version

The important line is:

bash: virsh: command not found

That error is the pass mark. My whole undo took about 75 seconds and freed roughly 620 MB.

Where to go next

  • Headless VMs: virt-install, cloud-init and snapshots without a desktop (the DEEP END follow-on — SSH keys instead of passwords, snapshots you can rewind to, and cloning).
  • Official docs: Ubuntu Server virtualisation documentation — the reference this guide's install follows.

Last tested: 13 August 2026 on Ubuntu 24.04.4 LTS. Versions: libvirt 10.0.0, QEMU 8.2.2, virt-manager 4.1.0, virt-install 4.1.0, cloud-image-utils 0.33.


Tried it? Improved it?

Tell the forum what worked and what didn’t: real experience beats recommendations, and the best answers get folded back into this guide with credit.

Related guides