a bit of a warning: the NAT fowarding script is a bit of hardcore kvm “hack” that might not work (kvm is under development), wish to kvm and virsh-manager developers: please please integrate an easy way (like in virtualbox) for

  1. direct (bridged) and
  2. NAT connecting VMs = making (for security reasons) only certain ports of the vm publicly available in virsh-manager
  3. thanks! 🙂

thanks to this excellent script it is now possible to nat-port forward multiple ports from:

[internet]<->port:host<->vm

thanks & great work all invovled 🙂

here is the script: etc_libvirt_hooks_qemu.txt

(and here an older backup of the same)

in NAT mode, the host firewall stands between the wild wild west inet and the guest vm.

in order to allow certain ports through (webserver: 80/443), a bit of config hazzle has to be done.

note: this article is a result of “quick note taking” process and is not of the quality, one would like to see and will have to be refined further, follow the instructions to install the script.

just ignore the rest and study the manual here: https://github.com/doccaz/kvm-scripts

and the admin-user should have no problems getting port-nat-forwarding to work 🙂

  1. give vm a fixed ip
    • this needs to be configured inside the vm, to not use dhcp but stick with a static ip
    • plus: via “virsh net-edit default” tell kvm that this vm will use that fixed ip
# how to nat host-port pass-through to kvm guest-vm
/etc/libvirt/hooks/qemu

https://github.com/doccaz/kvm-scripts

howto virsh set fixed ip

ssh into server and become root

su - root

download the qemu-hook-script and name it qemu

wget https://raw.githubusercontent.com/doccaz/kvm-scripts/master/qemu-hook-script -O qemu

copy into place

mv -v qemu /etc/libvirt/hooks/qemu
# what port of what vm (webserver3) shall be publicly accessible? (webserver usually: tcp@80, tcp@443)
# need to find out mac of webserver3
virsh dumpxml webserver3 | grep -i '<mac'
<mac address='52:54:00:4e:51:cf'/>
<host mac='52:54:00:4e:51:cf' name='webserver3' ip='192.168.122.204'/>

# show what vms have what dhcp asigned ip
virsh net-dhcp-leases default

Expiry Time MAC address Protocol IP address Hostname Client ID or DUID
--------------------------------------------------------------------------------------------------------------------------------------------------
2021-08-06 11:34:37 52:54:00:4e:51:cf ipv4 192.168.122.204/24 webserver3 ff:00:4e:51:cf:00:01:00:01:28:9a:76:3d:52:54:00:11:c1:e0

# (of course) make sure the webserver is working
# for example: generate test page within webserver3 like
echo "<h1>hello world</h1>" > /home/user/web/domain.com/index.html

asign fixed ip to webserver3:

which means: the kvm-dhcp server will know, this ip is taken and not re-assign it to other vms

# inside vm:
vim /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
# allow-hotplug enp1s0
# iface enp1s0 inet dhcp
auto enp1s0
iface enp1s0 inet static
address 192.168.122.204
netmask 255.255.255.0
gateway 192.168.122.1

# on kvm-host-sever: edit the kvm networking config file
# to announce that those VMs will use a fixed ip
virsh net-edit default
<network>
<name>default</name>
<uuid>82bac856-ef6f-4777-8c29-e296483b4856</uuid>
<forward mode='nat'/>
<bridge name='virbr0' stp='on' delay='0'/>
<mac address='52:54:00:eb:93:ad'/>
<ip address='192.168.122.1' netmask='255.255.255.0'>
<dhcp>
<range start='192.168.122.2' end='192.168.122.254'/>
   <host mac='52:54:00:4e:51:cf' name='vm1' ip='192.168.122.204'/>
   <host mac='52:54:00:52:3e:f6' name='vm2' ip='192.168.122.166'/>
   <host mac='52:54:00:b0:7b:b9' name='vm3' ip='192.168.122.203'/>
</dhcp>
</ip>
</network>

# to make the changes of net-edit active
virsh net-destroy default && virsh net-start default
# now add admin-unser-defined rules at the end of config file like
vim /etc/libvirt/hooks/qemu
### webserver3:
addForward      webserver3           enp7s0          public.ip.of.hostsrv    80              virbr0          192.168.122.204  80              tcp
addForward      webserver3           enp7s0          public.ip.of.hostsrv    443             virbr0          192.168.122.204  443             tcp


# every time changes are made to the above qemu networking config file
# 1) all vms need to be shut down
# 2) networking needs to be restarted with a special script
for i in $(virsh list | grep running | awk '{print $2}'); do virsh shutdown $i; done

# restart the virtual networking / to make changes active
virsh net-destroy default; virsh net-start default; 

# download and install the networking-restart script
wget https://raw.githubusercontent.com/doccaz/kvm-scripts/master/kvm-network-restart

# install it
mv -v kvm-network-restart /usr/sbin/kvm-network-restart
chmod +x /usr/sbin/kvm-network-restart

# run it to start network called 'default'
/usr/sbin/kvm-network-restart default
# now start all vms and test if ports are publicly available :)

liked this article?

  • only together we can create a truly free world
  • plz support dwaves to keep it up & running!
  • (yes the info on the internet is (mostly) free but beer is still not free (still have to work on that))
  • really really hate advertisement
  • contribute: whenever a solution was found, blog about it for others to find!
  • talk about, recommend & link to this blog and articles
  • thanks to all who contribute!
admin