nginx 默认首页竟是软链接:NFS 共享给 web 集群后为何不生效

发布时间:2026/10/14 4:57:21
nginx 默认首页竟是软链接:NFS 共享给 web 集群后为何不生效 装完 nginx把站点目录用 NFS 共享给几台后端 web 机df明明显示挂上了客户端访问却还是老样子——要么 403/404要么显示它自己本机的默认页。这篇把这条链路拆开为什么文件明明在共享目录里却传不过去、怎么三步确认、怎么修以及几类长得很像但其实不是的原因。本文概要项目内容文章主题定位并修复「nginx 默认站点目录里含软链接 → 用 NFS 共享给其他分流主机后内容不生效」的问题给出确认步骤与三种修法所属类别Linux 系统管理 → 网络文件共享 / Web 服务 → NFS 共享与 nginx 站点目录知识关键字nginx·NFS·软链接·/usr/share/nginx/html·/etc/exports·mount·readlink·cp -L·find·httpd_use_nfs主线这样走先看现象与复现环境一再讲清软链接是本机概念这个根因二。三步确认三→ 三种修法与取舍四→ 排错速查五。文中命令名均标注英文全称如cp copy完整清单见文末《附命令英文全称速查表》。一、现象共享出去了客户端还是老样子先看一套典型的多机实验一台 NFS 服务端管存储三台 web 机做分流后端共用同一份站点内容。主机名IP角色nfs10.1.2.100共享存储导出站点目录web1 / web2 / web310.1.8.11~13分流后端运行 nginx 并挂载共享目录client110.1.8.21内网客户端服务端准备内容并导出# nfs 上准备站点目录并导出 [rootnfs ~]# mkdir -p /usr/share/nginx/html # -p父目录不存在就一起创建 [rootnfs ~]# echo Welcome to www.zhb.cloud /usr/share/nginx/html/index.html [rootnfs ~]# echo /usr/share/nginx/html 10.1.2.0/24(rw,sync) /etc/exports [rootnfs ~]# systemctl enable nfs-server.service --now # --now设为开机自启并立即启动web 机装好 nginx 与 NFS 客户端工具再挂载# web1~web3 上装包并挂载 [rootweb1 ~]# yum install -y nginx nfs-utils # -y自动确认 [rootweb1 ~]# echo 10.1.2.100:/usr/share/nginx/html /usr/share/nginx/html nfs defaults 0 0 /etc/fstab [rootweb1 ~]# systemctl daemon-reload [rootweb1 ~]# mount -a # -a挂载 /etc/fstab 里所有还没挂的条目 [rootweb1 ~]# df -h /usr/share/nginx/html # -h容量按 K/M/G 显示 文件系统 容量 已用 可用 已用% 挂载点 10.1.2.100:/usr/share/nginx/html 17G 1.5G 16G 9% /usr/share/nginx/htmldf显示挂载成功、nginx 也起来了可客户端拿到的不是共享内容[rootclient1 ~]# curl -s 10.1.8.11 | head -3 # -s静默模式不显示进度输出的要么是 403/404要么是 web1 自己的默认欢迎页。⚠️注意df显示挂上了≠ 站点内容对。挂载只关心网络通不通、服务端导没导它完全不管目录里的软链接能不能在你这台机器上解析开。二、根因软链接是本机概念NFS 只搬目录树2.1 默认首页本来就是个软链接在装了 nginx 的机器上瞄一眼默认站点目录[rootrouter html]# ls -l /usr/share/nginx/html/ # -l长格式能看出链接指向 总用量 12 -rw-r--r-- 1 root root 3650 11月 10 2022 404.html -rw-r--r-- 1 root root 3693 11月 10 2022 50x.html lrwxrwxrwx 1 root root 20 10月 13 04:24 en-US - ../../doc/HTML/en-US drwxr-xr-x 2 root root 27 10月 13 04:24 icons lrwxrwxrwx 1 root root 18 10月 13 04:24 img - ../../doc/HTML/img lrwxrwxrwx 1 root root 25 10月 13 04:24 index.html - ../../doc/HTML/index.html -rw-r--r-- 1 root root 368 11月 10 2022 nginx-logo.png lrwxrwxrwx 1 root root 14 10月 13 04:24 poweredby.png - nginx-logo.png第一列开头是l的就是软链接。重点看index.html——它不是普通文件而是一条指向../../doc/HTML/index.html的链接。从/usr/share/nginx/html往上退两级就是/usr/share所以这条链接的真身是/usr/share/doc/HTML/index.html。换句话说这个目录里根本没有真正的首页文件真身在隔壁/usr/share/doc/下面。Debian / Ubuntu 系apt install nginx是同一个套路只是换成绝对路径的写法index.html指向/var/www/html/index.nginx-debian.html。判据照旧——ls -l第一列是不是l。2.2 挂载点拿到的是链接不是内容NFS 的传递方式是服务端把目录树里的条目原样交给客户端软链接也原样交过去。客户端要读它时是在客户端本机解析这条链接的——NFS 不会替你跳过去。于是不外乎三种结局链接目标相对挂载点解析落到了客户端自己的文件系统上客户端上恰好也有那个文件比如它也装了 nginx→ 一直显示它自己的页面共享内容等于没生效客户端上没有那个文件 → 链接悬空断链→ nginx 直接报403 / 404。同一个目录里对照着看更清楚poweredby.png - nginx-logo.png是就地链接目标nginx-logo.png就在/usr/share/nginx/html/里跟着目录树一起被导出客户端照样打得开而index.html - ../../doc/HTML/index.html往上级跑目标跑出了导出范围就废了。判据只有一条链接的目标是否还在同一棵被导出的目录树里。在里面就跟得走跑出去就废。⚠️注意别以为相对链接就安全。相对链接照样能跑出去这里的../../就是绝对链接则必然指到客户端本地。真正要看的不是相对还是绝对而是目标在不在导出树内。2.3nohide/crossmnt治不了这个病有人会想到/etc/exports里的nohide、crossmnt。那是解决挂载点被隐藏的一个文件系统挂在另一个被导出的目录里子挂载点默认不显示给客户端。它管的是挂载不管软链接——链接跨出去的目标加这两个选项也搬不过来。另外/etc/exports里的导出路径本身也不能含软链接。若/abc/logs是一条链接服务端会直接拒绝挂载日志里写的是symbolic link in export path or statfs failed。三、三步确认你踩的就是这个坑在客户端web 机上按顺序敲三条# 1) 挂载点里的首页是不是链接 [rootweb1 ~]# ls -l /usr/share/nginx/html/index.html lrwxrwxrwx 1 root root 25 10月 13 04:24 /usr/share/nginx/html/index.html - ../../doc/HTML/index.html # 2) 这条链接在“本机”解析到哪个真实文件 [rootweb1 ~]# readlink -f /usr/share/nginx/html/index.html # -f递归解析成最终绝对路径 /usr/share/doc/HTML/index.html # 3) 这个真实文件落在哪个文件系统上 [rootweb1 ~]# df -h /usr/share/doc/HTML/index.html 文件系统 容量 已用 可用 已用% 挂载点 /dev/sda2 17G 4.1G 13G 25% / # 本机磁盘不是 10.1.2.100:/...三条一对上就确诊了链接在跑目标却落在客户端自己的本地磁盘上——这跟 NFS 一点关系都没有。想一次看清整棵目录里还有多少条链接[rootweb1 ~]# find /usr/share/nginx/html -type l # -type l只匹配软链接 /usr/share/nginx/html/index.html /usr/share/nginx/html/img /usr/share/nginx/html/en-US /usr/share/nginx/html/poweredby.pngls用法速查表参数含义英文原意ls列出目录内容list-l长格式权限位、链接数、属主、大小、时间、链接目标long listing format-a连以.开头的隐藏项一起列all-h容量按 K/M/G 显示配合-l用human-readable-d只看目录本身不展开里面的内容directory-R递归列出子目录recursive-i显示 inode 号inode-Z显示 SELinux 上下文长选项--contextcontext位置参数要列出的文件或目录—readlink用法速查表参数含义英文原意readlink打印软链接指向的目标路径read link-f递归解析成最终绝对路径除最后一段外路径各段都必须存在canonicalize-e同-f但要求每一段都存在否则报错canonicalizeall must exist-n输出结尾不加换行no newline-v出错时打印诊断信息verbose位置参数软链接路径—find用法速查表参数含义英文原意find在目录树里按条件查找find-type l只匹配软链接-L生效时只匹配断链type: symbolic link-xtype l只匹配断链指向不存在的目标type of link target-L跟随软链接配合-type l可专门找断链follow symbolic links-maxdepth N限制递归层数maximum depth-name 模式按文件名匹配name-ls命中项按ls -l格式打印list in ls format-exec 命令 {} \;对每个命中项执行命令execute位置参数起始目录—df用法速查表参数含义英文原意df查看各文件系统的容量与挂载点disk free-h容量按人类可读单位显示human-readable-T额外显示文件系统类型type-i改看 inode 使用量而非块inode位置参数指定文件或目录只显示它所在的那个文件系统—⚠️注意find的-type l与-xtype l用法不同。默认-P下-type l会列出所有软链接要专门找断链用-xtype l或加-L后再用-type l。判断一个目录能不能直接拿去共享先跑一遍find 目录 -type l。四、修复三种做法按场景挑4.1 服务端把软链接实体化推荐思路把链接换成真实文件让内容真正落在被导出的那棵树里。单个文件就地替换# 在 nfs服务端上执行 [rootnfs ~]# cd /usr/share/nginx/html [rootnfs html]# cp --remove-destination $(readlink -f index.html) index.html [rootnfs html]# ls -l index.html -rw-r--r-- 1 root root 26 10月 13 11:20 index.html # 第一列变成 -已是真实文件--remove-destination是关键它先把同名的软链接删掉再落真实文件。不加这个选项时cp会顺着链接写进目标文件目录里留下的还是一条链接。整棵目录实体化后再共享# 把链接全部解引用复制成一棵“纯真实文件”的目录再改导出指向 [rootnfs ~]# cp -rL /usr/share/nginx/html/. /srv/webroot/ [rootnfs ~]# find /srv/webroot -type l # 再扫一遍应当没有任何输出 [rootnfs ~]# echo /srv/webroot 10.1.2.0/24(rw,sync) /etc/exports [rootnfs ~]# exportfs -rv # -r重读 /etc/exports 重新导出-v显示过程cp用法速查表参数含义英文原意cp复制文件或目录copy-r-R递归复制整个目录recursive-L跟随软链接复制目标文件的内容dereference-P不跟随软链接把链接本身复制过去-r时的默认行为no-dereference-a归档模式等价于-dR --preserveallarchive--remove-destination覆盖前先删掉同名目标用来把链接换成真实文件remove destination-p保留权限、属主、时间戳preserve-v显示复制过程verbose位置参数源路径 与 目标路径—⚠️注意不加-L时cp对递归中遇到的链接默认是原样复制等于把坑照搬过去。要解引用要么加-L要么就地替换时用--remove-destination。4.2 换个只放真实文件的共享目录最干净更省事的做法别共享软件包自带的模板目录另起一个专门放内容的目录。# 服务端新建一个纯内容目录NFS 导出它 [rootnfs ~]# mkdir -p /srv/webroot [rootnfs ~]# cp -r /path/to/你的站点内容/. /srv/webroot/ [rootnfs ~]# echo /srv/webroot 10.1.2.0/24(rw,sync) /etc/exports [rootnfs ~]# exportfs -rv # 客户端换挂载点nginx 的 root 也指过去 [rootweb1 ~]# umount /usr/share/nginx/html [rootweb1 ~]# mkdir -p /srv/webroot [rootweb1 ~]# mount -t nfs 10.1.2.100:/srv/webroot /srv/webroot # -t nfs指定文件系统类型再把 nginx 配置里的root从/usr/share/nginx/html改成/srv/webrootnginx -t校验通过后reload。好处很直接共享目录里的每个文件都是真实文件谁挂上去都读得到不用再操心链接解析。mount用法速查表参数含义英文原意mount挂载文件系统mount-t nfs指定文件系统类型type-a挂载/etc/fstab里所有尚未挂载的条目all-o指定挂载选项逗号分隔options-l列出时带上挂载来源标签list--bind把一个目录挂到另一个位置绑定挂载bind位置参数设备或远端路径以及本地挂载点—exportfs用法速查表参数含义英文原意exportfs管理 NFS 导出表export file systems-r重读/etc/exports并重新导出reexport-a对全部条目操作配-u即全部取消导出all-u取消导出unexport-o追加导出选项options-v显示详细输出verboseshowmount用法速查表参数含义英文原意showmount查询 NFS 服务端的导出情况show mount-e列出服务端已导出的目录清单exports-a列出所有已挂载过的客户端all-d只列出被挂载过的目录directories位置参数NFS 服务端地址—4.3 写内容时别踩重定向跟随软链接这一脚还有个很容易中招的细节给默认首页写内容时用了重定向。# 看着像是在共享目录里写首页其实写进了链接的真身 [rootnfs ~]# echo Welcome to www.zhb.cloud /usr/share/nginx/html/index.html会跟随软链接上面这条实际写进了/usr/share/doc/HTML/index.html——共享目录里躺着的那条链接一点没变客户端自然读不到。要真正写进共享目录先把链接删掉[rootnfs ~]# rm /usr/share/nginx/html/index.html # 删掉链接本身不影响原文件 [rootnfs ~]# echo Welcome to www.zhb.cloud /usr/share/nginx/html/index.html [rootnfs ~]# ls -l /usr/share/nginx/html/index.html -rw-r--r-- 1 root root 26 10月 13 11:20 /usr/share/nginx/html/index.html4.4 三种做法怎么选做法适合场景代价就地实体化--remove-destination只想修某一个文件改动最小只解决这一个文件整棵目录实体化cp -rL目录里链接不少还想沿用原路径多占一份磁盘换独立内容目录/srv/webroot新搭的集群能一次规划到位要同步改 nginx 的root不管选哪种收尾都跑一遍find 共享目录 -type l输出为空才算干净。五、排错速查几种长得像但另有原因的情况先看现象再对症下药403 / 404先确认挂载点不是空的再看 SELinux——RHEL 系上 NFS 挂载点的上下文是nfs_tnginx 默认读不了要开布尔值httpd_use_nfs最后看权限NFS 默认root_squash会把 root 映射成匿名用户权限给到位才读得动。显示本机默认页ls -l一看首页是l开头那就是本文这个坑去服务端做实体化。内容还是旧的df确认真的挂上了再检查是不是先写了本地页、后挂载——挂载会把挂载点里的原有内容遮住不是删掉卸载后还在服务端改了内容而客户端缓存没过期时remount一次即可。setsebool用法速查表参数含义英文原意setsebool开关 SELinux 布尔值set SELinux boolean-P同时写入策略重启后仍然生效persistent位置参数布尔值名以及on/off—# RHEL / CentOS 系允许 web 服务读取 NFS 上的内容 [rootweb1 ~]# setsebool -P httpd_use_nfs on [rootweb1 ~]# getenforce # 查看 SELinux 当前模式 # 若仍被拦看审计日志确认拦截点 [rootweb1 ~]# ausearch -m avc -ts recent | tail -5 # -m按消息类型过滤⚠️注意不要拿chmod -R 777或setenforce 0当常规收场手段。前者会连带把共享目录的写权限整片放开后者只是临时关掉一整个安全层都该在定位清楚之后再定方案。附命令英文全称速查表命令 / 缩写英文全称 / 原意作用lslist列出目录内容readlinkread link查看软链接指向findfind在目录树里查找文件dfdiskfree查看文件系统容量与挂载点cpcopy复制文件或目录mountmount挂载文件系统umountunmount卸载文件系统exportfsexport file systems管理 NFS 导出表showmountshow mount查询 NFS 导出与挂载情况setseboolset SELinux boolean开关 SELinux 布尔值getenforceget enforce查看 SELinux 当前模式NFSNetwork File System网络文件系统SELinuxSecurity-Enhanced Linux强制访问控制安全模块RPCRemote Procedure Call远程过程调用NFS 的通信底座 参考资料官方文档 · 中英双语英文原版nginx Beginners Guide官方文档cp(1) 手册 · man7.org中文版网络文件系统 NFS · 共享目录因使用符号链接导致错误FreeBSD 中文文档其余手册在服务器上直接查无需联网man 1 ls # 列出目录 man 1 readlink # 查看链接指向 man 1 find # 目录树查找 man 1 cp # 复制 man 8 mount # 挂载 man 5 exports # NFS 导出配置 man 8 exportfs # 导出表管理 man 8 showmount # 查询导出总结NFS 共享的是目录树而软链接是本机概念——链接目标一旦跑出导出树客户端就只能按自己的文件系统去解析于是要么指到本机旧文件、要么直接断链。修法归根到底一句话让真实文件待在被导出的那棵树里改完用find 目录 -type l扫一遍收尾。同系列 · Linux 集群与 Web 服务其余篇目见博客主页blog.csdn.net/nbsxl相关篇《Nginx upstream 负载均衡》《HAProxy 负载均衡》《LVS 负载均衡》 你搭 web 集群时NFS 共享踩过什么坑评论区贴出报错一起看。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询