In Nginx, what's the difference between variables $host
and $http_host
.
$host
is a variable of the Core module.
$host
This variable is equal to line Host in the header of request or name of the server processing the request if the Host header is not available.
This variable may have a different value from $http_host in such cases: 1) when the Host input header is absent or has an empty value, $host equals to the value of server_name directive; 2)when the value of Host contains port number, $host doesn't include that port number. $host's value is always lowercase since 0.8.17.
$http_host
is also a variable of the same module but you won't find it with that name because it is defined generically as $http_HEADER
(ref).
$http_HEADER
The value of the HTTP request header HEADER when converted to lowercase and with 'dashes' converted to 'underscores', e.g. $http_user_agent, $http_referer...;
Summarizing:
$http_host
equals always theHTTP_HOST
request header.$host
equals$http_host
, lowercase and without the port number (if present), except whenHTTP_HOST
is absent or is an empty value. In that case,$host
equals the value of theserver_name
directive of the server which processed the request.
server_name
directives too. if you happen to have a regex in the first one, that becomes the $host
, and all sorts of ugly stuff can happen during rewrite rules. –
Booking $server_name
variable equal the server_name
directive's value or the actual server name that was selected if there were multiple server_name
directives? –
Discriminating $server_name
is always equal to the first value specified with the server_name directive. For example, with server_name example.com one.example.com two.example.com;
, $server_name
will always be "example.com", regardless of which host the user has specified. In fact, if you don't have a default_server
, the host might be something completely different (like example.org). –
Kellda The accepted answer and its comments don't seem to be correct (anymore). The docs (http://nginx.org/en/docs/http/ngx_http_core_module.html#var_host) say that $host
is
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
So $http_host
is always the value of the Host
header field. They might differ if the host in the request line (if specified) differs from the Host
header field. Or if the Host
header is not set.
server_name
matches only the Host
header field (http://nginx.org/en/docs/http/request_processing.html), so that $host
may differ from the matched server_name
.
$http_host
has still the port included, while $host
doesn't seem so. Some peculiar settings may need the port to behave well, otherwise they fall on standard settings (port 80/443). –
Relator $http_host
$http_host
always equals Host
request header field
Host: example.org
$host
$host
is in this order of precedence (from high to low):
- Host name from the request line
GET http://example.org/test/ HTTP/1.1
Host
request header field- The
server_name
(in Nginx config) matching a request, even ifserver_name
is wildcard (Ex:server_name *.example.org;
)
Host name from the request line
When open URL http://example.org/test/
...
Most browser send the request like this
GET /test/ HTTP/1.1
Host: example.org
Most browser doesn't send the request like this (but this is valid request)
GET http://example.org/test/ HTTP/1.1
Validation
Nginx testing config
server {
listen 80;
server_name *.example.org;
location / {
default_type "text/plain";
return 200 "[host] = $host";
}
}
When all exist ...
$host
= host name from the request line
curl http://127.0.0.1 -v \
--request-target http://request.example.org/test/ \
--path-as-is \
-H "Host: host.example.org"
This command will
- Connect to
127.0.0.1
- Send request path as
GET http://request.example.org/test/ HTTP/1.1
- Set
Host
header toHost: host.example.org
* Trying 127.0.0.1:80...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)
> GET http://request.example.org/test/ HTTP/1.1
> Host: host.example.org
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.23.1
< Date: Fri, 21 Oct 2022 02:00:56 GMT
< Content-Type: text/plain
< Content-Length: 28
< Connection: keep-alive
<
* Connection #0 to host 127.0.0.1 left intact
[host] = request.example.org
When only Host
header exist ...
$host
= Host
header
curl http://127.0.0.1/test/ -v \
-H "Host: host.example.org"
* Trying 127.0.0.1:80...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)
> GET /test/ HTTP/1.1
> Host: host.example.org
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.23.1
< Date: Fri, 21 Oct 2022 02:01:37 GMT
< Content-Type: text/plain
< Content-Length: 25
< Connection: keep-alive
<
* Connection #0 to host 127.0.0.1 left intact
[host] = host.example.org
When none exist ...
$host
= server_name
(in Nginx config)
# HTTP 1.1 must have Host header, so use HTTP 1.0
curl http://127.0.0.1/test/ -v -H "Host:" -0
* Trying 127.0.0.1:80...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)
> GET /test/ HTTP/1.0
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.23.1
< Date: Fri, 21 Oct 2022 02:02:20 GMT
< Content-Type: text/plain
< Content-Length: 22
< Connection: close
<
* Closing connection 0
[host] = *.example.org
server
(vhost) even if the request has a bogus Host
header and does not match server_name
. This is an issue because applications behind nginx tend to use the passed on Host
header. It's a pity that server_name
does not check the Host
header (if exists in the request) if there was a hostname in "the request line" -- a rare and mostly malicious case. –
Weinman Both $http_host
and $host
are variables used in Nginx configuration files, but they have slight differences in their usage and behavior.
$http_host
: This variable represents the value of the "Host" header in the HTTP request. It includes the port if specified by the client. For example, if the client sends a request to "example.com:8080", then$http_host
will be set to "example.com:8080". This variable is useful when you need to capture the exact host value from the client request.$host
: This variable represents the name of the server requested by the client, without the port number. It only contains the hostname or IP address. For example, if the client sends a request to "example.com:8080", then$host
will be set to "example.com". This variable is commonly used for server configuration, especially when defining server names or redirects.
To summarize, the main difference between $http_host
and $host
is that $http_host
includes the port number specified by the client, while $host
does not. In most cases, you would use $host
when you need to capture the hostname for server-related configuration, and $http_host
when you need to capture the complete "Host" header value with the port included.
© 2022 - 2024 — McMap. All rights reserved.
server_name
that is defined in the current server block. if you have multipleserver_name
s, only the first one will appear. – Booking