Configure KVM Private NAT With Guest Gateway
This tutorial arose out of necessity. Hetzner only allows you a certain amount of "public" IPs to each of your dedicated servers. This means that if you follow the simple/traditional route of giving each of your guests their own public IP (like if you used DigitalOcean hosting etc), then you will quickly run out of IPs and won' be able to host very many services on your server.
What we need to do is create a private network for the majority of our guests to use, and set up a single guest as a gateway that they all connect to, in order to connect with the outside world. We will also be setting up a reverse proxy and port forwarding rules on this gateway so that our guests can be reached from the outside world, not just the other way around.
Steps
Create Private Network
The first thing we need to do is set up a private internal network that all of the guests will be connected to such that they can communicate with each other. This is unlike the default KVM network, which does not allow KVM guests to communicate with each other. This network will use the standard private IP address set, so we don't need to worry about running out of IP addresses.
Add/append this to your KVM host's network/interfaces file (don't change any existing blocks):
auto privatebr0
iface privatebr0 inet static
address 192.168.0.1
netmask 255.255.0.0
pre-up brctl addbr privatebr0
post-down brctl delbr privatebr0
Now use virsh to define the private network that relates to the block we just added to the interfaces file:
Now if you run
You should see the new network named privatenet
.
Name State Autostart Persistent
-----------------------------------------------
default active yes yes
privatenet active yes yes
Create NAT/Gateway Guest
Next, we need to create the NAT/gateway guest.
If you haven't already deployed a Debian guest to fulfill this role, do so now.
I will assume that they have already been set up against a normal bridged setup with a public IP address.
Run the following command to add a network interface to the guest that is connected to this new private network:
--live
part.
Edit the guest in order to see the mac addresses that are assigned to it. If you need to manually set one to a whitelisted MAC address, now is the time to do it.
Log into the guest
Use the following command to get details of your interfaces:
Make a note of the MAC address to interface name pairs. We need to make sure we use the name of the interface that is connected to the whitelisted MAC address, for the public IP, and the other interface name for the internal private network that the other KVM guests will be on.
Now, using the names of the networks, set your /etc/network/interfaces
file accordingly. Here is mine:
source-directory /etc/network/interfaces.d
auto enp0s2
allow-hotplug enp0s2
# Interface for public IP that can access the outside world
iface enp0s2 inet static
address xxx.xxx.xxx.xxx
netmask 255.255.255.255
point-to-point xxx.xxx.xxx.xxx
gateway xxx.xxx.xxx.xxx
dns-nameservers 8.8.8.8 8.8.4.4
# internal private network interface
auto enp1s0
iface enp1s0 inet static
address 192.168.0.1
netmask 255.255.0.0
gateway 192.168.0.1
dns-nameservers 8.8.8.8 8.8.4.4
Forwarding
We now need to configure the guest to allow forwarding of packets from the guests on the private network, as if they were this server, so they can get through the MAC address filtering.
First we need to tell your server to accept forwarding:
Edit the /etc/sysctl.conf
file
...and uncomment this line so there is no #
character:
#net.ipv4.ip_forward=1
IPTables
Now we need to set up iptables rules so that the server will forward packets. Whenever you wish to allow the outside world to gain access to one of your servers, you will need to tweak these rules to forward the relevant port. The only case where you wont need to do this is for websites with ports 80/443 because we will also set this server up as a reverse proxy later.
Create a file with the following contents (tweaking the variables as necessary), and save it somewhere like /root/import-iptables.sh
.
Make sure that file gets executed on boot, either by adding the relevant cron (e.g. @reboot
), or adding to your /etc/rc.local
file etc.
Reverse Proxy
Finally, port forwarding only helps us when we wish to provide services that use different ports. However, I find that most services are just websites that all want to use ports 80 and port 443. Thus we need to set up a reverse proxy. Luckily I already have a post for that, which you can use.
Other Guests
Make sure that your other guests have a single network interface, and they are configured to use the KVM private network we set up earlier.
Then be sure to assign them private static IPs. You will need to keep track of which IPs are already being used and assigned to which server. This is what you will need to set up your reverse proxy and port-forwarding rules against, otherwise we would have set up DHCP.
Below is an example /etc/network/interfaces
file of such a guest:
# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d
auto enp1s0
iface enp1s0 inet static
address 192.168.0.8
netmask 255.255.0.0
gateway 192.168.0.1
dns-nameservers 8.8.8.8 8.8.4.4
... and below is a netplan configuration for that guest (in case you are using Ubuntu etc)
References
Appendix
IPTables Reset Rules
If you ever mess up when setting up iptables, it's good to have this to hand to perform a reset.
First published: 19th July 2021