起因是项目上有一个文件域名,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/目录。

本地开发机器是windwos10,在一个盘符下创建了两个文件夹模拟了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 联结点(Junction Point)实现类似 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)。

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

记一次nginx访问快捷方式指向的文件夹失败的排查解决过程的更多相关文章

  1. C# 读取快捷方式指向的文件

    C# 读取快捷方式指向的文件 [Flags()] public enum SLR_FLAGS { SLR_NO_UI = 0x1, SLR_ANY_MATCH = 0x2, SLR_UPDATE = ...

  2. nginx 访问localhost老是下载文件不能打开网页什么情况?

    nginx打开网页直接下载文件的问题 nginx sites-available文件里的default已经修改过root 路径了. 但是访问localhost的时候总是直接下载网页而不是打开网址 很奇 ...

  3. Tomcat不能访问ln -s软连接文件夹的前因后果

    为了部署方便,把webapps下的大文件(图片等资源)放到工程外,通过软连接的方式设置 命令最常用的参数是-s,具体用法是:ln -s 源文件 目标文件. ln -s /usr/local/pic/i ...

  4. Linux怎样访问Windows共享文件和文件夹

    常常使用Windows的人可能会发现,Windows计算机之前共享资料非常方便,但是有时候想玩玩Linux的时候,如Fedora.Ubuntu.CentOS等,该怎样才能访问Windows计算机上的文 ...

  5. win7+Apache 设置域名指向本地文件夹

    实现:浏览器地址栏输入 www.bnzoo.com 访问 D:/www 系统:win7旗舰版+Apache 步骤: 1.打开文件 C:\Windows\System32\drivers\etc\hos ...

  6. 深入Jar包:Gradle构建可执行jar包与访问jar包中文件夹与文件

    前言 Java的跨平台功能听起来很诱人可口,号称"Write Once,Run Everywhere",实际上是"Run Once,Debug Everywh" ...

  7. nginx二级域名指向不同文件项目配置

    需要使用泛域名解析, 并且加上空的判断,以保证没有二级域名的也可以访问 核心配置 server_name ~^(?<subdomain>.+)\.caipudq\.cn$;if ( $su ...

  8. nginx 服务器在上传文件出现413代码的解决方法

    打开nginx主配置文件nginx.conf 找到http{}段,添加client_max_body_size 20m;

  9. 记一次线上频繁fullGc的排查解决过程

    发生背景 最近上线的一个项目几乎全是查询业务,并且都是大表的慢查询,sql优化是做了一轮又一轮,前几天用户反馈页面加载过慢还时不时的会timeout,但是我们把对应的sql都优化一遍过后,前台响应还是 ...

  10. 记一次u盘 无法格式化、0字节、写保护的解决过程

    首先各种找方法,下载了一堆烂七八糟的东西都没能解决 后来看了这个链接的文章 http://jingyan.baidu.com/article/6079ad0e5bdec428ff86dbcd.html ...

随机推荐

  1. VUE构建

    VUE 渐进式 JavaScript 框架 易学易用 基于标准 HTML.CSS 和 JavaScript 构建,提供容易上手的 API 和一流的文档. 性能出色 经过编译器优化.完全响应式的渲染系统 ...

  2. C++11 Lambda表达式(匿名函数)详解

    使用STL时,往往会大量用到函数对象,为此要编写很多函数对象类.而有的函数对象类只用定义一个对象,而且这个对象也只使用一次,那编写这样一个函数对象就很浪费了.而且有时这定义函数对象类的地方和使用函数对 ...

  3. 通过COM,用Python调用C#库

    1.C#配置 (1)类库 (2)COM互操作打勾 (3)代码中类必须要有无参构造函数,否则不会注册成功!!! using System; using System.Runtime.InteropSer ...

  4. 消息队列, 一种取舍的选择 Redis Stream

    人多公司方便多个业务方解耦, 常用一些成熟的消息队列. 会有专门部门帮你维护好. 但在小公司, 看成本靠个人. 有的简单可能就是 redis list or mysql 存一些状态, 有问题了就自己手 ...

  5. win10无选字框

    设置-->时间与语言-->语言-->中文-->选项 下滑到最底 微软拼音-->选项 常规-->(下滑到最底)打开使用以前版本的微软拼音输入法-->确定

  6. cygwin补充安装gcc/g++的方法

    安装cygwin如果按照默认的方式一直点下去的话,安装完了会发现没有安装gcc/g++. 这个时候可以在安装文件的目录打开命令行,并输入: setup-x86_64.exe -q -P wget -P ...

  7. springboot实现连接多个数据源

    dynamic datasource 导入依赖 <dependency> <groupId>com.baomidou</groupId> <artifactI ...

  8. Elastic学习之旅 (8) 深入词项和全文搜索

    大家好,我是Edison. 上一篇:Elastic学习之旅 (7) 聚合分析 相信很多童鞋和我一样,有点傻傻分不清Term查询和全文查询的区别,那么今天我们就来一起梳理一下. 基于Term的查询 Te ...

  9. 基于 swoole 下 异步队列和毫秒定时任务 API

    说明 1.在 Server 程序中如果需要执行很耗时的操作,比如一个聊天服务器发送广播,Web 服务器中发送邮件.如果直接去执行这些函数就会阻塞当前进程,导致服务器响应变慢. Swoole 提供了异步 ...

  10. dotnet (.Net) Core在不是Web 项目中使用HttpClientFactory正确用法

    在不是web 项目中也不是Api 中使用 HttpClientFactory 先需要添加 Microsoft.Extensions.DependencyInjection.Abstractions M ...