Setting up IPv6 on a Web Server

Posted on | 918 words | ~5 mins

This weekend, I finally came around to enabling IPv6 on my web server. In this post, I describe what I did to get everything up and running on a netcup vServer running CentOS 8, but this should be quite the same for other web hoster services.


My ISP (like many others) primarily uses IPv6 for client IPs and offers IPv4 access via DS-Lite . On random occasions, the IPv4 gateway (DS-Lite NAT) isn’t available, and I can only access the part of the internet which is correctly configured for IPv6 traffic. I was pretty surprised - and frankly shocked - how much this cripples my internet access. Of everything I’ve tried until now, only a handful of services are accessible through IPv6: Google, YouTube, and a couple of IT expert blogs like ;

Considering how long we know about IPv4 address shortage and that IPv6 is far from the new kid on the block, this struck me as odd - until I remembered how my own vServer was still locked in the IPv4 universe.

So, how hard can it be?

Step 1: Getting an IPv6 Address and rDNS

The first thing we need to do is getting the actual external IPv6 address for our machine. While you’ll probably get just one IPv4 address for your server, a whole IPv6 subnet is usually assigned to your machine.

A subnet looks like this 2a03:4000:6:12ab::/64. This means that you can assign any address between 2a03:4000:6:12ab::0 and 2a03:4000:6:12ab:ffff:ffff:ffff:ffff to your machine.

Select any IP in this range and add it for reverse DNS (rDNS) lookup to your machine. This means that anyone asking the DNS to a domain name for your IPv6 address will get back your domain name.

netcup rDNS UI

Step 2: Assigning Your IPv6 Address to Your Machine

Next, we set up a static IPv6 address. CentOS 8 has IPv6 enabled by default, so you don’t have to do anything there unless you have explicitly disabled IPv6 before.

Check this by executing ip -6 a on your server. You should at least see a loopback interface and a link-local address like that:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 fe80::5232:c368:a075:55a5/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

If you don’t see either of those, check out this guide on tecmint .

From there on out, configuring a static IPv6 address is smooth sailing! Just add the following lines to /etc/sysconfig/network-scripts/ifcfg-eth0. Remember that eth0 is your interface name and might be called something else in your case, e.g. enp6s0. You can see the actual interface name in the output of the ip command above.


Replace 2a03:4000:6:12ab::1 with the IPv6 address you configured for rDNS and eth0 with your actual network interface.

If you configured IPv4 to use DHCP, please undo that now. IPv4 and IPv6 should both be static, or the DHCP client might override your static IPv6 configuration. In my case, there was nothing to do. If you can see the line BOOTPROTO=none in your /etc/sysconfig/network-scripts/ifcfg-eth0 you’re golden. Otherwise, check this guide on .

After you’re done with that, reboot your system using sudo reboot. Just reloading the NetworkManager service did absolutely nothing in my case. If you find a solution that doesn’t involve a complete reboot, I’d be happy to hear from you and update this section.

After the reboot, ip -6 a should look something like that:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 2a03:4000:6:12ab::1/64 scope global noprefixroute 
       valid_lft forever preferred_lft forever
    inet6 fe80::5232:c368:a075:55a5/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

Step 3: Adding IPv6 DNS Entries

Now we can add the DNS entries for your shiny new IPv6 address. The easiest way is to add an additional AAAA entry with your IPv6 address for every existing A entry with your IPv4 address.

In my case, these would look like that:

Host Type Destination
* AAAA 2a03:4000:6:12ab::1
@ AAAA 2a03:4000:6:12ab::1

Keep in mind that changed DNS entries might take a while until they’re known to all DNS servers. Check your DNS TTL before starting to panic. For example, my .eu domain took about half an hour, while my .dev domain accepted the change right away. In some cases, this might take up to 48 hours.

Also, flush your local DNS cache or check using another device if it takes longer than expected. I had those caches fool me a couple of times before.

Step 3: Configuring IPv6 in Your Web Server

It’s time to make sure that your web server is listening to IPv6 requests. I’m using nginx, so in my case, that meant adding listen [::]:80; to every http server block and listen [::]:443 ssl http2; to every HTTPS server block.

You should easily find all relevant places in your configuration by searching for the corresponding IPv4 instructions (listen 80; and listen 443 ssl http2;). Depending on your SSL configuration, the HTTPS argument might be looking slightly different.

Step 4: Testing

The last step is to test if we did everything right. You can use ping6 to check if your machine answers to IPv6 pings and to check if your website is served via IPv6.

Successful result


And that’s it. It shouldn’t take you more than half an hour to make the internet a better place. The future is now 🚀!