Nginx listen ipv6 quirks
Most of 'our' nginx configs have something like:
server {
listen 80 default_server;
}
maybe if we support more than one site we also have a few copies of:
server {
listen 80;
}
laying around elsewhere
this all works fine, but it meant nginx is NOT listening on ipv6, and enabling ipv6 support is non-trivial.
The first attempt
first I tried changing every '80' to "[::]:80" which googling told me would support both:
server {
listen [::]:80;
}
however this doens't work in a multi-site config like I use (having many entries in sites-enabled, each with their own server block):
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
A second attempt
server {
listen 80;
listen [::]:80;
}
gives us:
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
ahh, since '[::]:80' is for both ipv6 and ipv4, so nginx tries to bind with port 80 on the ipv4 ip twice.
A third attempt
googling tells me that 'ipv6only=on' is the magic sauce:
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
}
server {
listen 80;
listen [::]:80 ipv6only=on;
}
which now gives me:
Restarting nginx: nginx: [emerg] duplicate listen options for [::]:80 in /etc/nginx/sites-enabled/foo:3
A fourth, and final, attempt
ahh so every listen ip:port combo can only be configured once, this makes sense for things like 'default_server', but I was honestly surprised it is for any config options.
This now leaves us with:
TL;DR
in nginx your default server should be:
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
}
every other (non default) should be:
server {
listen 80;
listen [::]:80;
}
now nginx is happy!