When configuring Nginx as a reverse proxy or web server, you'll often need to set up a default catch-all server block to handle requests that don't match any defined server_name
. Both server_name _
and server_name ""
serve this purpose, but let's examine their technical differences.
The empty string (""
) is actually the default value when no server_name
is specified. Nginx uses this to match requests that don't have a Host
header or don't match any configured server names.
server {
listen 80;
server_name ""; # matches empty Host header
return 444; # Connection closed without response
}
The underscore (_
) is simply a convention - a dummy name that will never match any real hostname. It's effectively identical to the empty string in functionality.
server {
listen 80 default_server;
server_name _;
return 444;
}
- Readability:
_
is more explicit about being a catch-all - Documentation: Official Nginx docs often use
_
as the example - Default Behavior: Not specifying any
server_name
is equivalent to""
Both approaches have identical performance characteristics. Nginx processes them the same way internally during the server selection phase.
For maximum clarity and maintainability, I recommend using:
server {
listen 80 default_server;
server_name _;
# Additional default server configuration
return 444; # Or your preferred handling
}
This makes the catch-all intention immediately obvious to anyone reading the configuration.
Here's a more complex example showing how this fits into a production setup:
# Specific named servers
server {
listen 80;
server_name example.com www.example.com;
# ... actual configuration
}
server {
listen 80;
server_name api.example.com;
# ... API specific configuration
}
# Catch-all default server
server {
listen 80 default_server;
server_name _;
location / {
return 403 "Forbidden: Invalid host header";
}
}
This structure ensures proper handling of both valid and invalid host headers.
When configuring Nginx as a web server, setting up a default catch-all server block is crucial for handling requests that don't match any defined virtual hosts. Both server_name _
and server_name ""
approaches are commonly used, but what's the technical difference?
The Nginx documentation states that an empty server name (""
) is automatically assigned if no server_name
is specified. The underscore (_
) is simply a convention that has no special meaning to Nginx - it's just an invalid domain name that will never match any real hostname.
# Both these configurations function identically:
server {
listen 80 default_server;
server_name ""; # Explicit empty name
return 444;
}
server {
listen 80 default_server;
server_name _; # Conventional placeholder
return 444;
}
While both approaches work, there are subtle differences in behavior you should be aware of:
- The empty string (
""
) is the official way to indicate a server block should match when no Host header is present - The underscore (
_
) is more readable and serves as clear documentation that this is a catch-all block - Performance-wise, there's no measurable difference between the two
For production environments, I recommend combining both the default_server
flag and an explicit catch-all name:
server {
listen 80 default_server;
server_name _ "";
return 444; # Close connection silently
# Alternatively: return 444 "No such host";
}
This configuration will handle:
- Requests with no Host header
- Requests with unknown hostnames
- Requests that would otherwise match no server block
You can verify your catch-all server block works using curl:
# Test with random hostname
curl -H "Host: random.example.com" http://your.server.ip
# Test with no host header
curl http://your.server.ip
Both commands should trigger your default server block response.
For more complex setups, you might want to:
server {
listen 80 default_server;
server_name _ "";
location / {
# Log unknown hosts for security monitoring
access_log /var/log/nginx/unknown_hosts.log;
# Redirect to a maintenance page
rewrite ^ /maintenance.html break;
}
}