How to install KVM on CentOS 7 / RHEL 7 Headless Server

How do I install and configure KVM (Kernel-based Virtual Machine) on a CentOS 7 or RHEL (Red Hat Enterprise Linux) 7 server? How can I setup KVM on a CentOS 7 and use cloud images/cloud-init for installing guest VM?

Tutorial details
Difficulty level Advanced
Root privileges Yes
Requirements KVM and CentOS/RHEL 7 Linux server
Est. reading time 8 minutes
Kernel-based Virtual Machine (KVM) is virtualization software for CentOS or RHEL 7. KVM turn your server into a hypervisor. This page shows how to setup and manage a virtualized environment with KVM in CentOS 7 or RHEL 7. It also described how to install and administer Virtual Machines (VMs) on a physical server using the CLI. Make sure that Virtualization Technology (VT) is enabled in your server’s BIOS. You can also run the following command to test if CPU Support Intel VT and AMD-V Virtualization tech:
$ lscpu | grep Virtualization
Virtualization: VT-x

Follow installation steps of KVM on CentOS 7/RHEL 7 headless sever

Step 1: Install kvm

Type the following yum command:
# yum install qemu-kvm libvirt libvirt-python libguestfs-tools virt-install
How to install KVM on CentOS 7 RHEL 7 Headless Server
Start the libvirtd service:
# systemctl enable libvirtd
# systemctl start libvirtd

Step 2: Verify kvm installation

Make sure KVM module loaded using lsmod command and grep command:
# lsmod | grep -i kvm

Step 3: Configure bridged networking

By default dhcpd based network bridge configured by libvirtd. You can verify that with the following commands:
# brctl show
# virsh net-list

All VMs (guest machine) only have network access to other VMs on the same server. A private network created for you. Verify it:
# virsh net-dumpxml default
If you want your VMs avilable to other servers on your LAN, setup a a network bridge on the server that connected to the your LAN. Update your nic config file such as ifcfg-enp3s0 or em1:
# vi /etc/sysconfig/network-scripts/enp3s0
Add line:


Save and close the file in vi. Edit /etc/sysconfig/network-scripts/ifcfg-br0 and add:
# vi /etc/sysconfig/network-scripts/ifcfg-br0
Append the following:

# I am getting ip from DHCP server #

Restart the networking service (warning ssh command will disconnect, it is better to reboot the box):
# systemctl restart NetworkManager
Verify it with brctl command:
# brctl show

Step 4: Create your first virtual machine

I am going to create a CentOS 7.x VM. First, grab CentOS 7.x latest ISO image using the wget command:
# cd /var/lib/libvirt/boot/
# wget

Verify ISO images:
# wget
# sha256sum -c sha256sum.txt

Create CentOS 7.x VM

In this example, I’m creating CentOS 7.x VM with 2GB RAM, 2 CPU core, 1 nics and 40GB disk space, enter:
# virt-install \
--virt-type=kvm \
--name centos7 \
--ram 2048 \
--vcpus=1 \
--os-variant=centos7.0 \
--cdrom=/var/lib/libvirt/boot/CentOS-7-x86_64-Minimal-1708.iso \
--network=bridge=br0,model=virtio \
--graphics vnc \
--disk path=/var/lib/libvirt/images/centos7.qcow2,size=40,bus=virtio,format=qcow2

To configure vnc login from another terminal over ssh and type:
# virsh dumpxml centos7 | grep vnc
<graphics type='vnc' port='5901' autoport='yes' listen=''>

Please note down the port value (i.e. 5901). You need to use an SSH client to setup tunnel and a VNC client to access the remote vnc server. Type the following SSH port forwarding command from your client/desktop/macbook pro system:
$ ssh -L 5901:
Once you have ssh tunnel established, you can point your VNC client at your own (localhost) address and port 5901 as follows:

You should see CentOS Linux 7 guest installation screen as follows:

Now just follow on screen instructions and install CentOS 7. Once installed, go ahead and click the reboot button. The remote server closed the connection to our VNC client. You can reconnect via KVM client to configure the rest of the server including SSH based session or firewall.

How to create RHEL 7.x VM

Make sure you have rhel-server-7.3-x86_64-dvd.iso stored locally. In this example, I’m creating RHEL 7.x VM with 2GB RAM, 2 CPU core, 1 nic and 40GB disk space, enter:
# virt-install \
--virt-type=kvm \
--name rhel7 \
--memory=2048,maxmemory=4096 \
--vcpus=2 \
--os-variant=rhel7.3 \
--cdrom=/var/lib/libvirt/boot/rhel-server-7.3-x86_64-dvd.iso \
--network=bridge=virbr0,model=virtio \
--graphics vnc \
--disk path=/var/lib/libvirt/images/rhel7.qcow2,size=40,bus=virtio,format=qcow2

To configure vnc login from another terminal over ssh and type:
$ sudo virsh dumpxml rhel7 | grep vnc
<graphics type='vnc' port='5904' autoport='yes' listen=''>

Please note down the port value (i.e. 5904). You need to use an SSH client to setup tunnel and a VNC client to access the remote vnc server. Type the following SSH port forwarding command from your client/desktop:
$ ssh -L 5904:
Once you have ssh tunnel established, you can point your VNC client at your own (localhost) address and port 5904 to continue with RHEL 7.x installation.

Step 5: Using cloud images

The above installation method is okay for learning purpose or a single VM. Do you need to deploy lots of VMs? Try cloud images. You can modify pre built cloud images as per your needs. For example, add users, ssh keys, setup time zone, and more using Cloud-init which is the defacto multi-distribution package that handles early initialization of a cloud instance. Let us see how to create CentOS 7 vm with 1024MB ram, 20GB disk space, and 1 vCPU.

Grab CentOS 7 cloud image

# cd /var/lib/libvirt/boot
# wget

Create required directories

# D=/var/lib/libvirt/images
# VM=centos7-vm1 ## vm name ##
# mkdir -vp $D/$VM
mkdir: created directory '/var/lib/libvirt/images/centos7-vm1'

Create meta-data file

# cd $D/$VM
# vi meta-data

Append the following:

instance-id: centos7-vm1
local-hostname: centos7-vm1

Crete user-data file

I am going to login into VM using ssh keys. So make sure you have ssh-keys in place:
# ssh-keygen -t ed25519 -C "VM Login ssh key"

See “How To Setup SSH Keys on a Linux / Unix System” for more info. Edit user-data as follows:
# cd $D/$VM
# vi user-data

Add as follows (replace hostname, users, ssh-authorized-keys as per your setup):

# Hostname management
preserve_hostname: False
hostname: centos7-vm1
# Users
    - default
    - name: vivek
      groups: ['wheel']
      shell: /bin/bash
      sudo: ALL=(ALL) NOPASSWD:ALL
        - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIMP3MOF2ot8MOdNXCpHem0e2Wemg4nNmL2Tio4Ik1JY VM Login ssh key
# Configure where output will go
  all: ">> /var/log/cloud-init.log"
# configure interaction with ssh server
ssh_genkeytypes: ['ed25519', 'rsa']
# Install my public ssh key to the first user-defined user configured
# in cloud.cfg in the template (which is centos for CentOS cloud images)
  - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIMP3MOF2ot8MOdNXCpHem0e2Wemg4nNmL2Tio4Ik1JY VM Login ssh key
# set timezone for VM
timezone: Asia/Kolkata
# Remove cloud-init 
  - systemctl stop network && systemctl start network
  - yum -y remove cloud-init

Copy cloud image

# cd $D/$VM
# cp /var/lib/libvirt/boot/CentOS-7-x86_64-GenericCloud.qcow2 $VM.qcow2

Create 20GB disk image

# cd $D/$VM
# export LIBGUESTFS_BACKEND=direct
# qemu-img create -f qcow2 -o preallocation=metadata $ 20G
# virt-resize --quiet --expand /dev/sda1 $VM.qcow2 $

Overwrite it resized image:
# cd $D/$VM
# mv $ $VM.qcow2

Creating a cloud-init ISO

# mkisofs -o $VM-cidata.iso -V cidata -J -r user-data meta-data

Creating a pool

# virsh pool-create-as --name $VM --type dir --target $D/$VM
Pool centos7-vm1 created

Installing a CentOS 7 VM

# cd $D/$VM
# virt-install --import --name $VM \
--memory 1024 --vcpus 1 --cpu host \
--disk $VM.qcow2,format=qcow2,bus=virtio \
--disk $VM-cidata.iso,device=cdrom \
--network bridge=virbr0,model=virtio \
--os-type=linux \
--os-variant=centos7.0 \
--graphics spice \

Delete unwanted files:
# cd $D/$VM
# virsh change-media $VM hda --eject --config
# rm meta-data user-data centos7-vm1-cidata.iso

Find out IP address of KVM VM (dhcp address)

# virsh net-dhcp-leases default

Log in to your VM

Use ssh command:
# ssh vivek@

Useful commands

Let us see some useful commands for managing VMs.

List all VMs

# virsh list --all

Get VM info

# virsh dominfo vmName
# virsh dominfo centos7-vm1

Stop/shutdown a VM

# virsh shutdown centos7-vm1

Start VM

# virsh start centos7-vm1

Mark VM for autostart at boot time

# virsh autostart centos7-vm1

Reboot (soft & safe reboot) VM

# virsh reboot centos7-vm1
Reset (hard reset/not safe) VM
# virsh reset centos7-vm1

Delete VM

# virsh shutdown centos7-vm1
# virsh undefine centos7-vm1
# virsh pool-destroy centos7-vm1
# D=/var/lib/libvirt/images
# VM=centos7-vm1
# rm -ri $D/$VM

To see a complete list of virsh command type
# virsh help | less
# virsh help | grep reboot

A note about virt-builder

One can build virtual machine images quickly on a CentOS 7 using virt-builder command.

List VM images

virt-builder --list
virt-builder --list | grep -i fedora
virt-builder --list | grep -i debian
virt-builder --list | grep -i ubuntu
virt-builder --list | grep -i freebsd

Build Ubuntu 16.04 LTS vm

# virt-builder ubuntu-16.04 \
--size=20G --format qcow2 -o /var/lib/libvirt/images/ncbz01-disk01.qcow2 \
--hostname ncbz01 --network --timezone Asia/Kolkata \
--firstboot-command "dpkg-reconfigure openssh-server" \
--edit '/etc/default/grub:
s/^GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT="console=tty0 console=ttyS0,115200n8"/' \
--run-command update-grub

Sample outputs (note it will display random root password on screen):

[   3.9] Downloading:
######################################################################## 100.0%
[ 121.7] Planning how to build this image
[ 121.7] Uncompressing
[ 126.5] Resizing (using virt-resize) to expand the disk to 20.0G
[ 142.1] Opening the new disk
[ 143.8] Setting a random seed
[ 143.8] Setting the machine ID in /etc/machine-id
[ 143.8] Setting the hostname: ncbz01
[ 144.3] Setting the timezone: Asia/Kolkata
[ 144.3] Setting passwords
virt-builder: Setting random password of root to 1KTLsuVx14k989eq
[ 144.9] Finishing off
                   Output file: /var/lib/libvirt/images/ncbz01-disk01.qcow2
                   Output size: 20.0G
                 Output format: qcow2
            Total usable space: 18.6G
                    Free space: 17.7G (94%)

Now image has been built. Let us install VM:
# virt-install --import --name ncbz01 \
--ram 2048 \
--vcpu 2 \
--disk path=/var/lib/libvirt/images/ncbz01-disk01.qcow2,format=qcow2 \
--os-variant ubuntu17.04 \
--network=bridge=virbr0,model=virtio \

Start it:
# virsh start ncbz01
Login into it:
# virsh console ncbz01

🐧 Get the latest tutorials on Linux, Open Source & DevOps via RSS feed or Weekly email newsletter.

🐧 6 comments so far... add one

CategoryList of Unix and Linux commands
Disk space analyzersdf ncdu pydf
File Managementcat cp mkdir tree
FirewallAlpine Awall CentOS 8 OpenSUSE RHEL 8 Ubuntu 16.04 Ubuntu 18.04 Ubuntu 20.04
Network UtilitiesNetHogs dig host ip nmap
OpenVPNCentOS 7 CentOS 8 Debian 10 Debian 8/9 Ubuntu 18.04 Ubuntu 20.04
Package Managerapk apt
Processes Managementbg chroot cron disown fg jobs killall kill pidof pstree pwdx time
Searchinggrep whereis which
User Informationgroups id lastcomm last lid/libuser-lid logname members users whoami who w
WireGuard VPNAlpine CentOS 8 Debian 10 Firewall Ubuntu 20.04
6 comments… add one
  • Ujulu Aug 31, 2020 @ 15:02

    Very nice and very helpful. Thanks for sharing and keep it up.

  • hay day Nov 13, 2020 @ 5:30

    I think you are helpfull more than my expectation at the start of reading

  • El Barouf Jan 5, 2021 @ 5:26

    Thanks for the step by step guide. The only issue I see…. is that even with the ssh keys copied there (I first tried 2), none of the machines can connect with that user and key. It is asking me to provide a password…. which isn’t set. :-/
    Any way around this?

  • George Hwa May 5, 2021 @ 2:21

    I’m bit confused with “br0” and “virbr0”. Do they refer to the same?

    • 🐧 Vivek Gite May 5, 2021 @ 12:20
      • br0 – Interface created as per your needs and connected directly to your LAN. Can get IP info from the DHCP server hosted in your LAN and connect to the Internet directly using your WAN router.
      • virbr0 – Interface created by default by installer. Only gives IP info via hosted DHCP on the same machine. Connects to the Internet using that server’s NAT.

Leave a Reply

Your email address will not be published.

Use HTML <pre>...</pre> for code samples. Still have questions? Post it on our forum