Nginx – Name-Based Virtual Hosts on IPv6

ipv6nginxvirtualhost

I have an nginx server serving up nearly half a dozen different websites. It's running on a Linode that just got IPv6 native support (Dallas data center), and I'm trying to configure most of my sites for dual-stack operation. I got the first one up and running using an IPv6-only subdomain like so:

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

    server_name example.com ipv6.example.com;

    root /var/www/example.com/htdocs;

    #More stuff, including PHP, WordPress
}

This works great — example.com is IPv4-only (for now), and ipv6.example.com is IPv6-only (primarily there for testing purposes). I can ping6 ipv6.example.com, and even wget ipv6.example.com without breaking a sweat — this much was pleasantly pain-free (after finding the "gotcha" with the way nginx binds virtual hosts, necessitating the ipv6only=on argument and the dual listen directives).

However, I'm now trying to expand this to support my other domains, starting with static.example.com; when I take the same approach as above, though (the dual listen directives, including the ipv6only=on argument), I get the following error when restarting nginx:

* Starting Nginx Server...
nginx: [emerg] a duplicate listen options for [::]:80 in /etc/nginx/sites-enabled/example.com.conf:3

It seems that perhaps nginx's method of binding for IPv6 doesn't permit name-based virtual hosts? Will I have to get additional IPv6 addresses from my host (not a problem) and use IP-based virtual hosting on IPv6 with named-based virtual hosting over IPv4? Or am I missing a solution that will allow my configurations to remain consistent on both stacks?

I was hoping to have my site fully on the IPv6 stack in time for World IPv6 Day, but unless I can clear this up quickly I may not be ready. Not a big deal from any practical standpoint — none of my sites qualify as a "major organization" by any stretch of the imagination — but help me save my geek cred!

Edited to add:

Thanks to the answer from @kolbyjack, I have a fully functional dual-stack web server now. Just for clarity's sake, I'm editing in the solution he gave me so everyone can see clearly what the answer is.

My default catchall vhost has the following listen directives:

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

I don't know if the order matters, but there it is. Then, each additional vhost has the following listen directives:

listen 80;
listen [::]:80;

(Or 8080 for the one that listens on that port instead.) The important part here appears to be the total lack of any additional arguments on all but the default vhost's listen directives — i.e. no repetition of ipv6only=on.

Again, much thanks to @kolbyjack for the solution here!

Best Answer

You only need listen options on one declaration for a socket. Generally you would put them on the declaration that also includes the default_server flag, but for some options, I think you can just set them on any one listen directive. Just remove the ipv6only=on from all of the listens except one.