LowEndBox - Cheap VPS, Hosting and Dedicated Server Deals

More Home Made Qemu KVM Recipes! — Give Each VM Its Own IP Address!


KVM logoPreviously we made KVM VPses with Qemu’s default slirp networking. This time we will set up networking with Qemu so each Virtual Machine can have its own IP address. With slirp, we didn’t have to touch networking, because slirp automatically connects using its hosts’s IP address.

Here we are going to assume that our machine has a routed subnet of IP addresses and a bridge. From our subnet we can assign and configure IP addresses for each VM we make. If we don’t already have extra IP addresses, we need to get them, usually from our provider. If we don’t already have a bridge configured, Linux-KVM.org has a great tutorial. The Linux-KVM.org tutorial also covers the needed qemu-ifup script.

The approach used here is intended to be mostly independent of Linux Distribution software package systems and networking configuration utilities. The approach here also uses basic, raw qemu, with none of the excellent libraries and utilities which commonly are used to help configure Qemu KVM. Obviously, our approach here is mostly for Low End LOLs and for studying how Qemu works. It’s not for real life in production. It’s a work in pregress. The approach here should work on a VPS, on a dedicated server, or on a local machine running most Linux distributions.


From Mason Rowe’s Yabs Script

We might want to check if we have enabled hardware virtualization support. Here’s a script to check:

root@debian:~# cat cpu-virt.sh
# From https://github.com/masonr/yet-another-bench-script/blob/master/yabs.sh
# Lines 210-212
# Thanks to Mason and yabs developers!

CPU_VIRT=$(cat /proc/cpuinfo | grep ‘vmx\|svm’)
[[ -z “$CPU_VIRT” ]] && CPU_VIRT=”\xE2\x9D\x8C Disabled” || CPU_VIRT=”\xE2\x9C\x94 Enabled”
echo -e “VM-x/AMD-V : $CPU_VIRT”


Libvirt includes a KVM environment validation utility at libvirt/tools/virt-host-validate-qemu.c

Libvirt is beyond the scope here, but, if you want to see a cool use of virt-host-validate, please take a look at Dmitrii Shcherbakov’s tutorial on running KVM inside LXC.

Install Or Compile Qemu

If Qemu is not already installed, use your distribution’s package system to install it. Alternatively, compile Qemu following the instructions on Qemu.org’s Download page. Qemu.org’s build instructions also are mentioned in a previous post on MIT’s free online Operating Systems course.

Make A Directory For The Virtual Machine

We’re going to call this VM vm206, so let’s make a directory for it.

tom@darkstar:~$ mkdir vm206
tom@darkstar:~$ cd vm206/

Download And Validate An Operating System Image

Get An Image

tom@darkstar:~$ wget https://cloud.debian.org/images/cloud/sid/daily/latest/debian-sid-nocloud-amd64-daily.qcow2

[ . . . ]


Get The Checksums

tom@darkstar:~/vm206$ wget https://cloud.debian.org/images/cloud/sid/daily/latest/SHA512SUMS

Verify The Image

tom@darkstar:~/vm206$ sha512sum --ignore-missing -c SHA512SUMS
debian-sid-nocloud-amd64-daily.qcow2: OK

Please verify prior to booting and running an image since booting and running an image changes it.

Enable Revert

Let’s copy the image so we can revert to the original.

tom@darkstar:~/vm206$ cp debian-sid-nocloud-amd64-daily.qcow2 vm206.qcow2

Resize The Image

The original downloaded image has a virtual size of 2 GiB:

tom@darkstar:~/vm206$ qemu-img info vm206.qcow2
image: vm206.qcow2
file format: qcow2
virtual size: 2 GiB (2147483648 bytes)
disk size: 864 MiB
cluster_size: 65536
Format specific information:
compat: 1.1
compression type: zlib
lazy refcounts: false
refcount bits: 16
corrupt: false
extended l2: false

Let’s resize the image:

tom@darkstar:~/vm206$ qemu-img resize vm206.qcow2 +48G
Image resized.

Now we have a virtual size of 50 GiB:

tom@darkstar:~/vm206$ qemu-img resize vm206.qcow2 +48G
Image resized.
tom@darkstar:~/vm206$ qemu-img info vm206.qcow2
image: vm206.qcow2
file format: qcow2
virtual size: 50 GiB (53687091200 bytes)
disk size: 864 MiB
cluster_size: 65536
Format specific information:
compat: 1.1
compression type: zlib
lazy refcounts: false
refcount bits: 16
corrupt: false
extended l2: false

We see inconsistent results with this resizing procedure. As shown above, resizing appears to succeed on the node. However, sometimes the VM boots with the internal partition scheme seeming to recognize the resize, and sometimes not. Note that virt-resize is not yet installed on Darkstar. Alternative procedures include (1) attaching a second qcow2 file for user data or (2) not using the nocloud image and, instead, installing from Debian’s netinst.iso on a larger qcow2 file.

Script To Start The Virtual Machine

We’re going to start vm206 with this script:

tom@darkstar:~/vm206$ cat start-qemu-206.sh
# Start VM on IP 206

# Run this script inside tmux

# Add route for IP 206
ip route add dev br0

# Start qemu

/usr/local/bin/qemu-system-x86_64 \
-cpu host -smp sockets=1,cores=8,maxcpus=8 \
-enable-kvm \
-nographic \
-m 8192 \
-drive file=/home/tom/vm206/vm206.qcow2,if=virtio \
-netdev tap,id=mynet206,ifname=tap206,script=/root/qemu-ifup.sh,downscript="" \
-device virtio-net,netdev=mynet206,mac=DE:AD:00:BE:EE:06

Use The Script To Start The VM Inside Tmux

tom@darkstar:~/vm206$ tmux
tom@darkstar:~/vm206$ sudo ./start-qemu-206.sh

[ . . . ]

[FAILED] Failed to start OpenBSD Secure Shell server.

[ . . . ]

Debian GNU/Linux bookworm/sid localhost ttyS0

localhost login: root
Linux localhost 5.17.0-3-amd64 #1 SMP PREEMPT Debian 5.17.11-1 (2022-05-26) x4

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.

The VM boots with the sshd server having failed and with no networking.

root@localhost:~# ping -c 2 www.google.com
ping: www.google.com: Temporary failure in name resolution
root@localhost:~# ping -c 2
ping: connect: Network is unreachable
root@localhost:~# ping6 -c 2 2602:ffc5:105:40f::202
ping6: connect: Network is unreachable

Networking Inside the VM

Let’s add networking inside the VM.

Here are commands to start IPv4 and IPv6:

ip address add dev enp0s3
ip route add dev enp0s3
ip route add default via dev ens3
ip -6 address add 2602:ffc5:105:40f::206/64 dev enp0s3
ip -6 route add 2602:ffc5:105:40f::1 dev enp0s3
ip -6 route add default via 2602:ffc5:105:40f::1 dev enp0s3

The network commands could be put into a script. I hear that it’s still possible to enable rc.local on Debian. Placing the script in rc.local will enable the script to run automagically during rebooting. We have this set up and working on another VM.


On this Debian VM /etc/resolv.conf is a symlink to /run/systemd/resolve/resolv.conf.

Let’s put Hurricane Electric’s resolver IP addresses in /etc/resolv.conf.

root@localhost:~# unlink /etc/resolv.conf
root@localhost:~# echo nameserver > /etc/resolv.conf
root@localhost:~# echo nameserver 2001:470:20::2 >> /etc/resolv.conf

Looks like DNS and both IPv4 and IPv6 are working:

root@localhost:~# ping -c 2 lowendbox.com
PING lowendbox.com(2606:4700:20::681a:1d8 (2606:4700:20::681a:1d8)) 56 data bs
64 bytes from 2606:4700:20::681a:1d8 (2606:4700:20::681a:1d8): icmp_seq=1 ttls
64 bytes from 2606:4700:20::681a:1d8 (2606:4700:20::681a:1d8): icmp_seq=2 ttls

--- lowendbox.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 25.972/25.988/26.005/0.016 ms
root@localhost:~# ping -4 -c 2 lowendbox.com
PING ( 56(84) bytes of data.
64 bytes from ( icmp_seq=1 ttl=58 time=21.6 ms
64 bytes from ( icmp_seq=2 ttl=58 time=21.6 ms

--- ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 21.553/21.568/21.583/0.015 ms

Looks like we have the expected IP addresses:

root@localhost:~# curl icanhazip.com
root@localhost:~# curl -4 icanhazip.com

Install Host SSL Certificates

Remember the OpenSSH server failed? That’s because it doesn’t have any host keys. Let’s fix that.

root@localhost:~# apt-get update
Get:1 http://deb.debian.org/debian sid InRelease [165 kB]
Get:2 http://deb.debian.org/debian sid/main Sources [9744 kB]
Get:3 http://deb.debian.org/debian sid/main amd64 Packages [9204 kB]
Get:4 http://deb.debian.org/debian sid/main Translation-en [6820 kB]
Fetched 25.9 MB in 7s (3779 kB/s)
Reading package lists... Done
root@localhost:~# apt-get upgrade
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Calculating upgrade... Done
The following packages will be upgraded:
cloud-guest-utils cloud-image-utils cloud-utils libnss-resolve
libpam-systemd libsystemd0 libudev1 systemd systemd-sysv udev
10 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 7599 kB of archives.
After this operation, 13.3 kB of additional disk space will be used.
Do you want to continue? [Y/n]

[ . . . ]

root@localhost:~# dpkg-reconfigure openssh-server

[ . . . ]

Creating SSH2 ED25519 key; this may take some time ...

[ . . . ]

root@localhost:~# systemctl status sshd
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: e>
Active: active (running) since Sat 2022-06-04 03:14:27 UTC; 1min 57s ago

[ . . . ]


If we didn’t want to use dpkg-reconfigure, ssh-keygen -A might work. Please see How To: Ubuntu / Debian Linux Regenerate OpenSSH Host Keys

Add Authorized Keys

root@localhost:~# mkdir .ssh
root@localhost:~# chmod 700 .ssh/
root@localhost:~# echo ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILySvSdulbZ4XG4K333YOoFbcwoo6ythPBOf175OIBfA chronos@localhost > .ssh/authorized_keys
root@localhost:~# chmod 600 .ssh/authorized_keys

Login via SSH

Login via SSH

How To Quit

To exit tmux while leaving the VM running, type “Ctrl-b” then “d”.
To re-enter tmux and the already running VPS:

tmux attach

To stop the VM and quit tmux:

shutdown -h now

Type “exit” when the command prompt returns following VM shutdown.

Additional Resources

A really helpful resource for me when I was first trying KVM tricks was Linux-KVM.org’s Network Configuration page.

Maybe the world’s most thorough qemu tutorial is from Dongli Zhang.


From our previous post we have available three ways to use qemu’s default networking tool, slirp. Now we have explored making KVM virtual machines with their own individual IP addresses.

Have fun on the Low End! 💖

No Comments

    Leave a Reply

    Some notes on commenting on LowEndBox:

    • Do not use LowEndBox for support issues. Go to your hosting provider and issue a ticket there. Coming here saying "my VPS is down, what do I do?!" will only have your comments removed.
    • Akismet is used for spam detection. Some comments may be held temporarily for manual approval.
    • Use <pre>...</pre> to quote the output from your terminal/console, or consider using a pastebin service.

    Your email address will not be published. Required fields are marked *