Product docsVirtualization & VDS
Create KVM virtual machines with libvirt on a Linux VDS
Run KVM guests inside a Linux VDS: install libvirt, start the default NAT network, create an Ubuntu VM from a cloud image with cloud-init and connect over SSH.
- Advanced
- 30 min read
- Updated
On this page
A Linux VDS with nested virtualization can run KVM virtual machines of its own, managed with libvirt. That is useful for isolated test environments, CI machines or labs. This guide creates an Ubuntu guest from Ubuntu's official cloud image; cloud-init puts your SSH key into it, so there is no installer to click through. It builds on the check and package installation in VDS and nested virtualization.
Before you start
- An Ubuntu or Debian VDS, nested dedicated or dedicated server where
kvm-ok(packagecpu-checker) printsKVM acceleration can be used. - A user with
sudoand an SSH key pair on your own computer; see SSH keys. - Free disk space for the guests under
/var/lib/libvirt/images.
Step 1: Install the tools
sudo apt update
sudo apt install qemu-system-x86 qemu-utils libvirt-daemon-system virtinst
sudo usermod -aG libvirt $USERLog out and in again so the group membership applies.
Verify: virsh list --all runs without a permission error.
Step 2: Start the default network
libvirt's default network gives guests addresses in 192.168.122.0/24 and NAT to the internet:
virsh net-list --all
sudo virsh net-start default
sudo virsh net-autostart defaultVerify: virsh net-list shows default as active with autostart yes.
Step 3: Download the cloud image
Download Ubuntu 24.04's cloud image and its checksum list, and check the file:
cd /var/lib/libvirt/images
sudo wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
sudo wget https://cloud-images.ubuntu.com/noble/current/SHA256SUMS
sha256sum -c SHA256SUMS --ignore-missingVerify: the check prints noble-server-cloudimg-amd64.img: OK.
Step 4: Create the guest's disk
Copy the image for the new guest and give it room to grow; cloud-init grows the file system on first boot:
sudo cp noble-server-cloudimg-amd64.img vm1.qcow2
sudo qemu-img resize vm1.qcow2 20GStep 5: Create and start the VM
Find the OS name libvirt knows for Ubuntu 24.04:
sudo apt install libosinfo-bin
osinfo-query os | grep -i ubuntu24Create the guest, import the disk and pass your public SSH key to cloud-init. Copy your public key to the server first (for example to ~/id_ed25519.pub):
virt-install --name vm1 --memory 2048 --vcpus 2 --disk /var/lib/libvirt/images/vm1.qcow2 --import --osinfo ubuntu24.04 --network network=default --cloud-init clouduser-ssh-key=$HOME/id_ed25519.pub --graphics none --noautoconsole--import builds the VM around the existing disk instead of running an installer, and clouduser-ssh-key lets you log in as the image's default user, ubuntu.
Verify: virsh list shows vm1 as running.
Step 6: Connect to the guest
Wait a minute for the first boot, then look up the guest's address and connect from the server:
virsh domifaddr vm1
ssh ubuntu@192.168.122.50From your own computer, jump through the server in one command:
ssh -J you@203.0.113.10 ubuntu@192.168.122.50If SSH does not work yet, open the serial console with virsh console vm1 and leave it with Ctrl + ].
Step 7: Everyday management
virsh list --all
virsh shutdown vm1
virsh start vm1
virsh autostart vm1virsh autostart starts the guest whenever the server boots. To delete a guest and its disk, run virsh destroy vm1 and virsh undefine vm1 --remove-all-storage.
Troubleshooting
virt-install says KVM is not available or falls back to slow emulation. The virtualization extensions are not visible; see nested virtualization problems.
virt-install reports that an OS name is required, or does not know the name. Use a name that osinfo-query os lists on your server; older systems may only know older Ubuntu releases.
virsh domifaddr shows nothing. The guest is still booting, or cloud-init has not configured the network yet. Wait, or check the boot output with virsh console vm1.
Permission denied (publickey) when connecting. The key file given to clouduser-ssh-key was not your public key, or you connected as the wrong user. Recreate the guest with the right key and connect as ubuntu.
The guest has no internet. Check that the default network is active (virsh net-list) and that your host firewall allows forwarding for virbr0.
Next steps
- A web interface for many guests: Proxmox VE on Debian 13.
- Publish a guest's website: Caddy reverse proxy.
Frequently asked questions
Do I need a graphical desktop to manage the VMs?
No. virsh and virt-install work over SSH. If you prefer a graphical tool, virt-manager on your own Linux computer can connect to the server over SSH.
How do guests reach the internet?
Through libvirt's default network, which gives guests private addresses with DHCP and NAT behind the server's public address.
How do I make a guest's web service public?
Run a reverse proxy such as Caddy or Nginx on the host and forward the site to the guest's private address. For other ports, forward them with firewall rules on the host.
Can I run Windows guests?
Yes, from an installation ISO with virt-install's --cdrom option and a graphical console such as VNC over an SSH tunnel. The steps in this guide use a Linux cloud image because it needs no installer.