The new virtual host serving you this website is now capable of IPv6, which is great. In the days where IPv4 addresses are rare and also not very cheap (>15€ per month for more than 4 addresses), it's good to have a /64 IPv6 subnet. 2^64
addresses is way to much but well.. it is for free.
Nginx is my webserver of choice right now and I want to enable IPv6 in dual stack mode. My first naive approach was to just uncomment the listen [::]:80
directive for all servers and that's it. I was wrong, this is the result:
Starting nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
configuration file /etc/nginx/nginx.conf test is successful
[emerg]: bind() to [::]:80 failed (98: Address already in use)
[emerg]: bind() to [::]:80 failed (98: Address already in use)
[emerg]: bind() to [::]:80 failed (98: Address already in use)
[emerg]: bind() to [::]:80 failed (98: Address already in use)
[emerg]: bind() to [::]:80 failed (98: Address already in use)
[emerg]: still could not bind()
The point here is, that if net.ipv6.bindv6only
(in /etc/sysctl.conf
) is disabled - which it is by default - nginx listens in dual stack mode. And as we have the directive listen 80
in our configuration as well, it crashes.
There are two solutions to this: Disable listen 80
for every server or change ipv6only
to 1
.
Replace all listen 80
with listen [::]:80
server {
# listen 80; ## listen for ipv4
listen [::]:80; ## listen for ipv6
}
$> netstat -nlp | grep nginx
tcp6 0 0 :::80 :::* LISTEN 8960/nginx
tcp6 0 0 :::443 :::* LISTEN 8960/nginx
No tcp (IPv4) listen directives for nginx. Despite that, the sockets are configured to accept both IPv4 and IPv6 connections via in6addr_any
.
Enable ipv6only
To explicitly create to sockets for each protocol, you'd have to to configure nginx the following way:
server {
listen 80;
listen [::]:80 ipv6only=on;
}
The default on Linux is disabled ipv6only. So you have to enable it manually with sysctl -w net.ipv6.bindv6only="1"
or put the following into /etc/sysctl.conf
and reboot.
net.ipv6.bindv6only = 1