What is nginx server_name and how it works?

nginx_server_name

Nginx server_name is a special directive used for server block configuration selection. Let say you have multiple server sections in your Nginx config file:

server {
 listen 80;
 server_name test.com;

 ...
}

server {
 listen 80;
 server_name example.com;

 ...
}

When we get incoming request with test.com “Host” header – first server block will be used. Same block will be selected for test.org, since it does not match any of the specified hostnames. In that case Nginx selects first server block that matches listen directive (port 80 in our case). Nginx first matches against listen entry and only after that against server_name.

Here is the code to match any request with any Host header on specific port:

missing nginx server_name

* will match any request to 8888 port. Sometimes useful for locations where u access resource by ip.

There is another interesting case – sometimes you want to specify a server block that will be used for all requests that doesn’t contain Host header (bots, crawlers, your own special clients or you just want to drop them):

server {
  listen 80;
  server_name "";
  return      400;
}

* will be matched for requests without Host header and return 400 Bad request error.

Nginx server_name match order

It’s important to know the order in which Nginx matches “Host” header against server_name entry.

  1. Exact match – if the Host matches directly, evaluation immediately stops and matched server entry gets selected.
  2. Longest left side wildcard like “*.test.com” ( yes, you can use wildcards in your server_name directive, but be careful because you can only use it before the first dot, or after the last one. If you need to match something in the middle – use regular expressions. )
  3. Longest right side wildcard like “test.*”
  4. First match against regular expression ( Nginx evaluates directives top to bottom, so the topmost matching entry wins )

Here is example for server_name with regular expression (PCRE):

server {
  listen 80;
  server_name ~^(?<subdomain>.+)\.test\.com$;

  location / {
    root   /sites/$subdomain;
  }
}

* Important! Please note ~ (tilde) sign at the beginning of the expression. I’ve seen too many people who accidentally skipped it and later started pulling hairs out trying to figure out why it didn’t work.. One other interesting thing here is (?<subdomain>.+).

As you probably already guessed that’s a named capture. Here we capture subdomain part and Nginx conveniently converts it into $subdomain variable which we then use in the location entry to switch the root. This is pretty powerful stuff that allows us to create dynamic configurations like giving each developer personal directory on the server for example.

Performance considerations

For frequently requested names it’s better to use direct matches, as those are the fastest and most efficient to execute. Regular expressions are the slowest option. I know that we like to create short and complex solutions, but in this case it makes sense to explicitly define commonly used names: server_name test.com www.test.com *.test.com;

If you have a ton of names in your configuration, you may want to adjust server_names_hash_max_size (set it to the number close to the number of server names).


Also published on Medium.

Leave a Reply