Port forward from KVM host to guests

I need help with the Firewall on my homelab server. I’ve been trying to set up a port forward that forwards traffic from 10.0.0.1:3000 to 192.168.122.2:3000. Specifically, the 10.0.0.1 host is the other end of a Wireguard tunnel whose interface is named VPS_Tunnel. It’s on the 10.0.0.0/30 subnet. The other IP address is the address of a libvirt guest using the default libvirt network. My homelab server runs RHEL, so I’ve been trying to accomplish this with Firewalld to no avail. Then I’ve messed with IPTables directly, and I haven’t seemed to locked myself out so I guess that’s a good thing, but it’s really sketchy for me messing with IPTables since I am generally less familiar with it than I am with Firewalld. Idk if this is of any use:

~ # iptables -L -n -v --line-numbers                                                                          130 ↵ root@GlaedrServer
Chain INPUT (policy ACCEPT 110K packets, 9027K bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1     110K 9030K LIBVIRT_INP  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1      107 19235 LIBVIRT_FWX  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
2      107 19235 LIBVIRT_FWI  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
3       53  7187 LIBVIRT_FWO  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
4        0     0 ACCEPT     tcp  --  VPS_Tunnel virbr0  0.0.0.0/0            0.0.0.0/0            tcp dpt:3000
5        0     0 ACCEPT     tcp  --  virbr0 VPS_Tunnel  0.0.0.0/0            0.0.0.0/0            tcp spt:3000 state RELATED,ESTABLISHED

Chain OUTPUT (policy ACCEPT 127K packets, 21M bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1     127K   21M LIBVIRT_OUT  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain LIBVIRT_FWI (1 references)
num   pkts bytes target     prot opt in     out     source               destination         
1        0     0 REJECT     all  --  *      virbr1  0.0.0.0/0            0.0.0.0/0            reject-with icmp-port-unreachable
2       54 12048 ACCEPT     all  --  *      virbr0  0.0.0.0/0            192.168.122.0/24     ctstate RELATED,ESTABLISHED
3        0     0 REJECT     all  --  *      virbr0  0.0.0.0/0            0.0.0.0/0            reject-with icmp-port-unreachable

Chain LIBVIRT_FWO (1 references)
num   pkts bytes target     prot opt in     out     source               destination         
1        0     0 REJECT     all  --  virbr1 *       0.0.0.0/0            0.0.0.0/0            reject-with icmp-port-unreachable
2       53  7187 ACCEPT     all  --  virbr0 *       192.168.122.0/24     0.0.0.0/0           
3        0     0 REJECT     all  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            reject-with icmp-port-unreachable

Chain LIBVIRT_FWX (1 references)
num   pkts bytes target     prot opt in     out     source               destination         
1        0     0 ACCEPT     all  --  virbr1 virbr1  0.0.0.0/0            0.0.0.0/0           
2        0     0 ACCEPT     all  --  virbr0 virbr0  0.0.0.0/0            0.0.0.0/0           

Chain LIBVIRT_INP (1 references)
num   pkts bytes target     prot opt in     out     source               destination         
1        0     0 ACCEPT     udp  --  virbr1 *       0.0.0.0/0            0.0.0.0/0            udp dpt:53
2        0     0 ACCEPT     tcp  --  virbr1 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:53
3        0     0 ACCEPT     udp  --  virbr1 *       0.0.0.0/0            0.0.0.0/0            udp dpt:67
4        0     0 ACCEPT     tcp  --  virbr1 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:67
5       33  2348 ACCEPT     udp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            udp dpt:53
6        0     0 ACCEPT     tcp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:53
7        0     0 ACCEPT     udp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            udp dpt:67
8        0     0 ACCEPT     tcp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:67

Chain LIBVIRT_OUT (1 references)
num   pkts bytes target     prot opt in     out     source               destination         
1        0     0 ACCEPT     udp  --  *      virbr1  0.0.0.0/0            0.0.0.0/0            udp dpt:53
2        0     0 ACCEPT     tcp  --  *      virbr1  0.0.0.0/0            0.0.0.0/0            tcp dpt:53
3        0     0 ACCEPT     udp  --  *      virbr1  0.0.0.0/0            0.0.0.0/0            udp dpt:68
4        0     0 ACCEPT     tcp  --  *      virbr1  0.0.0.0/0            0.0.0.0/0            tcp dpt:68
5        0     0 ACCEPT     udp  --  *      virbr0  0.0.0.0/0            0.0.0.0/0            udp dpt:53
6        0     0 ACCEPT     tcp  --  *      virbr0  0.0.0.0/0            0.0.0.0/0            tcp dpt:53
7        0     0 ACCEPT     udp  --  *      virbr0  0.0.0.0/0            0.0.0.0/0            udp dpt:68
8        0     0 ACCEPT     tcp  --  *      virbr0  0.0.0.0/0            0.0.0.0/0            tcp dpt:68

It takes a little work to get this going. First you need to make sure your system is allowed to route by setting a value in /proc/sys/net/ipv4/ip_forward. I think the best way to do this is to set this part up with the network interface itself (on Debian that’s in /etc/network/interfaces). I add this to my interface:

post-up echo 1 > /proc/sys/net/ipv4/ip_forward
post-up iptables -t nat -A POSTROUTING -s "$private_net" -o $private_int -j MASQUERADE

These lines basically tell the machine “I’m going to behave like a router”—forward traffic and masquerade as another address.

Then the syntax for a port forward for your case would be something like this:

iptables -t nat -A PREROUTING -i $public_int -p tcp --dport 3000 -j DNAT --to 192.168.122.2:3000
1 Like

/etc/network/interfaces seems to be a debian only thing. I didn’t have much time to try and find how to do that on RHEL before work, though.

Yeah, the different distros put these things in different places. If you do a search for “rhel router” you should find the equivalents.