nginx快捷方式指向文件夹访问问题的排查解决之路

2个月前发布 gsjqwyl
16 0 0

文章标题:nginx解决文件夹访问指向问题的探索历程

事情的起因是项目中有一个文件域名,dns将其解析到了Linux系统的服务器上,有个nginx服务对挂载在nas上的一个文件目录做了反向代理。现在有新需求,要让客户依旧通过这个域名作为访问入口,去访问同样在nas盘里且和那个目录同级的另一个目录下的文件。

比如说,通过nginx反向代理访问的nas盘下的目录路径是/mnt/picture/,访问的url是:https://picture.test.cn/cache/20260101/1749690185966.jpg

而和picture同级的目录路径是:/mnt/bak/,期望的访问url是:https://picture.test.cn/bak/20251024/1749690185966.jpg

我最先想到的办法是借助软连接,把/mnt/bak目录软连接到/mnt/picture/bak目录,命令如下:

ln -s /mnt/bak/ /mnt/picture/bak

nginx的简略配置如下:

server {
    listen 443;
    server_name picture.test.cn;
    ...

    location / {
        root /mnt/picture/;
    }
}

访问是没问题的,当然也可以通过增加一个location,用bak关键字来代理/mnt/bak/目录。

本地开发机器是Windows10,在一个盘符下创建了两个文件夹来模拟Linux机器上的挂载盘目录进行开发测试,nginx的简略配置如下:

server {
    listen 8066;
    server_name picture.test.cn;

    location / {
        root D:/tmp/mnt/picture/;
    }
}

两个目录分别是:D:/tmp/mnt/picture/D:/tmp/mnt/bak

我在D:/tmp/mnt/picture/下创建了一个D:/tmp/mnt/bak目录的快捷方式,快捷方式名称叫bak,还在hosts文件中配置了域名到本机的映射。

但访问http://picture.test.cn:8066/bak/20251024/1749690185966.jpg时却提示文件不存在,nginx的error日志如下:

2026/10/24 09:41:16 [error] 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"

明明在文件系统里点击快捷方式能进到对应的文件夹,可nginx却识别不了,问了下ai(不得不说现在ai真是个好帮手),核心原因有这些:

1.快捷方式的本质是特殊文件

Windows快捷方式(.lnk)属于系统级的符号链接文件,得由操作系统来解析路径。但Nginx作为Web服务器,只会读取实际的文件或目录内容,不会去解析.lnk文件的目标路径。

2.Nginx配置依赖物理路径

Nginx的root或alias指令得指向真实的目录(比如D:\folder),要是指向包含快捷方式的目录,Nginx会把快捷方式当作普通文件而非目录入口,从而导致访问失败。

3.路径安全限制

Nginx默认禁止访问路径中包含符号链接的文件(这是安全策略),而且Windows路径格式(反斜杠\、中文名等)容易引发兼容性问题。

ai给出的解决方案是:

1.用NTFS联结点实现类似Linux软链接的效果

文件系统得是NTFS,以管理员身份运行CMD,命令如下:

mklink /J "D:\tmp\mnt\picture\bak" "D:\tmp\mnt\bak"

2.修改Nginx配置来启用路径解析

在nginx的location下添加如下配置:

disable_symlinks off;  # 允许解析符号链接

其中disable_symlinks在nginx的1.1.15版本中添加,默认是开启的,需要在编译nginx时加上--with-file-aio参数。

通过nginx -vnginx -V确认项目上使用的nginx版本是1.22.0,服务器上的nginx也启用了--with-file-aio参数。

为啥Nginx在Linux支持软链接而Windows不支持快捷方式呢?ai给出了解答:

  • Linux:Nginx通过系统调用(比如open())访问文件时,内核会自动解析软链接路径,服务不需要额外处理。
  • Windows:Nginx直接读取文件系统,但.lnk是需要解析的二进制文件,不是标准的目录入口,所以没法识别它指向的真实路径。

按照ai给出的解决方案,我在本地Windows机器上用mklink创建了目录联结:

mklink /J "D:\tmp\mnt\picture\bak" "D:\tmp\mnt\bak"

再次访问http://picture.test.cn:8066/bak/20251024/1749690185966.jpg就能访问了。

我让ai详细说说mklink

mklink是Windows系统(Vista及以上版本)提供的命令行工具,用来创建文件或目录的链接,功能类似Linux中的ln命令,但实现机制和类型划分更复杂。以下是它的核心特性和使用场景的详细解析:

1.mklink的链接类型

类型 参数 特点 适用场景
符号链接 /D 跨分区支持,需要管理员权限,路径可以是相对或绝对,远程访问时可能不解析 需灵活路径映射(如开发环境配置)
目录联结 /J 仅限目录,不需要管理员权限,远程访问时自动解析目标路径 迁移大目录保留原始路径(如程序文件)
硬链接 /H 仅限文件,跨分区无效,删除任一链接不影响其他副本 节省空间(如备份重复文件)

2.关键差异与注意事项

  • 权限要求
    符号链接(/D)和文件硬链接(/H)需要管理员权限运行CMD,目录联结(/J)则不需要。

  • 路径解析
    符号链接支持相对路径(比如..\target),联结只支持绝对路径。
    移动符号链接可能会让相对路径失效,而联结的绝对路径仍然有效。

  • 跨分区限制
    硬链接不能跨分区,符号链接和联结可以跨分区但需要目标存在。

可以看到通过快捷方式和mklink命令创建出来的文件可以同名,但类型不一样,一个是快捷方式,一个是文件夹:

ai还提到nginx的disable_symlinks标签是为了防止攻击者通过上传符号链接文件访问/etc/passwd等系统文件,我在Windows上测试添加这个标签时发现,Windows上的nginx不支持这个标签,核心限制原因如下:
1.平台兼容性问题
disable_symlinks是Nginx针对类Unix系统(比如Linux)设计的特性,依赖文件系统符号链接权限检查机制,而Windows NTFS文件系统的符号链接管理逻辑和它不兼容,导致该指令在Windows环境下无效或无法正确解析。
尝试在Windows配置中使用时,nginx -t会提示语法错误或未知指令(比如unknown directive “disable_symlinks”)。
2.版本无实质支持
就算用户用的是较新的Nginx 1.22.0或更高版本,其Windows编译版也没适配这个功能。官方在Windows构建中没启用相关依赖模块(比如–with-file-aio)。

本地Windows机器只是用来开发测试,不影响,生产服务器上得严格做好目录权限的划分,并且在上传文件的入口强烈校验文件的类型。

© 版权声明

相关文章

没有相关内容!

暂无评论

none
暂无评论...