IPv6 is the most recent version of the IP protocol that the entire internet relies on to connect to other locations (IP protocol is a bit redundant because IP stands for internet protocol, but we will use it because it is easy). While IPv4 is still in use in many areas of the world, the IPv4 address space is being consumed at a rapid rate and it is not large enough to sustain the rapid deployment of internet-ready devices.
IPv6 looks to solve these problems. As well as making general improvements on the protocol, the most obvious benefit of utilizing IPv6 addresses is that it has a much larger address space. While IPv4 allowed for 2^32 addresses (with some of those reserved for special purposes), the IPv6 address space allows for 2^128 addresses, which is an incredible increase.
While IPv6 opens up a lot of opportunities and solves many long-standing issues, it does require a bit of an adjustment to some of your routine network configurations if you are used to using IPv4 exclusively. In this guide, we’ll talk about some of the IPv6 counterparts to some popular IPv4 tools and utilities and discuss how to configure some popular services to utilize IPv6.
Some of the simplest utilities used to diagnose network issues were created with IPv4 in mind. To address this, we can use their IPv6 cousins when we wish to deal with IPv6 traffic.
First of all, to see your currently configured IPv6 addresses for your server, you can use the
iproute2 tools to show you the current configured addresses:
ip -6 addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000 inet6 2400:6180:0:d0::41f/64 scope global valid_lft forever preferred_lft forever inet6 fe80::601:15ff:fe43:b201/64 scope link valid_lft forever preferred_lft forever 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000 inet6 fe80::601:15ff:fe43:b202/64 scope link valid_lft forever preferred_lft forever
To print out the IPv6 routing table, you can use
netstat by typing something like this:
netstat -A inet6 -rn
Kernel IPv6 routing table Destination Next Hop Flag Met Ref Use If 2400:6180:0:d0::/64 :: U 256 0 1 eth0 fe80::/64 :: U 256 0 0 eth1 fe80::/64 :: U 256 0 0 eth0 ::/0 2400:6180:0:d0::1 UG 1024 0 0 eth0 ::/0 :: !n -1 1 90 lo ::1/128 :: Un 0 1 20 lo 2400:6180:0:d0::41f/128 :: Un 0 1 86 lo fe80::601:15ff:fe43:b201/128 :: Un 0 1 75 lo fe80::601:15ff:fe43:b202/128 :: Un 0 1 0 lo ff00::/8 :: U 256 0 0 eth1 ff00::/8 :: U 256 0 0 eth0 ::/0 :: !n -1 1 90 lo
If you prefer the iproute2 tools, you can get similar information by typing:
ip -6 route show
2400:6180:0:d0::/64 dev eth0 proto kernel metric 256 fe80::/64 dev eth1 proto kernel metric 256 fe80::/64 dev eth0 proto kernel metric 256 default via 2400:6180:0:d0::1 dev eth0 metric 1024
Now that you know about how to get some of your own IPv6 information, let’s learn a bit about how to use some tools that work with IPv6.
ping command is actually IPv4-specific. The IPv6 version of the command, which works exactly the same but for IPv6 addresses, is named unsurprisingly
ping6. This will ping the local loopback interface:
ping6 -c 3 ::1
PING ::1(::1) 56 data bytes 64 bytes from ::1: icmp_seq=1 ttl=64 time=0.021 ms 64 bytes from ::1: icmp_seq=2 ttl=64 time=0.028 ms 64 bytes from ::1: icmp_seq=3 ttl=64 time=0.022 ms --- ::1 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 1998ms rtt min/avg/max/mdev = 0.021/0.023/0.028/0.006 ms
As you can see, this works exactly as expected, the only difference being the protocol version being used for the addressing.
Another tool that you might rely on is
traceroute. There is also an IPv6 equivalent available:
traceroute to google.com (2404:6800:4003:803::1006) from 2400:6180:0:d0::41f, 30 hops max, 24 byte packets 1 2400:6180:0:d0:ffff:ffff:ffff:fff1 (2400:6180:0:d0:ffff:ffff:ffff:fff1) 0.993 ms 1.034 ms 0.791 ms 2 2400:6180::501 (2400:6180::501) 0.613 ms 0.636 ms 0.557 ms 3 2400:6180::302 (2400:6180::302) 0.604 ms 0.506 ms 0.561 ms 4 10gigabitethernet1-1.core1.sin1.he.net (2001:de8:4::6939:1) 6.21 ms 10.869 ms 1.249 ms 5 15169.sgw.equinix.com (2001:de8:4::1:5169:1) 1.522 ms 1.205 ms 1.165 ms 6 2001:4860::1:0:337f (2001:4860::1:0:337f) 2.131 ms 2.164 ms 2.109 ms 7 2001:4860:0:1::523 (2001:4860:0:1::523) 2.266 ms 2.18 ms 2.02 ms 8 2404:6800:8000:1c::8 (2404:6800:8000:1c::8) 1.741 ms 1.846 ms 1.895 ms
You may be familiar with is the
tracepath command. This follows the example of the other commands for the IPv6 version:
1?: [LOCALHOST] 0.045ms pmtu 65536 1: ip6-localhost 0.189ms reached 1: ip6-localhost 0.110ms reached Resume: pmtu 65536 hops 1 back 64
If you need to monitor traffic as it comes into your machine, the
tcpdump program is often used. We can get this utility to show only our IPv6 traffic by filtering it with the expression
ip6 or proto ipv6 after our options.
For example, we can measure rapidly flowing IPv6 traffic easily by telling the tool to only capture the information we’re interested in. We can use this command as taken from here to only gather a summary of the information to avoid delaying output:
tcpdump -t -n -i eth0 -s 512 -vv ip6 or proto ipv6
You can easily check the DNS information for your domains by using the typical tools. The main difference is that you will probably be asking for
AAAA records, which are used for IPv6 addresses instead of
A records, which are only used for IPv4 mapping.
To retrieve an IPv6 address record for a domain, you can simply request the
AAAA record. With the
host command, you can do that like this:
host -t AAAA google.com
google.com has IPv6 address 2404:6800:4003:803::1004
If you prefer to use
dig, you can get similar results by using this syntax:
dig google.com AAAA
; <<>> DiG 9.8.1-P1 <<>> google.com AAAA ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14826 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;google.com. IN AAAA ;; ANSWER SECTION: google.com. 299 IN AAAA 2404:6800:4003:803::1006 ;; Query time: 5 msec ;; SERVER: 184.108.40.206#53(220.127.116.11) ;; WHEN: Tue Apr 1 13:59:23 2014 ;; MSG SIZE rcvd: 56
As you can see, checking that your DNS is resolving correctly for your domains is just as easy when you are working with IPv6 addresses.
Most of your common network services should have the ability to handle IPv6 traffic. Sometimes, they need special flags or syntax, and other times, they provide an alternative implementation specifically for IPv6.
For SSH, the daemon can be configured to listen to an IPv6 address. This is controlled in the configuration file that you can open with:
sudo nano /etc/ssh/sshd_config
ListenAddress specifies which address the SSH daemon will bind to. For IPv4 addresses, this looks like this:
This listens to the IPv4 address
18.104.22.168 on port 22. For an IPv6 address, you can do the same by placing the address in square brackets:
This tells the SSH daemon to listen to the
1341:8954:a389:33:ba33::1 address on port 22. You can tell it to listen to all available IPv6 addresses by typing:
Remember to reload the daemon after you’ve made changes:
sudo service ssh restart
On the client side, if the daemon that you are connecting to is configured to listen using IPv4 and IPv6, you can force the client to use IPv6 only by using the
-6 flag, like this:
ssh -6 firstname.lastname@example.org
Similar to the SSH daemon, web servers also must be configured to listen on IPv6 addresses.
In Apache, you can configure the server to respond to requests on a certain IPv6 address using this syntax:
This tells the server to listen to this specific address on port 80. We can combine this with an IPv4 address to allow more flexibility like this:
Listen 22.214.171.124:80 Listen [1341:8954:a389:33:ba33::1]:80
In practice, if you want to listen to connections on all interfaces in all protocols on port 80, you could just use:
On the virtualhost level, you can also specify an IPv6 address. Here, you can see that it’s possible to configure a virtualhost to match for both an IPv4 address and an IPv6 address:
<VirtualHost 126.96.36.199:80, [1341:8954:a389:33:ba33::1]:80> . . . </VirtualHost>
Remember to restart the service to make the changes:
sudo service apache2 restart
If you prefer to use Nginx as your web server, we can implement similar configurations. For the listen directive, we can use this for IPv6 traffic:
In Linux, this actually enables IPv4 traffic on port 80 as well because it automatically maps IPv4 requests to the IPv6 address. This actually prevents you from specifying an IPv6 address and IPv4 address separately like this:
listen [1341:8954:a389:33:ba33::1]:80; listen 188.8.131.52:80;
This will result in an error saying that the port is already bound to another service. If you want to use separate directives like this, you must turn off this functionality using
sysctl like this:
sysctl -w net.ipv6.bindv6only=1
You can make sure this is automatically applied at boot by adding it to
sudo nano /etc/sysctl.conf
. . . net.ipv6.bindv6only=1
Afterwards, you can use use a similar configuration to the one that was failing before by adding the
ipv6only=on flag to the IPv6 listening directive:
listen [1341:8954:a389:33:ba33::1]:80 ipv6only=on; listen 184.108.40.206:80;
Again, restart Nginx to make the changes:
sudo service nginx restart
If you are used to configuring your firewall rules using netfilter configuration front-ends like
iptables, you’ll be happy to know that there is an equivalent tool called
We have a guide here on how to configure iptables for Ubuntu here.
For the IPv6 variant, you can simply replace the command with
ip6tables to manage the IPv6 packet filter rules. For instance, to list the IPv6 rules, you can type:
sudo ip6tables -L
Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination
If you are using the
ufw tool, then congratulations, you’re already done! The
ufw tool configures both stacks at the same time unless otherwise specified. You may have to add rules for your specific IPv6 addresses, but you will not have to use a different tool.
You can learn more about how to use ufw here.
If you use TCP wrappers to control access to your server through the
/etc/hosts.deny files, you can simply use IPv6 syntax to match certain source rules.
For example, you could allow only an IPv4 and an IPv6 address to connect through SSH by typing editing the
/etc/hosts.allow file and adding this:
sudo nano /etc/hosts.allow
. . . sshd: 220.127.116.11/255.255.254.0, [1341:8954:a389:33::]/64
As you can see, it is very easy to adapt your current TCP wrapper rules to apply to IPv6 addresses. You can learn more about how to format IP addresses and subnets here.
Hopefully, by now you realize that transitioning to IPv6 or taking advantage of IPv6 in addition to IPv4 is a fairly straight forward process.
You will have to specifically investigate any network services that you use to find out if there are any additional configuration changes that are needed to correctly utilize your IPv6 resources. However, you should now feel more comfortable working with IPv6 with your most basic utilities and services.
<div class=“author”>By Justin Ellingwood</div>
If you’ve enjoyed this tutorial and our broader community, consider checking out our DigitalOcean products which can also help you achieve your development goals.