Home Troubleshooting IPv6 not working on Custom OS Installation

IPv6 not working on Custom OS Installation

Last updated on Apr 03, 2026

Some Operating Systems enable IPv6 privacy extensions by default. They make IPv6 link-local address unpredictable and not possible to determine from the outside. Your VM communicates with Onidel's IPv6 gateway (fe80::1) via link-local and is only allowed to do so from an EUI-64 address.

Despite the Guest OS having IPv6 set up properly according to the address you see in Onidel Cloud Panel, the IPv6 connections time out.

$ traceroute google.com
traceroute to google.com (2607:f8b0:4006:802::200e), 30 hops max, 80 byte packets
 1  * * *
 2  * * *
 3  * * *
 4  * * *
...
$ ip a
...
2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 0c:1d:e1:7d:40:60 brd ff:ff:ff:ff:ff:ff
    altname enp6s18
    altname enx0c1de17d4060
    inet 192.209.63.14/24 brd 192.209.63.255 scope global dynamic noprefixroute ens18
       valid_lft 3596sec preferred_lft 1796sec
    inet6 2602:f992:60:110::1/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::2feb:d3b9:8b53:857b/64 scope link 
       valid_lft forever preferred_lft forever
$ ip -6 route
2602:f992:60:110::/64 dev ens18 proto kernel metric 256 pref medium
fe80::/64 dev ens18 proto kernel metric 256 pref medium
default via fe80::1 dev ens18 metric 1024 onlink pref medium

Solutions

Here, we assume Debian OS is used as a guest and we showcase two possible ways of fixing the issue. Those are inspired by this superuser answer.

dhcpcd slaac hwaddr

If your OS uses DHCP to obtain IPv4 address, it's highly likely dhcpcd automatically manages SLAAC and IPv6 generation as well.

Near the bottom of /etc/dhcpcd.conf file, verify the selected slaac option is "hwaddr", not "private":

# Generate SLAAC address using the Hardware Address of the interface
slaac hwaddr
# OR generate Stable Private IPv6 Addresses based from the DUID
#slaac private

Then you just need to restart networking and the lower 64 bits of link-local IPv6 address should match your interface's MAC address.

$ ip a | grep 'scope link\|ether'
    link/ether 0c:1d:e1:7d:40:60 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::2feb:d3b9:8b53:857b/64 scope link 
$ systemctl restart networking
$ ip a | grep 'scope link\|ether'
    link/ether 0c:1d:e1:7d:40:60 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::e1d:e1ff:fe7d:4060/64 scope link 
$ ping -6 google.com
PING google.com (2607:f8b0:4006:819::200e) 56 data bytes
64 bytes from pnlgaa-av-in-x0e.1e100.net (2607:f8b0:4006:819::200e): icmp_seq=1 ttl=116 time=2.41 ms
64 bytes from pnlgaa-av-in-x0e.1e100.net (2607:f8b0:4006:819::200e): icmp_seq=2 ttl=116 time=1.03 ms
64 bytes from pnlgaa-av-in-x0e.1e100.net (2607:f8b0:4006:819::200e): icmp_seq=3 ttl=116 time=1.05 ms

sysctl addr_gen_mode

If the dhcpcd method did not work, it may indicate the kernel itself manages the generation of unique IPv6 link-local addresses. In such case, it may be required to set addr_gen_mode parameter of your network interface to 0 which forces kernel to use EUI-64 generated addresses.

According to sysctl documentation:

addr_gen_mode - INTEGER
Defines how link-local and autoconf addresses are generated.

  • 0: generate address based on EUI64 (default)

  • 1: do no generate a link-local address, use EUI64 for addresses generated from autoconf

  • 2: generate stable privacy addresses, using the secret from stable_secret (RFC7217)

  • 3: generate stable privacy addresses, using a random secret if unset

You can check the currently active address generation mode querying the addr_gen_mode parameter of given network interface as such:

$ sysctl net.ipv6.conf.ens18.addr_gen_mode
net.ipv6.conf.ens18.addr_gen_mode = 3

Then, to force address to be based on network interface MAC address (EUI-64):

$ sysctl -w net.ipv6.conf.ens18.addr_gen_mode=0

Changes should be applies instantly, without the need of restarting any network service.

$ ip a | grep 'scope link\|ether'
    link/ether 0c:1d:e1:7d:40:60 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::2feb:d3b9:8b53:857b/64 scope link 
$ sysctl -w net.ipv6.conf.ens18.addr_gen_mode=0
net.ipv6.conf.ens18.addr_gen_mode = 0
$ ip a | grep 'scope link\|ether'
    link/ether 0c:1d:e1:7d:40:60 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::e1d:e1ff:fe7d:4060/64 scope link proto kernel_ll 
    inet6 fe80::2feb:d3b9:8b53:857b/64 scope link 
$ ping -6 google.com
PING google.com (2607:f8b0:4006:801::200e) 56 data bytes
64 bytes from lga34s11-in-x0e.1e100.net (2607:f8b0:4006:801::200e): icmp_seq=1 ttl=116 time=1.30 ms
64 bytes from lga34s11-in-x0e.1e100.net (2607:f8b0:4006:801::200e): icmp_seq=2 ttl=116 time=1.04 ms
64 bytes from lga34s11-in-x0e.1e100.net (2607:f8b0:4006:801::200e): icmp_seq=3 ttl=116 time=1.02 ms