Nginx IPv4 IPv6 – Do You Need Separate IPv4 and IPv6 Listen Directives in Nginx?

ipv4ipv6nginx

I've seen various config examples for handling dual-stack IPv4 and IPv6 virtual hosts on nginx. Many suggest this pattern:

listen 80;
listen [::]:80 ipv6only=on;

As far as I can see, this achieves exactly the same thing as:

listen [::]:80 ipv6only=off;

Why would you use the former? The only reason I can think of is if you need additional params that are specific to each protocol, for example if you only wanted to set deferred on IPv4.

Best Answer

That probably is about the only reason you would use the former construct, these days.

The reason you're seeing this is probably that the default of ipv6only changed in nginx 1.3.4. Prior to that, it defaulted to off; in newer versions it defaults to on.

This happens to interact with the IPV6_V6ONLY socket option on Linux, and similar options on other operating systems, whose defaults aren't necessarily predictable. Thus the former construct was required pre-1.3.4 to ensure that you were actually listening for connections on both IPv4 and IPv6.

The change to the nginx default for ipv6only ensures that the operating system default for dual stack sockets is irrelevant. Now, nginx either explicitly binds to IPv4, IPv6, or both, never depending on the OS to create a dual stack socket by default.

Indeed, my standard nginx configs for pre-1.3.4 have the first configuration, and post-1.3.4 all have the second configuration.

Though, since binding a dual stack socket is a Linux-only thing, my current configurations now look more like the first example, but without ipv6only set, to wit:

listen [::]:80;
listen 80;