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.
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 theserver_name
of the virtual host which processed the request, as it was defined in the nginx configuration. If aserver
contains multipleserver_name
s, 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.I would like to add another important point not mentioned in the accepted answer.
$host
do NOT have port number, while$http_host
does 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.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
TL;DR: If you don't use regular expressions in
server_name
you can ignore this answer ?.Since this aspect hasn't been mentioned at all in other answers, but it's something that I found somewhat annoying: I use
$host
in the creation of my log file names, like so:Alas, if you use a regular expression in your
server_name
stanza like:Your
$host
will actually end up containing the regular expression like so (yep, including the backslash and everything):I for one found this very annoying and ended up changing my regular expression to:
to capture the full name for reuse in the log file name. The respective stanza was then changed to: