Remember a pitfall when configuring multiple domain names with nginx server_name

Detailed explanation of server_name command

        The server_name directive sets a virtual host based on domain name. A server with one IP can be configured with multiple domain names. The following server_names are valid:

  • server_name domain.com;
  • server_name domain.com www.domain.com;
  • server_name *.domain.com;
  • server_name .domain.com;
  • server_name domain.*;
  • server_name "";

        Separate multiple domain names with spaces. nginx allows a virtual host to have one or more names, and you can also use the wildcard "*" to set the name of the virtual host.

The matching order of the server_name directive after receiving the request is:

  • 1. Accurate server_name matching, for example: domain.com www.domain.com
  • 2. String starting with wildcard character: .domain.com .domain.com
  • 3. A string ending with a wildcard character: www.
  • 4. Match regular expression: ~^(?.+).domain.com$

        nginx will match the server name in the order of 1, 2, 3, and 4. After one match, the search will stop, similar to the location directive.

background

        In order to distinguish the online environment and the test environment, I created a domain name test.daemoncoder.com dedicated to my own testing. The official domain name of the online environment is www.daemoncoder.com. The server_name configuration in nginx is changed to:

# 只列出了我们关心的配置,省略了其他无关部分
server {
    server_name www.daemoncoder.com test.daemoncoder.com;
    ...
}

        However, when using it, I found that the request kept reporting errors and redirected to the error page, so I started to locate the problem.

Positioning of the problem

        According to the logs generated when reporting errors in the business, there is this judgment in the part that requests public processing:

if ($_SERVER['SERVER_NAME'] != parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST)) {
    $this->redirectError();
}

        If the domain name parsed in the request referer is different from the domain name in the $server_name variable in nginx, it will jump to the error page, which is also the problem mentioned earlier.

        So here comes the question, why is the domain name in the referer inconsistent with $_SERVER['SERVER_NAME']? The link format I requested was in the form of http://test.daemoncoder.com/xxx, but in the end the value of $_SERVER['SERVER_NAME'] obtained at the PHP layer was www.daemoncoder.com, and in HTTP_REFERER The domain name is: test.daemoncoder.com.

        You can see that the value of SERVER_NAME is inconsistent with our expectations. How does nginx pass this variable? You need to find the definition of SERVER_NAME from the fastcgi_params configuration file of nginx:

fastcgi_param SERVER_NAME $server_name;

        You can see that the $server_name variable in nginx is the source of $_SERVER['SERVER_NAME'] we retrieved from PHP.

Cause of problem

        Through the above positioning, we can basically see the root cause of the problem (knock on the blackboard and highlight the key points):

        When server_name is configured with multiple domain names under a server node in the nginx configuration, the value of the $server_name variable is the first one configured.

        Let’s review my nginx configuration:

# 只列出了我们关心的配置,省略了其他无关部分
server {
    server_name www.daemoncoder.com test.daemoncoder.com;
    ...
}

        There are two server_name nodes: www.daemoncoder.com and test.daemoncoder.com. When I use the test domain name to access the page, it can match the domain name test.daemoncoder.com, so it will be based on the configuration of the current server node. to handle this request, but nginx will set the value of $server_name to the first server_name configured in the current server node, which is www.daemoncoder.com . If the configuration is changed to:

server_name test.daemoncoder.com www.daemoncoder.com;

        Then you can get the expected value by requesting the test domain name (but there will be problems with the official domain name).

Solution

The first way is to split the configuration files into separate server nodes according to domain names, that is:

# 省略其他无关部分
server {
    server_name www.daemoncoder.com;
    ...
}
server {
    server_name test.daemoncoder.com;
    ...
}

In this way, access using different domain names will fall into their corresponding configurations, and the $server_name parsed will also have their own values.

The second way is to modify nginx SERVER_NAME to use the $host variable, that is, 

fastcgi_param SERVER_NAME $server_name;

change into:

fastcgi_param SERVER_NAME $host;

        The resolution of the $host variable is the currently requested host and will not be affected by whether server_name is configured with multiple domain names. In this way, we take $_SERVER['SERVER_NAME'] in PHP and the value taken out is the actual requested domain name, which can also solve the problem. (But the judgment logic in the code seems to be meaningless in the test environment, so the problem is not big).

other

        When there are multiple domain names (server_name other.domain.com www. domain.com;): fastcgi_param SERVER_NAME $server_name, $server_name will take the value of the first domain name (other.domain.com).

        $host may be equal to $server_name, or it may be an IP address (taken directly by accessing this precedence order: the hostname in the request line, or the hostname in the "Host" request header field, or the servername matching the request .

  $1|$2|$3 ...It is a variable generated by nginx when matching regular expressions. It is used to capture the matching string in the brackets of a regular expression (stored in from left to right $1|$2|$3 ...). The new value overwrites the old value. You can use the variable to save the value you need :set $pre $1

reference

https://www.daemoncoder.com/a/%E8%AE%B0%E4%B8%80%E4%B8%AAnginx%20server_name%E9%85%8D%E7%BD%AE%E5%A4%9A%E4%B8%AA%E5%9F%9F%E5%90%8D%E6%97%B6%E7%9A%84%E5%9D%91/4d6a513d

Guess you like

Origin blog.csdn.net/yangyangye/article/details/131972908