记一次nginx访问快捷方式指向的文件夹失败的排查解决过程
<p>起因是项目上有一个文件域名,dns解析到linux系统的服务器上,有一个nginx服务反向代理了一个位于nas挂载盘内的文件目录,现在有一个新需求是让客户还是通过这个域名作为访问入口,访问同样位于nas盘中和这个目录同级的另一个目录内的文件。</p><p>比如通过nginx反向代理访问的nas盘下的目录路径为<code>/mnt/picture/</code>,访问的url为:<code>https://picture.test.cn/cache/20260101/1749690185966.jpg</code></p>
<p>和<code>picture</code>同级的目录路径为:<code>/mnt/bak/</code>,期望的访问url为:<code>https://picture.test.cn/bak/20251024/1749690185966.jpg</code></p>
<p>我第一时间想到的就是通过软连接的方式,将<code>/mnt/bak</code>目录软连接到<code>/mnt/picture/bak</code>目录:</p>
<pre><code>ln -s /mnt/bak/ /mnt/picture/bak
</code></pre>
<p>nginx的配置简略如下:</p>
<pre><code>server {
listen 443;
server_name picture.test.cn;
...
location / {
root /mnt/picture/;
}
}
</code></pre>
<p>访问没有问题,当然还可以通过增加一个location,使用<code>bak</code>关键字代理<code>/mnt/bak/</code>目录。</p>
<p>本地开发机器是windwos10,在一个盘符下创建了两个文件夹模拟了linux机器上的挂载盘目录进行开发测试,nginx的配置简略如下:</p>
<pre><code>server {
listen 8066;
server_name picture.test.cn;
location / {
root D:/tmp/mnt/picture/;
}
}
</code></pre>
<p>两个目录分别是:<code>D:/tmp/mnt/picture/</code>、<code>D:/tmp/mnt/bak</code></p>
<p>我在<code>D:/tmp/mnt/picture/</code>下创建了一个<code>D:/tmp/mnt/bak</code>目录的快捷方式,快捷方式的名称叫<code>bak</code>,hosts文件中配置域名到本机的映射。</p>
<p>访问<code>http://picture.test.cn:8066/bak/20251024/1749690185966.jpg</code>却提示我文件不存在:</p>
<p>nginx的error日志如下:</p>
<pre><code>2026/10/24 09:41:16 16584#7532: *4 CreateFile() "D:/tmp/mnt/picture/bak/20251024/1749690185966.jpg" failed (3: The system cannot find the path specified), client: 127.0.0.1, server: picture.test.cn, request: "GET /bak/20251024/1749690185966.jpg HTTP/1.1", host: "picture.test.cn:8066"
</code></pre>
<p>明明我可以在文件系统中点击快捷方式进入对应的文件夹,为啥nginx却不识别,问了下ai(不得不说现在ai确实是一个好帮手),其核心原因有这些:</p>
<p><strong>1.快捷方式本质是特殊文件</strong></p>
<p>Windows快捷方式(.lnk)是系统级符号链接文件,需由操作系统解析路径。但Nginx作为Web服务器,仅读取实际文件或目录内容,不会解析.lnk文件的目标路径。</p>
<p><strong>2.Nginx配置依赖物理路径</strong></p>
<p>Nginx的root或alias指令需指向真实目录(如D:\folder),若指向含快捷方式的目录,Nginx会将快捷方式视为普通文件而非目录入口,导致访问失败。</p>
<p><strong>3.路径安全限制</strong></p>
<p>Nginx默认禁止访问路径含符号链接的文件(安全策略),且Windows路径格式(反斜杠\、中文名等)易引发兼容性问题。</p>
<p>ai提供了解决方案:</p>
<p><strong>1.NTFS 联结点(Junction Point)实现类似 Linux 软链接的效果</strong></p>
<p>文件系统需要是NTFS,以管理员身份运行CMD:</p>
<pre><code>mklink /J "D:\tmp\mnt\picture\bak" "D:\tmp\mnt\bak"
</code></pre>
<p><strong>2.修改Nginx配置启用路径解析</strong></p>
<p>nginx的location下增加如下配置:</p>
<pre><code>disable_symlinks off;# 允许解析符号链接
</code></pre>
<p>其中disable_symlinks于nginx的1.1.15版本中增加,默认开启,需要在编译nginx时增加<code>--with-file-aio</code>参数。</p>
<p>通过<code>nginx -v</code>和<code>nginx -V</code>确认项目上使用的nginx版本为1.22.0,服务器上的nginx也启用了<code>--with-file-aio</code>参数。</p>
<p>为何Nginx在Linux支持软链接而Windows不支持快捷方式?ai给出了回答:</p>
<ul>
<li>Linux:Nginx 通过系统调用(如 open())访问文件时,内核自动解析软链接路径,服务无需额外处理。</li>
<li>Windows:Nginx 直接读取文件系统,但 .lnk 是需解析的二进制文件,非标准目录入口,因此无法识别其指向的真实路径。</li>
</ul>
<p>按照ai给出的解决方案,我在本地windows机器上使用mklink创建了目录联结:</p>
<pre><code>mklink /J "D:\tmp\mnt\picture\bak" "D:\tmp\mnt\bak"
</code></pre>
<p>再次访问<code>http://picture.test.cn:8066/bak/20251024/1749690185966.jpg</code>已经可以访问。</p>
<p>我让ai详细说说<code>mklink</code></p>
<p>mklink 是 Windows 系统(Vista 及以上版本)提供的命令行工具,用于创建文件或目录的链接,其功能类似于 Linux 中的 ln 命令,但实现机制和类型划分更为复杂。以下是其核心特性和使用场景的详细解析:</p>
<p><strong>1.mklink 的链接类型</strong></p>
<table>
<thead>
<tr>
<th style="text-align: left">类型</th>
<th style="text-align: left">参数</th>
<th style="text-align: left">特点</th>
<th style="text-align: left">适用场景</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">符号链接</td>
<td style="text-align: left">/D</td>
<td style="text-align: left">跨分区支持,需管理员权限,路径可相对或绝对,远程访问时可能不解析</td>
<td style="text-align: left">需灵活路径映射(如开发环境配置)</td>
</tr>
<tr>
<td style="text-align: left">目录联结</td>
<td style="text-align: left">/J</td>
<td style="text-align: left">仅限目录,无需管理员权限,远程访问时自动解析目标路径</td>
<td style="text-align: left">迁移大目录保留原始路径(如程序文件)</td>
</tr>
<tr>
<td style="text-align: left">硬链接</td>
<td style="text-align: left">/H</td>
<td style="text-align: left">仅限文件,跨分区无效,删除任一链接不影响其他副本</td>
<td style="text-align: left">节省空间(如备份重复文件)</td>
</tr>
</tbody>
</table>
<p><strong>2.关键差异与注意事项</strong></p>
<ul>
<li>
<p>权限要求<br>
符号链接(/D)和文件硬链接(/H)需管理员权限运行 CMD,目录联结(/J)则不需要。</p>
</li>
<li>
<p>路径解析<br>
符号链接支持相对路径(如 ..\target),联结仅支持绝对路径。<br>
移动符号链接可能导致相对路径失效,而联结的绝对路径仍有效。</p>
</li>
<li>
<p>跨分区限制<br>
硬链接不可跨分区,符号链接和联结可跨分区但需目标存在。</p>
</li>
</ul>
<p>可以看到通过快捷方式和mklink命令创建出来的文件是可以同名的,但是其类型不一样,一个是快捷方式,一个是文件夹:<br>
<img src="https://img2024.cnblogs.com/blog/1407141/202506/1407141-20250620155020000-468996289.png"></p>
<p>ai还提到了nginx的<code>disable_symlinks</code>标签需要防止攻击者通过上传符号链接文件访问<code>/etc/passwd</code> 等系统文件,我在windows上测试添加这个标签发现,windows上的nginx并不支持这个标签,其核心限制原因如下:<br>
1.平台兼容性问题<br>
<code>disable_symlinks</code> 是 Nginx 针对类 Unix 系统(如 Linux)设计的特性,依赖文件系统符号链接权限检查机制,而Windows NTFS 文件系统的符号链接管理逻辑与此不兼容,导致该指令在 Windows 环境下无效或无法正确解析。<br>
尝试在 Windows 配置中使用时,nginx -t 会提示语法错误或未知指令(如 unknown directive "disable_symlinks")。<br>
2.版本无实质支持<br>
即使用户使用的是较新的 Nginx 1.22.0 或更高版本,其Windows 编译版仍未适配此功能。官方并未在 Windows 构建中启用相关依赖模块(如 --with-file-aio)。</p>
<p>本地windwos机器只是用来开发测试,倒是不影响,生产服务器上需要严格做好目录权限的划分以及在上传文件的入口强校验文件的类型。</p>
</div>
<div id="MySignature" role="contentinfo">
<p>本文来自博客园,作者:杜劲松,转载请注明原文链接:https://www.cnblogs.com/imadc/p/18938385</p><br><br>
来源:https://www.cnblogs.com/imadc/p/18938385
頁:
[1]