I'm trying to set up a WireGuard VPN with IPv6 only through which I (a) want to route all traffic and (b) with a server that is accessible from the internet. Since I couldn't even get (a) to work, I'll just try to get that to work, (b) is just for context.

I have a VPS with a globally routable IPv6, 2a03:4000:xx:xx:18d7:b1ef:fe48:7d35/64 (that's what ip a tells me) on eth0. I'll refer to it with the hostname vps. For testing purposes, the server has no firewall, and net.ipv6.conf.all.forwarding=1 and net.ipv6.conf.all.accept_ra=2.

Then I also have my device, which also has an IPv6 address, 2001:1715:yy:yy:db2d:ab24:ed3f:39d4/64 on wlan0 (this should not be relevant information, since this addr will change when I am on another WLAN). It carries the hostname laptop.

I want to end up with something like this:

Internet <-> vps <-> laptop

With IPv4, I'd use NAT, however in IPv6 world, NAT is discouraged. It's hard to find out what to do instead, but if I've read correctly, then I should give another IP address from the 2a03:4000:xx:xx::/64 block the VPS got to the laptop.


So I write these two wireguard configs:


Address = fc01::1/128 # Shouldn't really matter?
ListenPort = 1935 # This port is open to UDP on most networks
PrivateKey = uLxxxxxxxxxxxxxxxxxxxxxxxxEQ=

# laptop
PublicKey = swxxxxxxxxxxxxxxxxxxxxxxxxxmQ=
AllowedIPs = 2a03:4000:xx:xx:ffff::3/128 # Is inside the vps' /64 block


Address = 2a03:4000:xx:xx:ffff::3/128 # The globally routable IP addr of my laptop via the vps
ListenPort = 1935
PrivateKey = yMxxxxxxxxxxxxxxxxxxxxxxxxxxxxm8=

PublicKey = pCxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzs=
AllowedIPs = ::/0 # Route all traffic through this peer
Endpoint = [2a03:4000:xx:xx:18d7:b1ef:fe48:7d35]:1935

I bring them up:

[root@vps ~]# wg-quick up wg0
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -6 address add fc01::1/128 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] ip -6 route add 2a03:4000:xx:xx:ffff::3/128 dev wg0

[root@laptop ~]# wg-quick up wg0
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -6 address add 2a03:4000:xx:xx:ffff::3/128 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] wg set wg0 fwmark 51820
[#] ip -6 route add ::/0 dev wg0 table 51820
[#] ip -6 rule add not fwmark 51820 table 51820
[#] ip -6 rule add table main suppress_prefixlength 0
[#] ip6tables-restore -n

... aaaand it doesn't work.

WireGuard doesn't seem to successfully connect. The Laptop shows a connection and counts sent traffic (but 0B received), but the VPS doesn't show a conection.

How does one set up a IPv6-only WireGuard VPN correctly? And if this is correct, why does traffic sent at one end not arrive at the other end of the tunnel?

If more information (pcaps, ip outputs, etc.) would be useful, I'll happily amend the question.

New contributor
TobTobXX is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
  • Does your server actually "own" the entire /64 block? (This is just like in IPv4, just because an interface has doesn't mean the entire /24 goes to your machine.) While many hosting providers assign a separate /64 for each server, that's not universal – more simply you could just be on a shared /64 next to all other customers in that datacenter.
    – user1686
    2 days ago
  • Also, if the /64 is indeed "yours", it's worth finding out whether it is routed to the server, or if it's "on link". There's additional trickery needed to use an on-link address somewhere else than that link...
    – user1686
    2 days ago
  • @user1686 Yes. I added the IP address 2a03:4000:xx:xx::beef/128 with ip addr add to eth0 and I could ping it through the Internet. And also, I do receive many Router Solicitations on eth0, which all are not in my /64 block.
    – TobTobXX
    2 days ago
  • Normally there should not be a significant delay (maybe 2 seconds while duplicate address detection is done). If you run tcpdump -e -n -i eth0 icmp6 and then externally ping another address from your /64 (specifically, one that isn't actually assigned to eth0 – perhaps the laptop's WireGuard address or just some random address), what do you see on eth0 – do you get Neighbor Solicitation packets for that address or the actual ping/echo packets?
    – user1686
    2 days ago
  • I don't receive ICMPv6 echo packets (pings), but there are NS packets being sent to search for this IP: 15:21:04.875401 2c:6b:f5:a0:77:c0 > 33:33:ff:40:e9:24, ethertype IPv6 (0x86dd), length 86: fe80::22d8:b00:c3ee:ff4 > ff02::1:ff40:e924: ICMP6, neighbor solicitation, who has 2a03:4000:xx:xx::2340:e924, length 32. `
    – TobTobXX
    2 days ago

1 Answer 1


This isn't working because your server's gateway assumes the entire /64 is "on-link", that is, every address is directly reachable on the same Ethernet segment – so the gateway makes Neighbor Discovery queries for your laptop's MAC address, but won't receive any reply because the laptop isn't on the same link at all.

(Normally the server will not respond on behalf of addresses that are routed somewhere else – it only replies for addresses that are directly assigned to its own eth0 interface.)

To make this work with on-link addresses, you'll need to use "proxy NDP", i.e. actually make the server provide NDP replies on behalf of the laptop (and any other address that you're trying to route over the tunnel).

The most reliable way to do this for IPv6 would be to run the ndpresponder daemon on eth0. It will listen for Neighbor Solicitation packets and send the correct Neighbor Advertisements.

(Similarly you could use ndppd or even the kernel's built-in proxy_ndp feature, but those behave slightly differently from real NDP replies and sometimes won't pass the anti-spoofing checks that some VPS hosting operators do.)

Ideally, though, the hosting company should provide you a routed prefix – one where the datacenter gateway is explicitly configured to route everything 'via' your server's primary address. This would also be slightly beneficial to them, as as a single static route would be more efficient than many dynamic neighbor cache entries.

(Unfortunately, many server hosting companies internally use a certain VPS management platform that prevents them from offering routed prefixes – I've heard that it's the fault of SolusVM, which insists on the "flat on-link /48" model.)

Note: This is not IPv6-specific in any way – the same distinction between 'on-link' and 'routed' exists in IPv4, with the only difference being that IPv4 uses ARP instead of NDP. (For example, if your server was in on eth0 and you wanted to route to a VPN client, you'd have exactly the same problem and you'd need proxy-ARP to get around it.)

  • Thank you for explaining the problem and mentioning workarounds!
    – TobTobXX
    2 days ago

Your Answer

TobTobXX is a new contributor. Be nice, and check out our Code of Conduct.

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.