Port Forwarding from Host to Guest with libvirt 0.8.3 Using KVM on Ubuntu

The host has a single external IP available, so I set my KVM guests up with NAT.

How do I set up a port forwarding to forward some of the requests from the outside to the guests?

I couldn't find any documentation on this. The closest answer is probably this answer,but then it's also mentioned there is easier way to do this in libvirt 0.8.3. Does anyone know of a more current way to do this?


Solution 1:

Here is a better way to set up port forwarding, using a hook script (source).

In /etc/libvirt/hooks/qemu:

#!/bin/sh

GUEST_NAME=
HOST_PORT=
GUEST_IPADDR=
GUEST_PORT=

if [ "$1" = "$GUEST_NAME" ]; then
  if [ "$2" = start ]; then
    iptables -t nat -A PREROUTING -p tcp --dport "$HOST_PORT" \
         -j DNAT --to "$GUEST_IPADDR:$GUEST_PORT"
    iptables -I FORWARD -d "$GUEST_IPADDR/32" -p tcp -m state \
         --state NEW -m tcp --dport "$GUEST_PORT" -j ACCEPT
  elif [ "$2" = stopped ]; then
    iptables -t nat -D PREROUTING -p tcp --dport "$HOST_PORT" \
         -j DNAT --to "$GUEST_IPADDR:$GUEST_PORT"
    iptables -D FORWARD -d "$GUEST_IPADDR/32" -p tcp -m state \
         --state NEW -m tcp --dport "$GUEST_PORT" -j ACCEPT
  fi
fi

You should set the four variables at the top to fit your libvirt setup.

You will need to restart libvirt-bin, which on ubuntu is done with:

sudo sh -c 'service libvirt-bin stop; service libvirt-bin start'

then you will need to restart the guest. On Ubuntu, you will need to adjust /etc/apparmor.d/usr.sbin.libvirtd to allow the hook script to execute:

Next to

/usr/sbin/* PUx,

append

/etc/libvirt/hooks/* PUx,

Then reload apparmor:

sudo service apparmor reload

There's probably a way to autoconfigure $GUEST_IPADDR using virsh / dumpxml / iface-dumpxml, but I haven't found it. Alternatively, the IP can be set statically in the network xml: documentation.

As far as I can tell, network filters can only be used for restricting what happens on the virtual network, and they aren't useful for port forwarding.

Solution 2:

I'm in a similar situation. I have a Windows Server running in KVM in the private NATed network which is connected on the host via the interface virbr0. I want to do access the VM via remote desktop. So I have to forward the traffic to port 3389 (RDP) to the VM port 3389. I have achieved this with some iptable rules.

/sbin/iptables -t nat -A PREROUTING -p tcp -d HOST-IP --dport 3389 -j DNAT --to-destination VM-IP:3389

/sbin/iptables -I FORWARD -m state -d VM-NET/24 --state NEW,RELATED,ESTABLISHED -j ACCEPT

HOST-IP, VM-IP, and VM-NET have to be adopted of course. However messing with iptables and libvirt is tricky. Right now I'm searching for an solution to get internet access on my VM which I have lost due to messing with the iptable rules :-(