NFS服务器
NFS 服务器
目录
- 软件包安装
- 认识 NFS:是什么与版本差异
- NFS 服务端配置:/etc/exports 与 exportfs
- NFS 客户端挂载:mount 与开机自动挂载
- NFS 端口与防火墙放行
- NFS 权限与安全问题
- 常见问题排查清单
- 总结与练习
- 参考资料
软件包安装
NFS 需要服务端和客户端两套软件。在一台机器上可以同时安装两者。
服务端安装(Rocky / RHEL / CentOS)
sudo dnf install -y nfs-utils
# 启动并设置开机自启
sudo systemctl enable --now nfs-server
# 查看状态
sudo systemctl status nfs-server
说明:RHEL/Rocky 上 NFS 的服务名是
nfs-server(NFSv4)。某些老版本也叫nfs。
客户端安装
# 客户端也要 nfs-utils(提供 mount.nfs、showmount 等命令)
sudo dnf install -y nfs-utils
Ubuntu / Debian 差异
# 服务端
sudo apt install -y nfs-kernel-server
sudo systemctl enable --now nfs-server
# 客户端
sudo apt install -y nfs-common
常用验证命令
rpm -q nfs-utils # 查看是否安装
systemctl status nfs-server
showmount -e localhost # 查看本机导出的共享(见第二章)
一、认识 NFS:是什么与版本差异
1.1 一句话定义
NFS(Network File System) 允许你通过网络挂载另一台机器上的目录,就像访问本地目录一样。服务端把某个目录"共享/导出"出来,客户端把它挂载到自己的某个挂载点。
1.2 典型使用场景
- 多台服务器共享同一份数据(如共享上传目录、共享配置)。
- 无盘客户端、瘦客户端从服务器加载文件系统。
- 集群/分布式环境中共享存储(K8s 的 NFS 存储类、NFS Provisioner 等)。
1.3 NFS 版本差异
| 版本 | 特点 | 端口需求 |
|---|---|---|
| NFSv3 | 老版本,兼容性好 | 依赖 rpcbind(111)、mountd 等多个端口,防火墙配置复杂 |
| NFSv4 | 现代默认,性能与安全更好,单一 TCP 端口 | 主要用 2049/tcp,防火墙简单 |
- 现代 RHEL/Rocky 默认使用 NFSv4(
mount -t nfs4或默认-t nfs也倾向 v4)。 - NFSv4 也引入了类似 POSIX 的权限模型和更强的安全机制(Kerberos 可选)。
概念上理解:NFSv4 把端口和协议更集中化,所以防火墙只需要放开 2049,这也是为什么"NFS 常被防火墙挡住"在 v3 上尤为明显(见第四章)。
参考:Red Hat - NFS 官方文档
二、NFS 服务端配置:/etc/exports 与 exportfs
2.1 什么是 /etc/exports
NFS 服务端通过 /etc/exports 文件声明"把哪个目录共享给谁、以什么权限"。每行一条共享,格式为:
共享目录 客户端(选项1,选项2) 客户端2(选项)
客户端可以是:单个 IP、网段(CIDR)、主机名、通配符 *。
2.2 常见 exports 写法
# 把 /data 共享给整个 192.168.1.0/24 网段,读写
/data 192.168.1.0/24(rw,sync,no_subtree_check)
# 把 /data 共享给单个 IP,只读
/data 192.168.1.50(ro,sync)
# 共享给所有客户端,读写,且不禁用 root 压缩(危险,见第五章)
/data *(rw,sync,no_root_squash)
# 多客户端多选项
/data 192.168.1.0/24(rw,sync) 192.168.2.0/24(ro)
2.3 常用选项
| 选项 | 含义 |
|---|---|
ro / rw |
只读 / 读写 |
sync |
数据先写入磁盘再响应(更安全,默认推荐) |
async |
先响应再写盘(更快但不安全) |
root_squash |
把客户端的 root 映射为匿名用户(默认,安全) |
no_root_squash |
客户端的 root 保持 root 权限(危险) |
anonuid / anongid |
指定匿名用户映射到的 UID/GID |
no_subtree_check |
关闭子目录检查(提高性能,推荐) |
2.4 exportfs:让共享生效
改完 /etc/exports 后,用 exportfs 让配置生效(也可重启 nfs-server):
sudo exportfs -r # 重新读取 /etc/exports,应用所有共享
sudo exportfs -a # 导出所有共享
sudo exportfs -v # 详细显示当前导出的共享
sudo exportfs -ra # 重新导出全部(常用组合)
# 查看导出是否成功
sudo exportfs -v
showmount -e localhost # 在客户端可用 showmount 查看服务端共享
参考:Red Hat - Exporting NFS shares、Rocky Linux - NFS server
三、NFS 客户端挂载:mount 与开机自动挂载
3.1 手动挂载(mount)
客户端用 mount 把服务端共享挂载到本地目录:
# 创建挂载点
sudo mkdir -p /mnt/nfsdata
# 挂载服务端的 /data 到本地 /mnt/nfsdata
sudo mount -t nfs4 192.168.1.10:/data /mnt/nfsdata
# 或更通用(默认倾向 v4):
sudo mount -t nfs 192.168.1.10:/data /mnt/nfsdata
# 查看是否挂载成功
df -h | grep nfsdata
mount | grep nfs
-t nfs4显式用 NFSv4;-t nfs通用。- 也可加选项:
mount -t nfs4 -o rw,sync,nfsvers=4 192.168.1.10:/data /mnt/nfsdata。
3.2 卸载(umount)
sudo umount /mnt/nfsdata
卸载失败通常是"设备忙"(有进程在用),可用
lsof /mnt/nfsdata或fuser -km /mnt/nfsdata查看/结束占用进程后再卸载。
3.3 开机自动挂载(/etc/fstab)
想让 NFS 在开机时自动挂载,写入 /etc/fstab:
# 格式:服务端:共享 挂载点 类型 选项 备份 检查
192.168.1.10:/data /mnt/nfsdata nfs nfsvers=4,_netdev,rw 0 0
_netdev选项很关键:告诉系统这是网络文件系统,等网络就绪后再挂载,否则开机时网络还没起来会导致挂载失败。nfsvers=4指定版本;rw读写。- 第 5、6 列
0 0表示不备份、不做 fsck 检查(网络文件系统不适用)。
# 验证 fstab 配置是否正确(不重启就测试挂载)
sudo mount -a
# 全部按 fstab 挂载后查看
mount | grep nfs
参考:
man 5 nfs、man 5 fstab
四、NFS 端口与防火墙放行
NFS 常被防火墙挡住——这是 NFS 部署最典型的坑。原因是 NFS(尤其 v3)依赖多个动态端口,防火墙只放行 2049 往往不够。
4.1 NFS 用到的端口
| 服务 | 端口 | 说明 |
|---|---|---|
| NFS | 2049(tcp/udp) | 核心数据端口 |
| rpcbind | 111(tcp/udp) | 端口映射服务(NFSv3 必需) |
| mountd | 20048(tcp/udp) | 挂载守护进程(NFSv3) |
| nlockmgr、statd 等 | 高位随机端口 | NFSv3 锁定/状态,端口不定,最麻烦 |
- NFSv3:需要 2049 + 111 + 20048 + 一堆高位随机端口,防火墙配置很繁琐。
- NFSv4:主要只要 2049,防火墙简单很多。这也是推荐用 v4 的原因之一。
4.2 firewalld 放行(Rocky)
用 firewalld 自带的服务放行最省事(nfs、rpc-bind、mountd 三个服务):
# NFSv4:放行 nfs(2049),通常再加 rpc-bind(111)更稳
sudo firewall-cmd --permanent --add-service=nfs
sudo firewall-cmd --permanent --add-service=rpc-bind
# NFSv3:还需要 mountd(20048)
sudo firewall-cmd --permanent --add-service=mountd
# 重新加载生效
sudo firewall-cmd --reload
# 确认
sudo firewall-cmd --list-services
4.3 如果客户端还是连不上
- 先确认服务端防火墙放行了对应端口。
- 确认服务端相关服务都在运行:
systemctl status nfs-server rpcbind。 - 在客户端用
showmount -e 服务端IP测试能否看到共享;看不到多半是防火墙/端口问题。 - 若是 NFSv3 的高位随机端口,最稳妥的做法是改用 NFSv4(只需 2049)。
参考:Red Hat - Securing the NFS service(防火墙)
五、NFS 权限与安全问题
NFS 权限有两层:文件系统权限(结合权限模块)和 NFS 特有的 UID 映射。这是最容易出问题也最容易出安全漏洞的地方。
5.1 文件系统权限依然生效
- NFS 共享的是文件系统,所以目录/文件的 rwx 权限和属主依然要遵守。
- 客户端访问 NFS 文件时,实际上用的是客户端用户的 UID 在服务端上访问。
5.2 UID 映射与 root_squash(关键)
NFS 默认启用 root_squash:
- root_squash:把客户端的 root(UID 0)映射成匿名用户(通常是
nobody/nfsnobody,UID 65534)。这样客户端 root 到了服务端没有 root 权限,防止越权——默认且安全。 - no_root_squash:客户端的 root 到了服务端仍是 root。这会让任何能挂载该共享的客户端 root 直接获得服务端 root 权限——非常危险,等于提权漏洞。
默认:客户端 root(0) --> 服务端 nobody(65534) [root_squash,安全]
no_root_squash:客户端 root(0) --> 服务端 root(0) [危险!提权]
5.3 权限排查示例
客户端挂载后出现"没有权限/读不了":
# 在客户端查看文件属主
ls -n /mnt/nfsdata/ # -n 显示数字 UID
# 在服务端查看同一文件属主
ls -n /data/
# 对比两边 UID:如果不一致,就是客户端和服务端的用户 UID 没对齐
id username
关键:客户端用户 UID 与服务端用户 UID 若不一致,就会表现为"同一个用户名却是不同属主/没权限"。解决方法是让服务端和客户端用户的 UID 一致(如在两边都建 UID 相同的同名用户)。
5.4 anonuid / anongid
可以把匿名映射到指定用户,让匿名访问落到某个固定 UID:
# 把匿名用户映射为 UID 1000
/data *(rw,sync,anonuid=1000,anongid=1000)
5.5 安全建议
- 不要用
no_root_squash,除非你完全理解风险(它是公认的提权配置)。 - 尽量只共享给可信网段,不要用
*对全网开放。 - 只在必要目录共享,最小化暴露。
- 若需更高安全,可用 NFSv4 + Kerberos(
sec=krb5p,加密+认证),但配置较复杂。 - 客户端与服务器用户的 UID 尽量保持一致,避免权限错乱。
- 结合权限模块:共享目录的属主/组/权限(
chown/chmod)要按需求设置,配合 root_squash 形成完整权限体系。
参考:Red Hat - Securing the NFS service、HackTricks - NFS no_root_squash 提权
六、常见问题排查清单
- 客户端 mount 卡住/超时 → 服务端 nfs-server 和 rpcbind 是否在运行;防火墙是否放行(
firewall-cmd --list-services)。 mount: connection timed out→ 多为防火墙没放行 2049/111;或服务端没导出。access denied by server→/etc/exports里没允许该客户端,或选项不对;用exportfs -r重读。- 客户端 root 读不了/写不了 → root_squash 把 root 映射成 nobody,检查文件权限(见第五章)。
- 属主显示为 nobody → 客户端 UID 与服务端不匹配;统一 UID 或用 anonuid 映射。
- 开机没自动挂载 → 检查
/etc/fstab是否写了_netdev;mount -a测试。 device is busy卸载不了 →lsof 挂载点/fuser -km 挂载点找到占用进程。- NFSv3 连不上 → 高位随机端口被挡;改用 NFSv4(只放 2049)。
七、总结与练习
7.1 核心速查
| 需求 | 命令 |
|---|---|
| 安装(服务端) | sudo dnf install -y nfs-utils |
| 启动服务 | sudo systemctl enable --now nfs-server |
| 编辑共享 | vim /etc/exports |
| 生效 | sudo exportfs -r(或 -ra) |
| 查看导出 | sudo exportfs -v |
| 客户端挂载 | sudo mount -t nfs4 服务端:/共享 /挂载点 |
| 查看共享 | showmount -e 服务端IP |
| 防火墙放行 | sudo firewall-cmd --permanent --add-service=nfs --add-service=rpc-bind; sudo firewall-cmd --reload |
| 开机自动挂载 | 写 /etc/fstab(加 _netdev) |
7.2 动手练习建议
# 准备两台虚拟机:服务端 192.168.1.10,客户端 192.168.1.20
# 服务端:建共享目录并导出
sudo mkdir -p /data
echo "hello nfs" | sudo tee /data/test.txt
echo "/data 192.168.1.0/24(rw,sync)" | sudo tee -a /etc/exports
sudo exportfs -r
sudo firewall-cmd --permanent --add-service=nfs --add-service=rpc-bind
sudo firewall-cmd --reload
# 客户端:安装并挂载
sudo dnf install -y nfs-utils
sudo mkdir -p /mnt/nfsdata
sudo mount -t nfs4 192.168.1.10:/data /mnt/nfsdata
cat /mnt/nfsdata/test.txt # 应看到 hello nfs
# 测试 root_squash:在客户端用 root 写文件,看服务端属主
# 再配置开机自动挂载(fstab 加 _netdev)
提示:练习在虚拟机进行。NFS 权限问题多,请仔细体会 root_squash 和 UID 映射这两个概念。
参考资料
- Red Hat - Exporting NFS shares:https://docs.redhat.com/zh-cn/documentation/red_hat_enterprise_linux/8/html/configuring_and_managing_file_systems/exporting-nfs-shares
- Red Hat - Securing the NFS service:https://docs.redhat.com/zh-cn/documentation/red_hat_enterprise_linux/10/html/securing_networks/securing-the-nfs-service
- Rocky Linux - NFS server:https://docs.rockylinux.org/guides/file_sharing/nfsserver/
- man 手册:
man 5 exports、man 5 nfs、man 8 exportfs、man 5 fstab - HackTricks - NFS no_root_squash 提权:https://hacktricks.wiki/en/linux-hardening/interesting-files-permissions/nfs-no_root_squash-misconfiguration-pe.html
- 菜鸟教程 - Linux 教程:https://www.runoob.com/linux/linux-tutorial.html
