Nginx 变量 $host、$http_host 和 $server_name 有什么区别?
区分 Nginx $host 的查找顺序、$http_host 的原始请求头与 $server_name 的配置值,并给出可直接检查的访问日志示例。
$host 是 Nginx 解析出的主机名,$http_host 是客户端发送的 Host 请求头原值,$server_name 是处理当前请求的服务器配置名称。 三者在端口、缺失值和可信来源上不同,不能互相替代。
三种变量的来源
| 变量 | 取值来源 | 示例 |
|---|---|---|
$host |
按顺序取请求行中的主机名、Host 请求头中的主机名,最后回退到匹配请求的服务器名称 | example.com |
$http_host |
客户端 Host 请求头原值;缺少该头时为空 | example.com:8080 |
$server_name |
接受请求的 server 块的配置名称,通常为其首个 server_name | example.com |
例如客户端访问 http://example.com:8080/ 时,$http_host 可以保留 :8080,而 $host 通常只含主机名。代理收到绝对形式的请求行时,请求行中的主机名优先于 Host 头。
正确记录三个值
先在 http 上下文定义日志格式,再在 server 中引用其名称。access_log 的第二个参数是格式名称,不能直接填写格式字符串。
http {
log_format host_debug '$remote_addr host="$host" '
'http_host="$http_host" server="$server_name" '
'status=$status request="$request"';
server {
listen 8080;
server_name example.com www.example.com;
access_log /var/log/nginx/host-debug.log host_debug;
}
}
把相关指令并入现有配置的对应上下文,执行 nginx -t 检查语法后,再按服务管理流程重新加载。
代理与跳转应该用哪个
- 向上游传递解析后的主机名:可以设置
proxy_set_header Host $host;,是否需要端口取决于上游路由规则。 - 排查客户端实际发送了什么:同时记录
$http_host和$host。 - 为固定域名做 HTTPS 跳转:直接使用确定的地址,如
return 301 https://example.com$request_uri;。
请求行和请求头均来自客户端。不要未经验证就把它们拼进对外跳转地址;多域名业务应先匹配允许的域名列表。
把上述变量写入访问日志后,可通过观测云 Nginx 日志采集保留并解析为不同字段。用带显式 Host 头的一次请求核对字段值,再按请求域名和实际匹配的 server 分组检查,避免把这三种名称混为一谈。