$server_name不反映真实请求,仅返回配置的原始字符串(如*.example.com),无法区分具体子域;应使用$host(标准化Host头)或$http_host(原始Host头)记录实际访问域名。

想在 Nginx 日志里准确记录用户实际访问的域名(比如 api.example.com 而不是配置里的 *.example.com),关键不是靠 $server_name,而是用 $host 或 $http_host —— 因为 $server_name 在泛域名配置下是“写死”的,不反映真实请求。
为什么 $server_name 不适合日志记录
$server_name 只返回配置中 server_name 指令写的原始字符串。例如你配了:
server_name *.example.com;
那么无论用户访问的是 www.example.com、blog.example.com 还是 api.example.com,$server_name 在日志里统统显示为 *.example.com,完全无法区分。
该用哪个变量才可靠
推荐两个更真实的变量,按场景选择:
-
$host:Nginx 解析并标准化后的 Host 头,小写、去端口、自动处理空 Host;最常用,适合绝大多数日志场景 -
$http_host:原始 HTTP 请求头中的 Host 字段,保留大小写和端口号(如API.EXAMPLE.COM:8080);适合需要原始信息做审计或调试
例如定义一个自定义日志格式:
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$host"';
这样每条日志末尾就会带上真实访问的主机名。
配合 server_name 实现日志分流(按域名分文件)
如果希望不同域名写入不同日志文件,直接在每个 server 块里独立配 access_log:
- 确保每个站点有单独的
server块,并明确写出server_name(支持空格分隔多个域名) - 在块内指定路径,比如:access_log /var/log/nginx/www.example.com.log main;
- 提前创建目录并确保 nginx 用户有写权限:sudo mkdir -p /var/log/nginx && sudo chown -R www-data:www-data /var/log/nginx
- 避免多个
server块共用同一日志路径,否则会混写
泛域名场景下的实用技巧
若必须用通配符(如 *.example.com)统一处理子域,又想日志里体现具体子域,可以:
- 改用正则匹配 + 捕获组,例如:server_name ~^([a-z0-9\-]+)\.example\.com$;
- 然后在日志格式中引用捕获值:"$1.example.com" 或直接用
$host更简单 - 注意:正则匹配优先级高于通配符,但需确保 PCRE 库支持(Nginx 默认已启用)


















