37

What is the difference between the three Nginx variables $host, $http_host, and $server_name?

I have a rewrite rule where I'm not sure which one I should be using:

location = /vb/showthread.php {
    # /vb/showthread.php?50271-What-s-happening&p=846039
    if ($arg_p) {
        return 301 $scheme://$host/forum/index.php?posts/$arg_p/;
        }

I'm looking for an answer that doesn't just say 'use ___ variable in your rewrite rule' but also explains the theoretical differences between them.

  • I realized later I didn't even need to specify $scheme and $host... return 301 /forum/index.php?posts/$arg_p/; works fine. – Jeff Widman Jul 17 '15 at 8:06
  • Most browser would work with relative URL in redirect, but the standard (w3.org/Protocols/rfc2616/rfc2616-sec14.html) requires absolute url in the Location header. – Cthulhu Jul 17 '15 at 9:16
48

You should almost always use $host, as it's the only one guaranteed to have something sensible regardless of how the user-agent behaves, unless you specifically need the semantics of one of the other variables.

The difference is explained in the nginx documentation:

  • $host contains "in this order of precedence: host name from the request line, or host name from the 'Host' request header field, or the server name matching a request"
  • $http_host contains the content of the HTTP "Host" header field, if it was present in the request
  • $server_name contains the server_name of the virtual host which processed the request, as it was defined in the nginx configuration. If a server contains multiple server_names, only the first one will be present in this variable.

Since it is legal for user-agents to send the hostname in the request line rather than in a Host: header, though it is rarely done except when connecting to proxies, you have to account for this.

You also have to account for the case where the user-agent doesn't send a hostname at all, e.g. ancient HTTP/1.0 requests and modern badly-written software. You might do so by diverting them to a catch-all virtual host which doesn't serve anything, if you are serving multiple web sites, or if you only have a single web site on your server you might process everything through a single virtual host. In the latter case you have to account for this as well.

Only the $host variable accounts for all the possible things that a user-agent may do when forming an HTTP request.

  • On the other hand, the $server_name is safe when Host: field from UA may contain arbitrary content. – Cthulhu Jul 17 '15 at 9:13
  • 1
    Is $http_host renamed to $hostname ? I can not find such variable in Nginx doc. $hostname is the most similar one I guess. – darkbaby123 Feb 23 '16 at 3:00
  • 3
    @darkbaby123 No, it was not renamed to anything. See the documentation. – Michael Hampton Feb 23 '16 at 3:15
  • 1
    Ah now I understand what http_<name> variable means. Thank you! – darkbaby123 Feb 23 '16 at 3:38
0

I would like to add another important point not mentioned in the accepted answer.

$host do NOT have port number, while $http_hostDO include the port number.

edit: not always.

I set up a header "add_header Y-blog-http_host "$http_host" always;"

Then curl -I -L domain.com:80 (or 443) and the header doesn't show a port number at all. Verified with nginx-extra 1.10.3. Is is because it's common http(s) ports or nginx configuration? This comment just to say things do not always behave the way you think.

0

I also struggled with this for a while. It became clear when I understood that $http_XXXXX refer to all declared header variables.

So $http_user_agent, $http_referer are "USER AGENT", "REFERER" referenced in lower case and underslash. This explained me where the hell $http_upgrade was coming from in many NGINX configuration samples.

Read it from https://stackoverflow.com/questions/15414810/whats-the-difference-of-host-and-http-host-in-nginx

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.