45

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!

Kromey
  • 3,621
  • 4
  • 24
  • 30
  • With nginx 1.2.1 I didn't have to specify `ipv6only=on`. Everything else remained the same however, thanks for this! – BeepDog May 05 '14 at 02:03

1 Answers1

47

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.

kolbyjack
  • 7,854
  • 2
  • 34
  • 29
  • 2
    Wait, I'm confused. I thought at least one listen directive per server declaration was required -- otherwise how would nginx know with which server block is intended to respond on which port(s)? I didn't mention it above because I didn't think it relevant, but I have one server on 8080, the rest on 80, and I intend to offer 443 for a couple as well just as soon as I get this ironed out and then get myself an SSL certificate. – Kromey Jun 07 '11 at 16:33
  • Okay, looking again at the documentation, the sites that are on port 80 look like they won't actually need a listen directive at all, just one with the default_server flag on my catchall vhost. However, this is still failing for my server on 8080, for which I also use a default catchall (the catchall is written to simply ignore any requests for a host name I haven't explicitly configured in another vhost). – Kromey Jun 07 '11 at 16:44
  • 1
    I'm not saying to remove all your listen directives. Just remove the ipv6only=on flag from all but one of them. Without a listen directive in each server, they will default to just listen 80; which may or may not include ipv6. I think the correct approach is to include both listen directives in each server, but only put the ipv6only=on in just one of the servers. – kolbyjack Jun 07 '11 at 17:38
  • 4
    Ah, I see now what you mean. I misread your post originally. This has worked for me: `ipv6only=on` is only listed (for each port I listen on) in my default vhost (alongside `default_server`); each vhost then simply specifies `listen 80;` and `listen [::]:80` (no additional parameters at all) to function on both IPv4 and IPv6. Now all I have to do is finish adding the AAAA records for my dual-stack domains, and I should be good to go here. Thanks! – Kromey Jun 07 '11 at 17:44
  • 2
    worked for me as well , but i dont understand why i nginx can listen on ipv4 for multiple blocks, but not ipv6 . . can you explain ? – Adeerlike Feb 03 '16 at 22:23