必须用 map 指令在 http 块顶层映射 $uri 到日志路径变量,再于 server 级通过 access_log $log_path 引用;location 内直接写 access_log 会报错。

用 map 指令为不同 location 分配独立 access_log 文件
直接在 location 块里写 access_log 会失效——Nginx 不允许在 location 中使用该指令(1.19.2+ 仍不支持)。必须借助 map 提前把路径映射成日志文件路径变量,再在 http 或 server 级别引用。
常见错误是试图这样写:
location /api/v1/ {
access_log /var/log/nginx/api_v1.log; # ❌ 语法错误,Nginx 启动失败
}
正确做法是先定义映射关系:
-
map必须放在http块顶层,不能嵌套在server或location内 - 匹配键是
$request_uri或$uri;推荐用$uri(已解码、无 query string),避免因参数差异导致漏匹配 - 默认值要用空字符串或占位路径,否则未匹配时 Nginx 会 fallback 到全局
access_log
示例配置片段:
http {
map $uri $log_path {
~^/api/v1/ /var/log/nginx/api_v1.log;
~^/admin/ /var/log/nginx/admin.log;
~^/healthz /var/log/nginx/health.log;
default /var/log/nginx/default.log;
}
<pre class="brush:php;toolbar:false;">server {
listen 80;
access_log $log_path main; # ✅ 在 server 级生效
...
}}
区分动静态路径时注意正则优先级和贪婪匹配
如果业务同时有 /api/v1/users 和 /api/v1/static/avatar.jpg,且你想把静态资源单独归档,但又不想干扰 API 日志,就得小心正则顺序——map 是按书写顺序从上到下匹配,第一个满足的即生效。
使用tbot机器ID身份文件配合tsh CLI,通过Teleport访问控制SSH登录托管主机或执行远程命令。
- 把更具体的路径(如带文件扩展名)放在前面,例如:
~^/api/v1/static/.*\.(jpg|png|js|css)$ - 避免用
.*开头的宽泛正则(如~/api/)放在前面,否则它会吃掉所有子路径,后续规则永不触发 -
$uri不含 query string,所以/api/v1/list?sort=desc仍匹配~^/api/v1/list,无需额外处理参数
错误示范(后一条永远不执行):
map $uri $log_path {
~^/api/ /var/log/nginx/api.log; # ❌ 覆盖全部 /api/*
~^/api/v1/static/ /var/log/nginx/static.log; # ⚠️ 实际不会命中
}
权限与轮转问题:Nginx worker 进程必须能写入所有目标目录
多个 access_log 文件意味着多个磁盘写入点。如果某个路径对应日志文件所在目录不存在,或 Nginx 用户(如 www-data)无写权限,Nginx 不报错,但该路径的日志会静默丢失——只在 error_log 里记一条 open() "/var/log/nginx/xxx.log" failed (13: Permission denied)。
- 提前创建所有日志目录,并确保属主和权限正确:
sudo mkdir -p /var/log/nginx/{api,admin,health} && sudo chown www-data:adm /var/log/nginx/* - logrotate 配置需显式列出每个文件,不能只靠通配符(如
/var/log/nginx/*.log可能漏掉新添加的路径) - 若启用
buffer或gzip参数(如access_log $log_path main buffer=64k gzip=1),要确认磁盘空间足够应对突发缓冲积压
调试 map 匹配结果:用 $log_path 做响应头临时验证
上线前不确定某条请求是否走对了日志路径?可以在 server 块里加个临时响应头输出 $log_path 值,用 curl 验证:
add_header X-Log-Path $log_path;
然后请求 curl -I http://your.site/api/v1/status,看响应头是否为 X-Log-Path: /var/log/nginx/api_v1.log。这比翻 error_log 更快定位映射逻辑缺陷。
真正上线时记得删掉这行——暴露日志路径可能泄露内部结构,尤其当路径含环境标识(如 prod-api.log)时。
最易被忽略的是:Nginx reload 后,旧 worker 进程仍持有已删除日志文件的 fd,新日志会继续写入旧文件(即使文件已被 mv)。务必配合 kill -USR1 或使用 logrotate 的 create 指令保证文件句柄及时切换。










