[default_server_flag] Missing default_server on shared listen socket
What this check looks for
This plugin reports when multiple server blocks share the same listen address and port, but none of them is marked as default_server (or default).
Why this is a problem
When an incoming request does not match any server_name, NGINX still has to pick a server block. Without an explicit default, selection becomes harder to reason about and may change when configs are refactored or include order changes. That can lead to requests landing on the wrong virtual host, exposing unintended content or certificates.
Bad configuration
# HTTP vhosts share :80, but no default_server
server {
listen 80;
server_name a.test;
return 301 https://a.test$request_uri;
}
server {
listen 80;
server_name b.test;
return 301 https://b.test$request_uri;
}
# HTTPS vhosts share :443, but no default_server
server {
listen 443 ssl;
server_name a.test;
ssl_certificate /etc/ssl/a.test.crt;
ssl_certificate_key /etc/ssl/a.test.key;
location / { return 200 "a\n"; }
}
server {
listen 443 ssl;
server_name b.test;
ssl_certificate /etc/ssl/b.test.crt;
ssl_certificate_key /etc/ssl/b.test.key;
location / { return 200 "b\n"; }
}
Requests for an unknown hostname will be handled by whichever server ends up being the default implicitly.
Better configuration
Pick the server you want as the catch-all and mark it explicitly:
# Explicit default for HTTP :80
server {
listen 80 default_server;
server_name _;
return 444;
}
# Explicit default for HTTPS :443
server {
listen 443 ssl default_server;
server_name _;
# A dedicated/default cert (self-signed or otherwise) for unknown names
ssl_certificate /etc/ssl/default.crt;
ssl_certificate_key /etc/ssl/default.key;
return 444;
}
# a.test
server {
listen 80;
server_name a.test;
return 301 https://a.test$request_uri;
}
server {
listen 443 ssl;
server_name a.test;
ssl_certificate /etc/ssl/a.test.crt;
ssl_certificate_key /etc/ssl/a.test.key;
location / { return 200 "a\n"; }
}
# b.test
server {
listen 80;
server_name b.test;
return 301 https://b.test$request_uri;
}
server {
listen 443 ssl;
server_name b.test;
ssl_certificate /etc/ssl/b.test.crt;
ssl_certificate_key /etc/ssl/b.test.key;
location / { return 200 "b\n"; }
}
Additional notes
This plugin only runs when a scan of full configuration is performed, i.e. when the configuration scanned includes an http { .. } block.
Sockets are compared the way NGINX itself compares them. listen 80, listen *:80, listen 0.0.0.0:80 and listen 0.0.0.0 all name one socket, as do listen [::]:80, listen [::0]:80 and listen [::]; an argument with no port implies port 80. The IPv4 and IPv6 wildcards on one port stay separate, and so do sockets of different types - listen 443 ssl and listen 443 quic each have their own default server, as do listen 12345 and listen 12345 udp in stream.
listen unix:/path sockets are not checked.
An http server block with no listen directive at all still takes part in the check: NGINX gives it *:80 when running as the superuser (*:8000 otherwise), so it shares the socket with any listen 80; sibling. Because the scanned configuration says nothing about the user NGINX will run as, the check assumes the *:80 case.
server blocks are only compared within their own module, so an http server and a stream server on the same port are not reported against each other.