IPv6, Proxmox and OVH: A nightmare!

Today I pretty much spent my whole day trying to add IPv6 connectivity to my VMs and LXC containers hosted on an OVH (Soyoustart) server in France. This well-known ISP assigns you an entire /64 IPv6 subnet: great, one ‘d think, but there’s a glitch…

If you try and assign an IPv6 address to an LXC/VM with a virtual MAC address, OVH infrastructure will refuse to route it and you won’t get anywhere. That’s what I found out to be the case after some tests and some reading on the internet.

Uh.. The key is to create an additional internal bridge (we will call it vmbr1) and assign an IPv6 address to it. All our VMs/LXCs will connect to this bridge with their own IPv6 Global address and the bridge IPv6 address as a gateway. Using a clear replacement of the old ARP protocol – which doesn’t exist anymore in IPv6 – called proxy_ndp one host should be able to discover all the other hosts and connect to them.

We will end up with each VM/LXC having 1 Global IPv6 address, which can be routed globally and it is the equivalent of a public IPv4 address.

IPv6 and security (or Where’s NAT?)

NAT wasn’t indented as a security feature is the first place. With IPv6, since there are so many addresses, we don’t need NAT anymore and each device can have a public IP address. This is totally an advantage as Application Layer Gateways aren’t needed anymore.

Let’s go step by step now

IPv6 address list:

vmbr0 (external bridge) -> XXXX:XXXX:XXXX:XXZZ::1

vmbr1 (internal bridge) -> XXXX:XXXX:XXXX:XXZZ::2


Proxmox Host

We need to edit /etc/network/interfaces and replace XXXX:XXXX:XXXX:XXZZ with our /64 IPv6 subnet.

Important! When adding routes, note that the last 2 digits SHOULD be left out. This is because the mask changes to a /57

iface vmbr0 inet6 static
netmask 64
post-up /sbin/ip -f inet6 route add XXXX:XXXX:XXXX:XXff:ff:ff:ff:ff dev vmbr0
post-up /sbin/ip -f inet6 route add default via XXXX:XXXX:XXXX:XXff:ff:ff:ff:ff
pre-down /sbin/ip -f inet6 route del default via XXXX:XXXX:XXXX:XXff:ff:ff:ff:ff
pre-down /sbin/ip -f inet6 route del XXXX:XXXX:XXXX:XXff:ff:ff:ff:ff dev vmbr0

iface vmbr1 inet6 static
netmask 64
post-up echo 1 > /proc/sys/nXXXX:XXXX:XXXX:XXet/ipv6/conf/all/proxy_ndp
post-up echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
post-up echo 1 > /proc/sys/net/ipv6/conf/default/forwarding
post-up /sbin/ip -f inet6 route add XXXX:XXXX:XXXX:XXZZ::3/128 dev vmbr1
post-up /sbin/ip -f inet6 neigh add proxy XXXX:XXXX:XXXX:XXZZ::2 dev vmbr1
post-up /sbin/ip -f inet6 neigh add proxy XXXX:XXXX:XXXX:XXZZ::3 dev vmbr0

vmbr1 is our internal bridge, while vmbr0 (as per default) is connected to eth0 and it’s our external bridge.

Explanation: It’s important to understand what we are doing here: first of all we are setting up a route to our default gateway, this way the host can route traffic to IPv6 machines.

Next, we are assigning ::2 to our internal bridge, setting up the ARP equivalent, allowing forwarding so that ::3 can connect to external IPv6 hosts, adding a route to ::3 (the host now knows how to reach it) and setting up the Neighbor Discovery Protocol.

On the VM

We edit /etc/network/interfaces once again and we add:

iface eth0 inet6 static
netmask 128
post-up /sbin/ip -f inet6 route add XXXX:XXXX:XXXX:XXZZ::2 dev eth0
post-up /sbin/ip -f inet6 route add default via XXXX:XXXX:XXXX:XXZZ::2

This assigns the IPv6 address ::3 to eth0 and sets the bridge IPv6 address as the default router.


I’ll leave some links below: (they are all missing something)