The virtual machine networking configuration for routed mode on Hetzner, OVH, and Online.net servers is counterintuitive because you have networks that resemble this:
Host IP: 192.168.0.2
Host Netmask: 255.255.255.0 (/24)
Host Gateway: 192.168.0.1
Guest IP: 10.0.0.1
Guest Netmask: 255.255.255.255 (/32)
Guest Gateway: 192.168.0.1
Guest MAC: 02:00:00:01:02:03
The example above is just an illustration, not sample IP addresses you can expect from any of the aforementioned hosting providers.
Huh? What? How can you have a subnet of just one IP address (10.0.0.1/32
)? There's no room for a gateway! Why is the gateway on a very different subnet (192.168.0.0/24
)?
These are the questions that make Linux and Windows fail their networking sanity checks, since the networks make no sense to them. They think that the gateway would be unreachable.
Hetzner, OVH, and Online.net use some network trickery that make the gateway reachable anyway.
Fortunately, on both Linux and Windows, you can override the sanity checks and set the above interface configuration.
Possible Solutions
Static Addressing
This is the easiest to do. The most configuration you need to do on the host is to create a bridge.
Host
On Debian/Ubuntu, if your management/Internet interface is eth0
, you can edit /etc/network/interfaces
to have a bridge br0
like so:
auto eth0
iface eth0 inet manual
auto br0
iface br0 inet static
address 192.168.0.2 # Host IP
netmask 255.255.255.0 # Host Netmask
gateway 192.168.0.1 # Host Gateway
metric 0
bridge_ports eth0
bridge_stp on
bridge_fd 0
bridge_maxwait 0
Run sudo service networking restart
to make the bridged networking configuration take effect.
On RHEL/CentOS, if your management/Internet interface is eth0
, you can edit /etc/sysconfig/network-scripts/ifcfg-eth0
to use bridge br0
like so:
TYPE="Ethernet"
BOOTPROTO="none"
DEVICE="eth0"
ONBOOT="yes"
NM_CONTROLLED="no"
BRIDGE="br0"
Then create a new file /etc/sysconfig/network-scripts/ifcfg-br0
to configure the bridge:
DEVICE="br0"
BOOTPROTO="static"
IPADDR="192.168.0.2" # Host IP
NETMASK="255.255.255.0" # Host Netmask
GATEWAY="192.168.0.1" # Host Gateway
ONBOOT="yes"
TYPE="Bridge"
NM_CONTROLLED="no"
Run sudo service network restart
to make the bridged networking configuration take effect.
If you remain connected to your server, congrats, you've got a working bridge!
Hypervisor
On pure Xen xl (libxenlight), this is all you need to write for the virtual interface configuration:
vif=[ 'mac=02:00:00:01:02:03,bridge=br0' ]
Note that 02:00:00:01:02:03
is the MAC address that Hetzner, OVH, or Online.net gave you for the guest's network, and br0
is the bridge that we just configured above.
If you're using libvirt, inside the <devices>
tag, add this interface:
<interface type='bridge'>
<mac address='02:00:00:01:02:03'/>
<source bridge='br0'/>
</interface>
Once you have this virtual interface configured with the right MAC address and bridge, boot up your guest and connect to its console (xl console domU
, virsh console domU
, or attach to the guest's VNC session, if applicable).
Guest
Here comes the ugly part. It varies by operating system on how to override the networking sanity checks. I'll cover Debian/Ubuntu, RHEL/CentOS, and Microsoft Windows NT.
On Debian/Ubuntu, if the interface is called eth0
, write this into /etc/network/interfaces
:
auto eth0
iface eth0 inet static
address 10.0.0.1 # Guest IP
broadcast 10.0.0.1 # Guest IP
netmask 255.255.255.255
gateway 192.168.0.1 # Guest Gateway, a.k.a. Host Gateway
post-up route add 192.168.0.1 dev eth0
post-up route add default gw 192.168.0.1
pre-down route del 192.168.0.1 dev eth0
pre-down route del default gw 192.168.0.1
The post-up
and post-down
iproute2 commands tell the operating system to apply the gateway anyway, even though it's on a different subnet.
After running sudo service networking restart
, you should now be able to reach your guest through Guest IP 10.0.0.1
.
On RHEL/CentOS, if the interface is called eth0
, write this into /etc/sysconfig/network-scripts/ifcfg-eth0
:
DEVICE="eth0"
BOOTPROTO="none"
ONBOOT="yes"
USERCTL="no"
PEERDNS="yes"
TYPE="Ethernet"
NETMASK="255.255.255.255"
IPADDR="10.0.0.1" # Guest IP
GATEWAY="192.168.0.1" # Guest Gateway, a.k.a. Host Gateway
ARP="yes"
HWADDR="02:00:00:01:02:03" # Guest MAC
Then, write the following into /etc/sysconfig/network-scripts/route-eth0
:
192.168.0.1 dev eth0
default via 192.168.0.1 dev eth0
This file tells iproute2 to apply the gateway anyway, even though it's on a different subnet.
After running sudo service network restart
, you should now be able to reach your guest through Guest IP 10.0.0.1
.
On Microsoft Windows NT, go to Network Connections in Control Panel, right-click the interface, and click "Properties". Under the "Networking" tab, choose "Internet Protocol Version 4 (TCP/IPv4)", then click "Properties". Fill in the fields as shown:
When you click "OK", you'll get this warning:
Click "OK" to confirm that you want to use the gateway anyway.
After a few seconds, you should be able to reach your guest through Guest IP 10.0.0.1
.
DHCP Dynamic Addressing
Unfortunately, this is not possible. No DHCP server is going to assign you 10.0.0.1/32
and tell you the gateway is 192.168.0.1
, even if you somehow intercepted the guest's DHCPDISCOVER. And no DHCP client is going to accept this bizarre configuration.
You need a properly structured network with a gateway inside your subnet in order to set up DHCP. The only way to do this is to create a private network (172.16.0.0/12
) and do network address translation between your guest's private IP address (172.16.0.2
) and its public IP address (10.0.0.1
) via the gateway (172.16.0.1
).
Private Network and NAT
Although I've verified all the steps above, I never successfully created a one-to-one/basic NAT from private IPs to public IPs. Part of the reason is that there's a lot to do to build the networks.
Your network could look like this:
Guest Public IP: 10.0.0.1
Guest Private IP: 172.16.0.2
Guest Netmask: 255.240.0.0 (/12)
Guest Gateway: 172.16.0.1
The host would then forward traffic between Guest Public IP 10.0.0.1
and Guest Private IP 172.16.0.2
via Guest Gateway 172.16.0.1
.
OpenStack (which supports Xen via libvirt) could potentially provide this NAT setup as well as a private subnet DHCP server through its network abstraction, OpenStack Neutron, but setting up OpenStack itself is quite a hassle.
I was able to get a single-node OpenStack installation and Neutron private networks running for Nova instances/guests/servers, but I could not figure out how to NAT the private IP addresses (172.16.0.0/12
) to external network IP addresses (10.0.0.1/32
, 10.0.0.2/32
, and so on) because OpenStack doesn't support Hetzner's, OVH's, and Online.net's unusual networking structure for virtual machines out-of-the-box. This remains an unsolved problem.
Additional Resources
Do you want your VM to have a public IP address? – Daniel B – 2017-02-19T01:57:53.977
Yes I have a subnet of public ipv4 addresses – bobthemac – 2017-02-19T05:49:03.997
It's been a while since I had a subnet. With individual IPs, you can now use a self-service button in the Robot user interface to assign a different MAC address. Maybe you can do that with individual IPs from the subnet, too? – Daniel B – 2017-02-19T12:21:51.347
No for some reason they don't allow you to do that on subnets. I did check with support though as I have had individual IPs on my old box a few years ago and you could to the virtual MAC – bobthemac – 2017-02-19T13:03:01.220