NFS服务器

Administrator 0

NFS 服务器


目录

  1. 软件包安装
  2. 认识 NFS:是什么与版本差异
  3. NFS 服务端配置:/etc/exports 与 exportfs
  4. NFS 客户端挂载:mount 与开机自动挂载
  5. NFS 端口与防火墙放行
  6. NFS 权限与安全问题
  7. 常见问题排查清单
  8. 总结与练习
  9. 参考资料

软件包安装

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 默认使用 NFSv4mount -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/nfsdatafuser -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 nfsman 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 自带的服务放行最省事(nfsrpc-bindmountd 三个服务):

# 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 + Kerberossec=krb5p,加密+认证),但配置较复杂。
  • 客户端与服务器用户的 UID 尽量保持一致,避免权限错乱。
  • 结合权限模块:共享目录的属主/组/权限(chown/chmod)要按需求设置,配合 root_squash 形成完整权限体系。

参考:Red Hat - Securing the NFS service、HackTricks - NFS no_root_squash 提权


六、常见问题排查清单

  1. 客户端 mount 卡住/超时 → 服务端 nfs-server 和 rpcbind 是否在运行;防火墙是否放行(firewall-cmd --list-services)。
  2. mount: connection timed out → 多为防火墙没放行 2049/111;或服务端没导出。
  3. access denied by server/etc/exports 里没允许该客户端,或选项不对;用 exportfs -r 重读。
  4. 客户端 root 读不了/写不了 → root_squash 把 root 映射成 nobody,检查文件权限(见第五章)。
  5. 属主显示为 nobody → 客户端 UID 与服务端不匹配;统一 UID 或用 anonuid 映射。
  6. 开机没自动挂载 → 检查 /etc/fstab 是否写了 _netdevmount -a 测试。
  7. device is busy 卸载不了lsof 挂载点 / fuser -km 挂载点 找到占用进程。
  8. 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 映射这两个概念。


参考资料