Nginx Virtual Host – Correct Way to Use reuseport

nginx

I use nginx as a reverse proxy with a gunicorn application server (Django app).

In my nginx virtual host file, there are two server blocks. The former redirects www traffic to the latter (which handles non-www, https traffic).

Specifically, the former location block is:

server {

    server_name www.example.com;

    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    return 301 https://example.com$request_uri;
}

The latter location block is:

server {

    server_name example.com;
    listen 443 ssl http2 reuseport;
    listen [::]:443 ssl http2 reuseport;

    # other directives here
}

Notice the use of reuseport in the latter block.

If I put reuseportin both blocks, I get an error: nginx: [emerg] duplicate listen options for 0.0.0.0:443 in /etc/nginx/sites-enabled/vhost:62.

If I insert it in the former block solely, it works. I'm torn about where to correctly place it, the former block or the latter one. Can someone clarify?


I understand that the reuseport parameter instructs nginx to create an individual listening socket for each worker process, allowing the kernel to distribute incoming connections between worker processes (to handle multiple packets being sent between client and server).

But that doesn't help me understand why I can't use reuseport in both of my aforementioned blocks, or which one I should use it in (given I can only use it in one).

Best Answer

In NGINX, you specify the network socket's listen options only once in configuration and they "apply" to all other configured servers which listen on the same socket (port). Quoting docs:

The listen directive can have several additional parameters specific to socket-related system calls. These parameters can be specified in any listen directive, but only once for a given address:port pair.

So, what you have to decipher from the error message, is that you should only specify reuseport once for every unique listen address+port.

In which server you do this depends on your preference. But as a rule and for clarity, I suggest designating one of the servers with default_server directive, which:

if present, will cause the server to become the default server for the specified address:port pair. If none of the directives have the default_server parameter then the first server with the address:port pair will be the default server for this pair.

Then place your listen options in that server block (where you have specified the default_server).

E.g.

server {

    server_name www.example.com;

    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    return 301 https://example.com$request_uri;
}

server {

    server_name example.com;
    listen 443 ssl http2 default_server reuseport;
    listen [::]:443 ssl http2 default_server reuseport;

    # other directives here
}