In KVM, you can install a guest virtual machine using the graphical or command-line interface. If you are running a minimally configured Linux distribution as a KVM host, the only interface available to you will be a command-line interface.

Even if your KVM host has a graphical user interface, you may prefer to install a guest virtual machine using only the command-line interface. So, the way to install a guest virtual machine from the command line is through a serial console using the virt-install tool.

Interacting with a serial console is similar to using a text terminal without a graphical interface or a mouse. It provides an alternative way of accessing your host by replacing the default graphical consoles. Generally, the first serial port on the guest VM (/dev/ttyS0) is used for the serial console.

Once you have finished installing the operating system on a guest virtual machine with a serial console, you can use SSH to connect to it. The serial console comes in handy if you are unable to ssh into your virtual machine due to connectivity issues, or if you need to provide a LUKS passphrase during boot if you have encrypted your virtual machine disks with LUKS encryption.

In this blog, I'll show you how to use the virt-install tool to install a KVM guest virtual machine from the command line. While virt-install also supports graphical installations via SPICE or VNC, this article will only focus on text-mode installations via the serial console.

I will use Debian 12 as an example of a guest virtual machine.

If you prefer to install a guest virtual machine through a graphical interface with Virtual Machine Manager, see my other blog, 'Create Virtual Machines in KVM Virt-Manager like a Pro: All Options Explained'.

If you haven't already installed KVM virtualization on your Linux distribution, please see my other blog, 'How Do I Properly Install KVM on Linux'.

So, let’s begin.

Table of Contents

1. Using the virt-install Command-Line Tool

To create a virtual machine and begin the installation of its operating system, you must first provide some basic information.

The command below, for example, will create a Debian 12 guest virtual machine named debian-12-default with 2 GiB of RAM, 1 virtual CPU, and a 20 GiB qcow2 virtual disk, with all options required.

$ sudo virt-install \
--name debian-12-default \
--memory 2048 \
--vcpus 1 \
--cdrom /dc/iso/debian-12.5.0-amd64-DVD-1.iso

Since you have not specified the type of console to use for the installation, the hypervisor default will be used, in this case, a graphical console (virt-viewer) using the SPICE client.

If you attempt to run the same command on a Linux distribution with only a command-line interface (no desktop environment), you will get an error. It will throw an error message something like "No console to launch for the guest." You will be unable to continue with the installation.

Moreover, the preceding example is very simple. To properly configure a guest virtual machine, much more detailed options are required.

The command below will create a Debian 12 guest virtual machine named debian-12-minimal, but with a few extra options. This will also have 2 GiB of RAM, 1 virtual CPU, and a 20 GiB qcow2 virtual disk. This, on the other hand, will use a serial console.

$ sudo virt-install \
--name debian-12-minimal \
--memory memory=6144,currentMemory=2048 \
--vcpus maxvcpus=3,vcpus=1 \
--cpu mode=host-passthrough \
--network network=default \
--location /dc/iso/debian-12.5.0-amd64-DVD-1.iso \
--os-variant debian12 \
--disk size=20,format=qcow2,cache=none,discard=unmap \
--tpm model='tpm-crb',type=emulator,version='2.0' \
--channel type=unix,target.type=virtio,target.name=org.qemu.guest_agent.0 \
--graphics none \
--extra-args 'console=tty0 console=ttyS0,115200n8 --- console=tty0 console=ttyS0,115200n8' \
--boot uefi

While there are numerous other settings to tweak, I believe this will be sufficient to get you started with your virtual machine. For more information, see the manual page man virt-install.

Before you press the [ENTER] key and begin the installation process, let me explain all of the options.

--name debian-12-minimal

Name of the guest virtual machine. It must be unique among all known guests of the hypervisor on the connection, including those not currently active.

--memory memory=6144,currentMemory=2048

The amount of host memory (in MiB) that will be allocated to the guest. The element 'memory=6144' (6 GiB) specifies the maximum amount of memory that can be hot plugged into the running guest. However, 'currentMemory=2048' (2 GiB) specifies the guest's actual memory allocation at boot.

If you just want a fixed memory of 2 GiB and no hot plugging, use '--memory 2048' instead.

To find out how much total memory is available and how much is free on your host, use the following command.

$ sudo virsh nodememstats
--vcpus maxvcpus=3,vcpus=1

The number of virtual CPUs to assign to the guest virtual machine. The 'maxvcpus=3' element specifies the maximum number of virtual CPUs that can be hot plugged to the running guest. The 'vcpus=1' element, on the other hand, specifies the actual number of virtual CPUs assigned to the guest at boot.

If you only want a fixed number of virtual CPUs, say one, use '--vcpus 1' instead.

Run the following command to find out how many CPUs the host has.

$ sudo virsh nodeinfo
--cpu mode=host-passthrough

Sets the CPU model for the guest. The mode attribute allows you to configure a guest CPU to be as close as possible to the host CPU.

When the mode is set to 'mode=host-passthrough', the model and features of the host CPU are exactly passed on to the guest virtual machine. This is also the recommended option. The downside is that live migration to other hosts with different hardware is not possible.

You can also set the mode to 'mode=host-model'. In this mode, a CPU model similar to the host CPU is first chosen from the "CPU models" list. Then, to get as close as possible to the host CPU, additional features are added. This will not exactly match the host CPU like 'host-passthrough', but it will provide many of the benefits of host-passthrough while also making live migration safe.

To find out which CPU model and features will be assigned to the guest virtual machine if the mode is set to 'host-model', run the following command on your host.

$ sudo virsh capabilities --xpath '//cpu'

To see a list of all the "CPU models" you can use, run the following command on your host.

$ sudo virsh domcapabilities --arch $(uname -m) | grep "model usable='yes'"
--network network=default

Connects the guest virtual machine to the host network.

Here, you can choose how the virtual machine should connect to the host network.

When Libvirt is connected to a system instance, there are three options for connecting the virtual machine to the host network. A virtual NAT network, a bridge network using a bridge device, or a virtual bridge network using MacVTap.

'default' Virtual NAT Network:

When you install KVM virtualization, a virtual network named 'default' with NAT is automatically created.

To see a list of available networks for you, run the following command.

$ sudo virsh net-list

Please keep in mind that virtual machines on the 'default' network will only have outbound network access. That is, virtual machines will have complete network access, but devices outside the host will be unable to communicate with virtual machines on the host. Only the host computer will have complete access to the virtual machines.

The virtual machine, for example, can browse the internet, but cannot host a web server that is accessible to the outside world. Not even from your own mobile device on the same network. Only the host computer, and of course, other virtual machines connected to the same 'default' network, can access the web server.

From a security standpoint, this network is the best option because you have exclusive access to the virtual machine.

The 'network=default' element indicates that you want to connect to the virtual NAT network named 'default' that was created by default when you installed KVM virtualization.

Bridge Device:

If you want virtual machines to be directly visible on the same physical network as the host and accessible to external devices, you must use a network bridge.

Before opting for this option, however, make sure you have already established a network bridge connection on your host.

If you have not yet created a network bridge and would like to do so on your host computer, please see my other blog post, 'How to Properly Install KVM on Linux'.

To configure the network bridge, simply replace the 'network=default' element with 'bridge=bridge0' element. Where bridge0 is the name of the bridge connection you've created.

You will then have a network that is accessible to other physical machines on the same network as yours, as well as the outside world.

Virtual machines that use this bridge device will receive IP addresses from the same pool as your host computer, which is typically the DHCP server on your modem.

MacVTap Device:

If you don't want to go through the hassle of manually creating a network bridge, but still want the virtual machine to be accessible from the outside world, including other devices on the same network as yours, you can use the MacVTap option.

To configure the network to MacVTap, simply replace the 'network=default' element with 'type=direct,source=enp2s0' element. Where enp2s0 is the name of your network device.

The virtual machine will then receive an IP address from the same pool as your host computer, which is typically the DHCP server on your modem.

However, keep in mind that your host computer should not have any network bridges configured for this to work.

Your virtual machine will then be accessible to the outside world, with one exception: your own host computer cannot access the virtual machine.

For example, suppose you run a web server on your virtual machine and set up the network to use MacVTap device. The web page you hosted on your virtual machine will then be accessible to the outside world. The web page is also accessible to other devices on the same physical network as yours, such as your mobile phone.

The only computer that does not have access to the virtual machine is your own host computer. You cannot ping the virtual machine from your host, nor can you ssh in. You should work directly from the serial console of the Virtual Machine. This is the difference between the MacVTap network and the network bridge.

--location /dc/iso/debian-12.5.0-amd64-DVD-1.iso

The location of the installer image.

To find out if the ISO file is an operating system installation image, use the following command.

$ osinfo-detect /dc/iso/debian-12.5.0-amd64-DVD-1.iso 
Media is bootable.
Media is an installer for OS 'Debian 12 (x86_64)'
--os-variant debian12

Indicate which operating system the guest virtual machine should be optimized for. To get a list of the accepted operating system variant names, run the following command.

$ osinfo-query os
--disk size=20,format=qcow2,cache=none,discard=unmap

Specifies the media to be used as the guest virtual machine storage, with various options.

  • size=20: Sets the disk size to 20 GiB.
  • format=qcow2: Sets the disk format to qcow2. Other options may include 'raw', 'vdi', 'vmdk', and so on. Please keep in mind that internal snapshots are only available for the qcow2 type.
  • cache=none: This indicates that the host cache must be bypassed. Reads and writes take place directly between the hypervisor and the storage device. This is also the recommended one. Other options include writebackwritethroughunsafe, and directsync.
  • discard=unmap: The type of discard mode you want to use for the qcow2 virtual disk. There are two modes available here: ignore and unmap. When you delete files in the guest, the changes are immediately reflected in the guest's file system. However, the qcow2 disk image file associated with the guest on the host does not shrink to reflect the newly freed space. When you set the discard mode to 'unmap', the qcow2 disk image will automatically shrink to reflect the newly freed space.
--tpm model='tpm-crb',type=emulator,version='2.0'

This enables the guest to have access to TPM functionality. KVM supports two models: TPM Interface Specification (TIS) and Command-Response Buffer (CRB). Both version 1.2 and version 2.0.

The element model='tpm-crb' sets the TPM to the CRB. When type=emulator is used, each guest gets its own private emulated TPM. The element version='2.0' indicates that TPM version 2.0 is to be used.

--channel type=unix,target.type=virtio,target.name=org.qemu.guest_agent.0

Creates a QEMU Guest Agent channel.

The QEMU Guest Agent channel establishes a private communication channel between the host physical machine and the guest virtual machine, allowing you to send commands to the guest virtual machine's operating system. The guest operating system, then responds asynchronously to these commands.

Please keep in mind that once you've added the QEMU Guest Agent channel, you'll also need to install the qemu-guest-agent package in the guest virtual machine.

--graphics none

The guest virtual machine will not be assigned a graphical console. As a result, the guest virtual machine must be explicitly configured with a text console on the guest virtual machine's first serial port. The option --extra-args is used to accomplish this.

--extra-args 'console=tty0 console=ttyS0,115200n8 --- console=tty0 console=ttyS0,115200n8'

I've specified two consoles here: a virtual console and a serial console. The console=tty0 denotes the first VGA console, while the console=ttyS0 denotes the first serial port. The output will be displayed on both of them.

The first 'console=tty0 console=ttyS0,115200n8' element instructs virt-install to install the guest virtual machine using the VGA console or the serial console /dev/ttyS0 at 115200 bits per second speed, with no parity bit and 8 data bits.

Following a triple dash (---), the same second element instructs the virt-install to permanently copy it into the bootloader of the installed guest virtual machine.

As a result, on subsequent boots, the kernel boot messages are sent to both consoles of the guest virtual machine. This will come in handy if you decide to add a VGA console to the virtual machine later.

The changes are made to the GRUB_CMDLINE_LINUX line in the guest virtual machine's /etc/default/grub file.

--boot uefi

Use UEFI firmware for the guest. When using UEFI firmware, internal snapshots can be taken only when the guest is offline and not online.

If you want BIOS firmware instead, simply ignore the '--boot' option. With the BIOS firmware, you can take internal snapshots when the guest is offline as well as online.

2. Install KVM Guest OS from the Command-Line

Now that you know the options, let's proceed with the installation of the Debian 12 Linux operating system. When you press the [ENTER] key, a text-based installation process begins in the serial console.

$ sudo virt-install \
--name debian-12-minimal \
--memory memory=6144,currentMemory=2048 \
--vcpus maxvcpus=3,vcpus=1 \
--cpu mode=host-passthrough \
--network network=default \
--location /dc/iso/debian-12.5.0-amd64-DVD-1.iso \
--os-variant debian12 \
--disk size=20,format=qcow2,cache=none,discard=unmap \
--tpm model='tpm-crb',type=emulator,version='2.0' \
--channel type=unix,target.type=virtio,target.name=org.qemu.guest_agent.0 \
--graphics none \
--extra-args 'console=tty0 console=ttyS0,115200n8 --- console=tty0 console=ttyS0,115200n8' \
--boot uefi

Starting install...
Retrieving 'vmlinuz' | 0 B 00:00:00 ...
Retrieving 'initrd.gz' | 0 B 00:00:00 ...
Allocating 'debian-12-minimal.qcow2' | 0 B 00:00:00 ...
Creating domain... | 0 B 00:00:00
Running text console command: virsh --connect qemu:///system console debian-12-minimal
Connected to domain 'debian-12-minimal'
Escape character is ^] (Ctrl + ])
How to Install a KVM Guest OS from the Command-Line - Install Start

Follow the standard installation procedure for the guest operating system. Complete the installation process by selecting a language, keyboard, location, creating partitions, configuring user and password, and so on.

When it comes to software, uncheck any GUI desktop environment. Only a text interface is permitted in the serial console. You can, however, install the GUI desktop environment if you intend to use it later when you add a graphical display to the guest virtual machine. I'll show you how to add a graphical display later in this tutorial.

Also, make sure the SSH server is installed. You'll need it to connect to the virtual machine.

How to Install a KVM Guest OS from the Command-Line - Select SSH

When the installation is complete, press the [Continue] button to reboot the system to a text-mode login page.

How to Install a KVM Guest OS from the Command-Line - Install Complete

Type in your username and password and you will be logged into a command-line interface within a virtual serial console.

  Booting `Debian GNU/Linux'

Loading Linux 6.1.0-18-amd64 ...
Loading initial ramdisk ...
/dev/vda2: clean, 33041/446160 files, 379306/1783296 blocks

Debian GNU/Linux 12 debian ttyS0

debian login:
madhu
Password:
Linux debian 6.1.0-18-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.76-1 (2024-02-01) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.


madhu@debian:~$

If you want to exit the serial console, press the Ctrl + ] keys. You will be returned to the host terminal.

Now that I'm in the host terminal, let me connect to the guest via SSH. First, find the IP address of the guest.

$ sudo virsh domifaddr debian-12-minimal --source agent
Name MAC address Protocol Address
-------------------------------------------------------------------------------
lo 00:00:00:00:00:00 ipv4 127.0.0.1/8
- - ipv6 ::1/128
enp1s0 52:54:00:bd:4c:06 ipv4
192.168.124.223/24
- - ipv6 fe80::5054:ff:febd:4c06/64

The guest's IP address is 192.168.124.223. So connect the guest to this address using SSH.

$ ssh [email protected]
...
Are you sure you want to continue connecting (yes/no/[fingerprint])?
yes
[email protected]'s password:
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Mar 24 18:23:47 2024


madhu@debian:~$

You have now established an SSH connection to the guest virtual machine. To disconnect from the SSH connection, type exit or press the Ctrl + d keys.

And, to reconnect the guest virtual machine via serial console again, enter the following command into the host and press the [Enter] key.

$ sudo virsh console debian-12-minimal 
Connected to domain 'debian-12-minimal'
Escape character is ^] (Ctrl + ])


debian login: madhu
Password:

Last login: Sun Mar 24 20:47:49 IST 2024 from 192.168.124.1 on pts/0
madhu@debian:~$

Make sure the QEMU guest agent is installed in Debian. If not, install the package.

madhu@debian:~$ sudo apt update
madhu@debian:~$ sudo apt install qemu-guest-agent

3. Set the Terminal Type and Console Window Size

When you connect a remote device via SSH, the terminal type and host screen size are automatically sent to the remote device. This does not occur when connecting via a serial connection. As a result, you may notice a reduced screen size, visual anomalies, and scrolling that isn't working properly.

By default, the serial console will have a terminal type vt220 (or, vt100) and a size of 24x80.

madhu@debian:~$ echo $TERM
vt220

madhu@debian:~$ stty size
24 80

Because of the vt220 terminal type, the output will be black and white. To get colors, you may want to change the terminal type to xterm-256color.

madhu@debian:~$ export TERM=xterm-256color

madhu@debian:~$ echo $TERM
xterm-256color

Also, manually increase the size of the console window.

madhu@debian:~$ stty rows 40 cols 150

madhu@debian:~$ stty size
40 150

There is one other tool called resize that comes with the package xterm in Ubuntu/Debian. In Fedora/Rocky the package is known as xterm-resize. It adjusts the size of the serial console using the settings from the host terminal window.

madhu@debian:~$ sudo apt install xterm

madhu@debian:~$ resize
COLUMNS=172;
LINES=43;
export COLUMNS LINES;

madhu@debian:~$ stty size
43 172

If, after changing the screen size, the serial console still crops the text, exit the serial console by pressing the Ctrl + ] keys. And then enter the command reset in the host terminal. Reconnect to the serial console with the command sudo virsh console debian-12-minimal.

4. Check and Set the Baud Speed of the Serial Port

In a real-world situation, the baud speed setting of the RS-232 connection is affected by the length of the cable. The higher the baud rate, the shorter the cable should be. Otherwise, the communication will be unreliable. So most of the Linux distributions set the baud speed to 9600, which is considered a reliable and safe baud speed. The Linux kernel supports a serial console speed of 1200240048009600192003840057600, and 115200 bits per second.

Since we are using a virtual serial console, a much higher baud rate of 115200 is recommended.

I've already set the baud speed to 115200 bits per second. Verify the serial port baud speed is the same as specified.

madhu@debian:~$ stty speed
115200

If you want to change the serial port speed, for example, to 9600 bps, do the following.

madhu@debian:~$ stty -F /dev/ttyS0 speed 9600
115200

madhu@debian:~$ stty speed
9600

To know which TTY you are attached to, run the tty command.

madhu@debian:~$ tty
/dev/ttyS0

5. Hot Plug/Unplug Memory and CPU

You can dynamically increase or decrease the memory and CPU while the guest virtual machine is running.

This enables you to improve a virtual machine's performance by allocating more resources to it only when critical applications are running and you cannot afford to shut down the virtual machine and face downtime.

Similarly, you can also free up the resources from the virtual machine to the host so that they can be used elsewhere.

To manage the resources of the virtual machine, first exit the serial console by pressing Ctrl + ]. If you used SSH to connect to the virtual machine, press Ctrl + d to disconnect.

Adding and removing memory:

First, determine the maximum memory and the memory currently in use in a virtual machine. This will serve as a baseline for your changes as well as verification.

$ sudo virsh dominfo debian-12-minimal | grep memory
Max memory: 6291456 KiB
Used memory: 2097152 KiB

As you can see, the maximum memory is set to 6 GiB, while the memory currently in use is 2 GiB.

To dynamically increase the memory of a running virtual machine, for example, to 4 GiB, use the following command.

$ sudo virsh setmem debian-12-minimal 4G --current

Verify the changes again.

$ sudo virsh dominfo debian-12-minimal | grep memory
Max memory: 6291456 KiB
Used memory:
4194304 KiB

As you can see, the current memory is set to 4 GiB. You can also use the same method to decrease memory.

When the guest is restarted, the memory will be reset back to 2 GiB. If you want the memory to be configured to 4 GiB upon boot permanently, you can use the following command on the host.

$ sudo virsh setmem debian-12-minimal 4G --config

Adding and removing virtual CPU:

Similar to memory, you can increase or decrease the virtual CPU count.

View the current state of the virtual CPUs in the targeted virtual machine.

$ sudo virsh vcpucount debian-12-minimal 
maximum config 3
maximum live 3
current config 1
current live 1

As you can see, the current CPU count is 1 and the maximum is 3.

To dynamically increase the virtual CPU count of a running virtual machine, for example, to 2, use the following command.

$ sudo virsh setvcpus debian-12-minimal 2 --live

Verify the changes again.

$ sudo virsh vcpucount debian-12-minimal 
maximum config 3
maximum live 3
current config 1
current live
2

As you can see, the current CPU count is set to 2. You can also use the same method to decrease the CPU count.

When the virtual machine is restarted, the CPU count is reset to 1. If you want the CPU to be permanently configured to 2 upon boot, run the following command on the host.

$ sudo virsh setvcpus debian-12-minimal 2 --config

You can now reconnect to the virtual machine and continue to use it with its newly optimized resource.

$ sudo virsh console debian-12-minimal

6. Add a Graphical Display for the Guest

A graphical display can also be added to the guest virtual machine. This allows you to use a graphical desktop environment in the guest virtual machine. For this, the host must also have some kind of desktop environment.

I'll add the SPICE protocol in conjunction with the VirtIO driver to provide remote access to the debian-12-minimal guest virtual machine via the VGA console. SPICE supports advanced features such as audio and USB device streaming, as well as enhanced graphics performance.

On the host, execute the following commands.

$ sudo virsh shutdown debian-12-minimal 

$ sudo virt-xml debian-12-minimal --add-device --graphics spice
$ sudo virt-xml debian-12-minimal --add-device --channel spicevmc
$ sudo virt-xml debian-12-minimal --edit --video model.type=virtio,clearxml=yes
$ sudo virt-xml debian-12-minimal --add-device --sound model=default

Now that you have added SPICE, you might want to install spice-vdagent package, which is a SPICE agent for Linux. This enables automatic adjustment of the X-session resolution as well as copy-and-paste support between the guest and host. This will only work if the active X-session is active.

Install spice-vdagent and reboot your Debian 12 guest virtual machine.

madhu@debian:~$ sudo apt update
madhu@debian:~$ sudo apt install spice-vdagent
madhu@debian:~$ sudo reboot

The command-line installation of a KVM Guest virtual machine is now complete. You can now shut down the Debian 12 guest.

From inside that guest.

madhu@debian:~$ sudo poweroff

Alternatively, from the host hypervisor.

$ sudo virsh shutdown debian-12-minimal

7. Conclusion

In this blog, you learned how to install a KVM guest OS from the command-line using the virt-install tool. Once the installation is complete, the next step is to learn how to administer KVM virtual machine using the virsh command-line tool.

Going forward, I will be writing articles on how to use the virsh command-line tool and also on how to take snapshots of virtual machines.

8. Watch on YouTube


Subscribe
Notify of
guest
2 Comments
Newest
Oldest
Inline Feedbacks
View all comments