Opened 3 weeks ago

Closed 3 weeks ago

#2298 closed defect (invalid)

Documentation or subtle bug - "listen" directive

Reported by: SirLaffalot@… Owned by:
Priority: minor Milestone:
Component: documentation Version: 1.18.x
Keywords: listen Cc:
uname -a: Linux pippin.infoscienceinc.com 5.10.0-10-amd64 #1 SMP Debian 5.10.84-1 (2021-12-08) x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.18.0
built with OpenSSL 1.1.1k 25 Mar 2021
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -ffile-prefix-map=/build/nginx-q9LD4J/nginx-1.18.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_sub_module

Description

Not sure what this is: It's either that the documentation needs to be more explicit (for listen directive), or there is a subtle bug in the listen processing.

My take is that for virtual servers, the listen directive needs to be consistently identical for all the servers. This seems to be implied somewhere in the documentation, but not explicitly documented.

How this showed up: I moved from an older Debian to a different cloud box with a newer Debian.

I have 6 virtual servers which all seemed to work if you hit them from outside, the pages display as expected. HOWEVER, Certbot could not renew 4 of the 6 server certificates. The response to the http challenge was a 404 error which made no sense because the servers were apparently functional.

Each server has it's own named access and error log. What was really odd was that the GET was posted in a "default", unnamed access log, not in the server's access log. After much hair-pulling and nail-biting, I guessed that it had something to do with the listen directives.

The listen directives at the start of the problem were:
coffeeroasterdb.conf: listen [::]:443 ssl; # managed by Certbot
coffeeroasterdb.conf: listen 443 ssl; # managed by Certbot
coffeeroasterdb.conf: listen *:80;
coffeeroasterdb.conf: listen [::]:80;
infoscienceinc.conf: listen 443 default_server ssl; # managed by Certbot
infoscienceinc.conf: listen 80 default_server;
nextcloud.conf: listen 443 ssl; # managed by Certbot
nextcloud.conf: listen 80;
phplist.conf: listen 443 ssl; # managed by Certbot
phplist.conf: listen 80;
pippin.conf: listen [::]:443 ssl; # managed by Certbot
pippin.conf: listen 443 ssl; # managed by Certbot
pippin.conf: listen 80;
takeabow.conf: listen 80;
takeabow.conf: listen 443 ssl; # managed by Certbot

nextcloud.conf and coffeeroasterdb.conf renewed, but the others didn't.

What finally worked was matching the listen statements to the first virtual server.
coffeeroasterdb.conf: listen [::]:443 ssl; # managed by Certbot
coffeeroasterdb.conf: listen *:443 ssl; # managed by Certbot
coffeeroasterdb.conf: listen *:80;
coffeeroasterdb.conf: listen [::]:80;
infoscienceinc.conf: listen [::]:443 default_server ssl; # managed by Certbot
infoscienceinc.conf: listen *:443 default_server ssl; # managed by Certbot
infoscienceinc.conf: listen [::]:80 default_server;
infoscienceinc.conf: listen *:80 default_server;
nextcloud.conf: listen 443 ssl; # managed by Certbot
nextcloud.conf: listen 80;
phplist.conf: listen [::]:443 ssl; # managed by Certbot
phplist.conf: listen *:443 ssl; # managed by Certbot
phplist.conf: listen [::]:80;
phplist.conf: listen *:80;
pippin.conf: listen [::]:443 ssl; # managed by Certbot
pippin.conf: listen *:443 ssl; # managed by Certbot
pippin.conf: listen [::]:80;
pippin.conf: listen *:80;
takeabow.conf: listen [::]:80;
takeabow.conf: listen *:80;
takeabow.conf: listen [::]:443 ssl; # managed by Certbot
takeabow.conf: listen *:443 ssl; # managed by Certbot

It may also have something to do with the way Certbot makes requests, but since these are popular certificates, the documentation should be more clear on this.

Thanks.

Change History (1)

comment:1 by Maxim Dounin, 3 weeks ago

Resolution: invalid
Status: newclosed

The listen directive lists listening sockets a particular server is going to accept requests. Quoting docs:

Sets the address and port for IP, or the path for a UNIX-domain socket on which the server will accept requests.

Obviously enough, if a socket is not listed, the server won't accept requests on this socket. This is probably what happened in your case: a request was made to a listening socket not configured for the particular server, and was processed in the default server for the listening socket instead, resulting in 404.

Depending on your particular configuration, different listen directives in different server blocks might be correct or not. Some examples to better explain how it works are provided in the How nginx processes a request introductory article.

Hope this helps.

Note: See TracTickets for help on using tickets.