NFS
出自维基百科
- 网络文件系统 (NFS) 是一种分布式文件系统协议,最初由 Sun Microsystems 于 1984 年开发,允许客户端计算机上的用户通过网络访问文件,方式类似于访问本地存储。
NFS FAQ 列出了经过良好测试的文件系统,并详细说明了关于 FAT32 的限制。
- 默认情况下,NFS 未加密。配置 #TLS 加密,或配置 Kerberos (
sec=krb5p
以提供基于 Kerberos 的加密),或者在处理敏感数据时,通过加密的 VPN (例如 WireGuard) 隧道传输 NFS。 - 与 Samba 不同,NFS 默认情况下没有任何用户身份验证,客户端访问受到其 IP 地址/主机名的限制。如果需要更强的身份验证,可以使用 Kerberos。
- NFS 期望客户端和服务器上的 用户 和/或 用户组 ID 相同 (除非使用 Kerberos)。使用 NFSv4 idmapping 或通过在
/etc/exports
中一起使用anonuid
/anongid
和all_squash
手动覆盖 UID/GID。 - NFS 不支持 POSIX ACL。NFS 服务器仍将强制执行 ACL,但客户端将无法查看或修改它们。
安装
强烈建议使用时间同步守护程序,以保持客户端/服务器时钟同步。如果所有节点上的时钟不准确,NFS 可能会引入不必要的延迟。
服务器配置
全局配置选项在 /etc/nfs.conf
中设置。简单配置的用户应该不需要编辑此文件。
NFS 服务器需要共享目录列表,以导出的形式 (详见 exports(5)),必须在 /etc/exports
或 /etc/exports.d/*.exports
中定义。默认情况下,目录以其路径原样导出;例如
/etc/exports
/data/music 192.168.1.0/24(rw)
以上配置将使 /data/music
目录可以作为 MyServer:/data/music
为 NFSv3 和 NFSv4 挂载。
自定义导出根目录
共享可以相对于所谓的 NFS 根目录。一个好的安全实践是在离散目录树中定义 NFS 根目录,这将使用户仅限于该挂载点。绑定挂载用于将共享挂载点链接到 文件系统 上其他位置的实际目录。在过去,NFS 根目录对于 NFSv4 是强制性的;现在是可选的 (从内核 2.6.33 和 nfs-utils 1.2.2 开始,它们实现了虚拟根目录)。
考虑以下示例,其中:
- NFS 根目录是
/srv/nfs
。 - 导出是通过绑定挂载到实际目标
/mnt/music
的/srv/nfs/music
。
# mkdir -p /srv/nfs/music /mnt/music # mount --bind /mnt/music /srv/nfs/music
要使绑定挂载在重启后保持持久性,请将其添加到 fstab 中
/etc/fstab
/mnt/music /srv/nfs/music none bind 0 0
将要共享的目录添加到 /etc/exports
中,并将它们限制为允许挂载它们的客户端机器的 CIDR 或主机名范围,例如:
/etc/exports
/srv/nfs 192.168.1.0/24(rw,fsid=root) /srv/nfs/music 192.168.1.0/24(rw,sync) /srv/nfs/home 192.168.1.0/24(rw,sync) /srv/nfs/public 192.168.1.0/24(ro,all_squash,insecure) desktop(rw,sync,all_squash,anonuid=99,anongid=99) # map to user/group - in this case nobody
当使用 NFSv4 时,选项 fsid=root
或 fsid=0
表示 “根” 导出;如果存在这样的导出,则所有其他目录必须在其下方。/etc/nfs.conf
文件中的 rootdir
选项对此没有影响。当没有 fsid=0
导出时,默认行为与 NFSv3 中的行为相同。
在上面的示例中,由于 /srv/nfs
被指定为根目录,因此导出 /srv/nfs/music
现在可以通过 NFSv4 作为 MyServer:/music
挂载 – 请注意,根前缀被省略了。
- 对于 NFSv3 (NFSv4 不需要),
crossmnt
选项使客户端可以访问标记为crossmnt
的文件系统上挂载的所有文件系统,并且客户端不需要单独挂载每个子导出。请注意,如果子导出与不同的地址范围共享,则这可能不是理想的。 - 除了
crossmnt
之外,还可以在子导出上使用nohide
选项,以便在客户端挂载根导出时可以自动挂载它们。与crossmnt
不同,nohide
仍然遵守子导出的地址范围。请注意,该选项也是 NFSv3 特有的;NFSv4 始终表现得好像启用了 nohide。 insecure
选项允许客户端从 1023 以上的端口连接。(据推测,只有 root 用户可以使用低编号端口,因此默认情况下阻止其他端口会创建一个肤浅的访问障碍。实际上,省略或包含insecure
选项都不会对安全性提供任何有意义的改进或损害。)- 使用星号 (
*
) 允许从任何接口访问。
应该注意的是,在服务器运行时修改 /etc/exports
将需要重新导出才能使更改生效
# exportfs -arv
要更详细地查看当前加载的导出状态,请使用
# exportfs -v
有关所有可用选项的更多信息,请参阅 exports(5)。
fsid=1
选项。启动服务器
协议版本 4 导出的用户可能希望屏蔽至少 rpcbind.service
和 rpcbind.socket
,以防止多余的服务运行。请参阅 FS#76453。此外,还可以考虑屏蔽 nfs-server.service
,它由于某种原因也被拉入。
限制 NFS 到指定接口/IP
默认情况下,启动 nfs-server.service
将侦听所有网络接口上的连接,而与 /etc/exports
无关。可以通过定义要侦听的 IP 和/或主机名来更改此设置。
/etc/nfs.conf
[nfsd] host=192.168.1.123 # Alternatively, use the hostname. # host=myhostname
重启 nfs-server.service
以立即应用更改。
防火墙配置
要通过防火墙启用对 NFSv4 服务器的访问,必须为传入连接打开 TCP 端口 2049
。(NFSv4 使用静态端口号;它不使用任何辅助服务,例如 mountd 或 portmapper。)
要启用对 NFSv3 服务器的访问,您还需要为 portmapper (rpcbind) 打开 TCP/UDP 端口 111
,以及 MOUNT (rpc.mountd) 端口。默认情况下,rpc.mountd 动态选择端口,因此如果您位于防火墙后面,则需要编辑 /etc/nfs.conf
以设置静态端口。使用 rpcinfo -p
检查 NFSv3 服务器上使用的确切端口
$ rpcinfo -p
100003 3 tcp 2049 nfs 100003 4 tcp 2049 nfs 100227 3 tcp 2049 nfs_acl ...
客户端配置
打算将 NFS4 与 Kerberos 一起使用的用户需要启动并启用 nfs-client.target
。
手动挂载
对于 NFSv3,使用此命令显示服务器的导出文件系统
$ showmount -e servername
对于 NFSv4,挂载根 NFS 目录并查找可用的挂载点
# mount servername:/ /mountpoint/on/client
然后挂载时省略服务器的 NFS 导出根目录
# mount -t nfs -o vers=4 servername:/music /mountpoint/on/client
如果挂载失败,请尝试包含服务器的导出根目录 (Debian/RHEL/SLES 需要,某些发行版需要 -t nfs4
而不是 -t nfs
)
# mount -t nfs -o vers=4 servername:/srv/nfs/music /mountpoint/on/client
servername
需要替换为有效的主机名 (不仅仅是 IP 地址)。否则,远程共享的挂载将挂起。使用 /etc/fstab 挂载
对于始终在线的服务器,以及客户端启动时 NFS 共享可用的情况,使用 fstab 非常有用。编辑 /etc/fstab
文件,并添加反映设置的适当行。同样,服务器的 NFS 导出根目录被省略。
/etc/fstab
servername:/music /mountpoint/on/client nfs defaults,timeo=900,retrans=5,_netdev 0 0
一些需要考虑的附加挂载选项
- rsize 和 wsize
rsize
值是从服务器读取时使用的字节数。wsize
值是写入服务器时使用的字节数。默认情况下,如果未指定这些选项,则客户端和服务器会协商它们都可以支持的最大值 (详见 nfs(5))。更改这些值后,建议测试性能 (请参阅 #性能调优)。- soft 或 hard
- 确定 NFS 请求超时后 NFS 客户端的恢复行为。如果未指定任何选项 (或者如果指定了
hard
选项),则会无限期地重试 NFS 请求。如果指定了soft
选项,则 NFS 客户端在发送 retrans 次重传后会使 NFS 请求失败,从而导致 NFS 客户端向调用应用程序返回错误。
soft
超时在某些情况下可能会导致静默数据损坏。因此,仅当客户端响应能力比数据完整性更重要时才使用 soft
选项。通过 TCP 使用 NFS 或增加 retrans
选项的值可能会减轻使用 soft
选项的一些风险。- timeo
timeo
值是以十分之一秒为单位的时间量,在 RPC 超时后,等待重新发送传输之前的时间。通过 TCP 进行 NFS 的默认值为 600 (60 秒)。在第一次超时后,超时值在每次重试时加倍,最大为 60 秒或直到发生主要超时。如果连接到速度较慢的服务器或通过繁忙的网络连接,则可以通过增加此超时值来获得更好的稳定性。- retrans
- NFS 客户端在尝试进一步恢复操作之前重试请求的次数。如果未指定
retrans
选项,则 NFS 客户端会尝试每个请求三次。NFS 客户端在 retrans 次重试后生成 “服务器未响应” 消息,然后尝试进一步恢复 (取决于 hard 挂载选项是否生效)。 - _netdev
_netdev
选项告诉系统在尝试挂载共享之前等待网络启动 - systemd 为 NFS 假定了这一点。
fs_passno
) 设置为非零值可能会导致意外行为,例如,当 systemd automount 等待永远不会发生的检查时发生挂起。使用带有 systemd 的 /etc/fstab 挂载
另一种方法是使用 x-systemd.automount 选项,该选项在访问时挂载文件系统
/etc/fstab
servername:/home /mountpoint/on/client nfs _netdev,noauto,x-systemd.automount,x-systemd.mount-timeout=10,timeo=14,x-systemd.idle-timeout=1min 0 0
为了使 systemd 意识到对 fstab 的更改,重新加载 systemd 并重启 remote-fs.target
[1]。
noauto
挂载选项将不会挂载 NFS 共享,直到它被访问:使用auto
使其立即可用。
如果遇到由于网络未启动/不可用而导致挂载失败的任何问题,请启用NetworkManager-wait-online.service
。它将确保network.target
在激活之前拥有所有可用的链接。users
挂载选项将允许用户挂载,但请注意,它暗示了更多选项,例如noexec
。x-systemd.idle-timeout=1min
选项将在未使用 1 分钟后自动卸载 NFS 共享。适用于可能突然断开网络连接的笔记本电脑。- 如果由于 NFS 导致关机/重启时间过长,请启用
NetworkManager-wait-online.service
以确保在卸载 NFS 卷之前 NetworkManager 不会退出。 - 不要添加
x-systemd.requires=network-online.target
挂载选项,因为这可能会导致 systemd 内的排序循环 [2]。systemd 会自动将network-online.target
依赖项添加到_netdev
挂载的单元。 - 使用
nocto
选项可以提高只读挂载的性能,但仅应在服务器上的数据仅偶尔更改时使用。
作为 systemd 单元
在 /etc/systemd/system
中创建一个新的 .mount
文件,例如 mnt-home.mount
。有关详细信息,请参阅 systemd.mount(5)。
mnt-home.mount
只能在您要将共享挂载在 /mnt/home
下时使用。否则,可能会发生以下错误:systemd[1]: mnt-home.mount: Where= setting does not match unit name. Refusing.
。如果挂载点包含非 ASCII 字符,请使用 systemd-escape)。What=
共享路径
Where=
共享挂载路径
Options=
共享挂载选项
- 网络挂载单元自动获取对
remote-fs-pre.target
、network.target
和network-online.target
的After
依赖项,并获得对remote-fs.target
的Before
依赖项,除非设置了nofail
挂载选项。对于后者,还会添加一个Wants
单元。 - 附加
noauto
到Options
以防止在启动期间自动挂载 (除非它被其他单元拉入)。 - 如果您想使用要共享的服务器的主机名 (而不是 IP 地址),请将
nss-lookup.target
添加到After
。这可以避免启动时出现的挂载错误,这些错误在测试单元时不会出现。
/etc/systemd/system/mnt-home.mount
[Unit] Description=Mount home at boot [Mount] What=172.16.24.192:/home Where=/mnt/home Options=vers=4 Type=nfs TimeoutSec=30 [Install] WantedBy=multi-user.target
要使用 mnt-home.mount
,启动该单元并启用它以在系统启动时运行。
自动挂载
要自动挂载共享,可以使用以下自动挂载单元
/etc/systemd/system/mnt-home.automount
[Unit] Description=Automount home [Automount] Where=/mnt/home [Install] WantedBy=multi-user.target
禁用/停止 mnt-home.mount
单元,并启用/启动 mnt-home.automount
以在访问挂载路径时自动挂载共享。
使用 autofs 挂载
当多台计算机想要通过 NFS 连接时,使用 autofs 非常有用;它们既可以是客户端也可以是服务器。此方法优于早期方法的原因是,如果服务器关闭,客户端不会抛出关于无法找到 NFS 共享的错误。有关详细信息,请参阅 autofs#NFS 网络挂载。
技巧与诀窍
NFSv4 idmapping
- NFSv4 idmapping 并未解决默认
sec=sys
挂载选项的所有问题。请参阅 #静态映射 和 [3] - 需要在客户端和服务器两者上启用 NFSv4 idmapping。
- 另一种选择是确保客户端和服务器上的用户和组 ID (UID 和 GID) 匹配。
- 启用/启动
nfs-idmapd.service
不是客户端运行所必需的,因为它已被新的 ID 映射器取代
# dmesg | grep id_resolver
[ 3238.356001] NFS: Registering the id_resolver key type [ 3238.356009] Key type id_resolver registered
- 不要将
nfsidmap
(仅适用于 nfs 客户端) 与 NFS 服务器使用的并派生进程rpc.idmapd
的nfs-idmapd.service
混淆。 - rpc.idmapd 和 nfsidmap 也共享来自 idmapd.conf(5) 的一些配置。
- 有关详细信息,请参阅 idmapd(8) 和 nfsidmap(8)。
NFSv4 协议在线路上将本地系统的 UID 和 GID 值表示为 user@domain
形式的字符串。从 UID 转换为字符串以及从字符串转换为 UID 的过程称为 ID 映射。
域
- 默认情况下,字符串的域部分是系统的 DNS 域名。如果系统是多宿主的,或者系统的 DNS 域名与系统的 Kerberos realm 的名称不匹配,也可以在 /etc/idmapd.conf 中指定它。
- 当未在 /etc/idmapd.conf 中指定域时,将查询本地 DNS 服务器以获取 _nfsv4idmapdomain 文本记录。如果记录存在,则将使用该记录作为域。当记录不存在时,将使用 DNS 域的域部分。
在 stdout 上显示系统的有效 NFSv4 域名。
# nfsidmap -d
domain.tld
编辑以匹配服务器和/或客户端上的域
/etc/idmapd.conf
[General] Domain = guestdomain.tld
静态映射
- 此映射仅供客户端在本地映射 uid 使用。如果您创建一个由服务器上未知的 uid (例如 1005) 拥有的文件。该文件以 uid 1005 存储在服务器上,但不再以正确的 uid “在线路上传输” 显示。
- 您可以在与服务器交互后 (即列出文件) 查看密钥环中的所有条目
# nfsidmap -l
7 .id_resolver keys found: uid:nobody user:1 uid:bin@domain.tld uid:foo@domain.tld gid:foo@domain.tld uid:remote_user@domain.tld uid:root@domain.tld
- 您可以使用
nfsidmap -c
清除密钥环,但这不是必需的,在默认设置中,10 分钟后条目过期。
只有当服务器和客户端具有不同的用户/组名称时,才需要这些步骤。更改仅在客户端配置文件中完成。
/etc/idmapd.conf
[Translation] # The default is nsswitch and other methods exist. method = static,nsswitch [Static] foo@domain.tld = local_foo remote_user@domain.tld = user
回退映射
仅在客户端配置中。当无法完成映射时要使用的本地用户/组名称
/etc/idmapd.conf
[Mapping] Nobody-User = nobody Nobody-Group = nobody
性能调优
当在具有大量客户端的网络上使用 NFS 时,可以将默认 NFS 线程从 8 增加到 16 甚至更高,具体取决于服务器/网络要求
/etc/nfs.conf
[nfsd] threads=16
可能需要调整 rsize
和 wsize
挂载选项以满足网络配置的要求。
在最新的 Linux 内核 (>2.6.18) 中,NFS 服务器允许的 I/O 操作大小 (默认最大块大小) 因 RAM 大小而异,最大为 1M (1048576 字节),即使 nfs 客户端需要更大的 rsize
和 wsize
,也将使用服务器的最大块大小。请参阅 https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/5/html/5.8_technical_notes/known_issues-kernel 可以通过在启动 nfsd 之前写入 /proc/fs/nfsd/max_block_size
来更改服务器允许的默认最大块大小。例如,以下命令恢复以前的默认 iosize 32k
# echo 32768 > /proc/fs/nfsd/max_block_size
max_block_size
可能会降低现代硬件上的 NFS 性能。要使更改永久生效,请创建一个 systemd-tmpfile
/etc/tmpfiles.d/nfsd-block-size.conf
w /proc/fs/nfsd/max_block_size - - - - 32768
要使用增加的 rsize
和 wsize
挂载选项进行挂载
# mount -t nfs -o rsize=32768,wsize=32768,vers=4 servername:/srv/nfs/music /mountpoint/on/client
此外,尽管违反了 NFS 协议,但设置 async
而不是 sync
或 sync,no_wdelay
可能会潜在地实现显着的性能提升,尤其是在旋转磁盘上。使用此选项配置导出,然后执行 exportfs -arv
以应用。
/etc/exports
/srv/nfs 192.168.1.0/24(rw,async,crossmnt,fsid=0) /srv/nfs/music 192.168.1.0/24(rw,async)
async
会带来可能的数据丢失或损坏的风险。自动挂载处理
此技巧对于 无线 网络和/或可能不可靠的网络上的 NFS 共享非常有用。如果 NFS 主机变得不可访问,则将卸载 NFS 共享,以期在使用 hard
挂载选项时防止系统挂起 [4]。
确保在 fstab 中正确指示了 NFS 挂载点
/etc/fstab
lithium:/mnt/data /mnt/data nfs noauto 0 0 lithium:/var/cache/pacman /var/cache/pacman nfs noauto 0 0
创建 auto_share
脚本,该脚本将由 cron 或 systemd/Timers 使用,以使用 ICMP ping 检查 NFS 主机是否可访问
/usr/local/bin/auto_share
#!/bin/bash function net_umount { umount -l -f $1 &>/dev/null } function net_mount { mountpoint -q $1 || mount $1 } NET_MOUNTS=$(sed -e '/^.*#/d' -e '/^.*:/!d' -e 's/\t/ /g' /etc/fstab | tr -s " ")$'\n'b printf %s "$NET_MOUNTS" | while IFS= read -r line do SERVER=$(echo $line | cut -f1 -d":") MOUNT_POINT=$(echo $line | cut -f2 -d" ") # Check if server already tested if [[ "${server_ok[@]}" =~ "${SERVER}" ]]; then # The server is up, make sure the share are mounted net_mount $MOUNT_POINT elif [[ "${server_notok[@]}" =~ "${SERVER}" ]]; then # The server could not be reached, unmount the share net_umount $MOUNT_POINT else # Check if the server is reachable ping -c 1 "${SERVER}" &>/dev/null if [ $? -ne 0 ]; then server_notok[${#server_notok[@]}]=$SERVER # The server could not be reached, unmount the share net_umount $MOUNT_POINT else server_ok[${#server_ok[@]}]=$SERVER # The server is up, make sure the share are mounted net_mount $MOUNT_POINT fi fi done
# Check if the server is reachable ping -c 1 "${SERVER}" &>/dev/null
为
# Check if the server is reachable timeout 1 bash -c ": < /dev/tcp/${SERVER}/2049"在上面的
auto_share
脚本中。确保脚本是可执行的。
接下来检查配置脚本以每 X 分钟运行一次,在下面的示例中,这是每分钟一次。
Cron
# crontab -e
* * * * * /usr/local/bin/auto_share
systemd/Timers
/etc/systemd/system/auto_share.timer
[Unit] Description=Automount NFS shares every minute [Timer] OnCalendar=*-*-* *:*:00 [Install] WantedBy=timers.target
/etc/systemd/system/auto_share.service
[Unit] Description=Automount NFS shares After=network.target [Service] Type=oneshot ExecStart=/usr/local/bin/auto_share [Install] WantedBy=multi-user.target
使用 NetworkManager 调度器
NetworkManager 也可以配置为在网络状态更改时运行脚本。
在网络状态更改时挂载共享的最简单方法是符号链接 auto_share
脚本
# ln -s /usr/local/bin/auto_share /etc/NetworkManager/dispatcher.d/30-nfs.sh
但是,在那种特殊情况下,卸载只会在网络连接已被禁用后发生,这是不干净的,并可能导致诸如 KDE Plasma 小部件冻结之类的影响。
以下脚本通过监听 down
、pre-down
和 vpn-pre-down
事件,在相关网络连接被禁用之前安全地卸载 NFS 共享,确保脚本是可执行的
/etc/NetworkManager/dispatcher.d/30-nfs.sh
#!/bin/sh # Find the connection UUID with "nmcli con show" in terminal. # All NetworkManager connection types are supported: wireless, VPN, wired... WANTED_CON_UUID="CHANGE-ME-NOW-9c7eff15-010a-4b1c-a786-9b4efa218ba9" if [ "$CONNECTION_UUID" = "$WANTED_CON_UUID" ]; then # Script parameter $1: network interface name, not used # Script parameter $2: dispatched event case "$2" in "up") mount -a -t nfs4,nfs ;; "down"|"pre-down"|"vpn-pre-down") umount -l -a -t nfs4,nfs -f >/dev/null ;; esac fi
noauto
选项的挂载,删除此挂载选项或使用 auto
以允许调度器管理这些挂载。在 /etc/NetworkManager/dispatcher.d/pre-down
中创建一个符号链接以捕获 pre-down
事件
# ln -s /etc/NetworkManager/dispatcher.d/30-nfs.sh /etc/NetworkManager/dispatcher.d/pre-down.d/30-nfs.sh
TLS 加密
从 Linux 6.5 开始,可以使用 TLS 加密 NFS 流量,使用 xprtsec=tls
挂载选项。首先,在客户端和服务器上安装 ktls-utilsAUR 软件包,并按照以下配置步骤分别进行配置。
服务器
创建一个私钥并获取一个包含您的服务器 DNS 名称的证书(详见 传输层安全)。这些文件不需要添加到系统的信任存储中。
编辑 /etc/tlshd.conf
以使用这些文件,使用您自己的 x509.certificate
和 x509.private_key
值
/etc/tlshd.conf
[authenticate.server] x509.certificate= /etc/nfsd-certificate.pem x509.private_key= /etc/nfsd-private-key.pem
客户端
将上一步中生成的服务器 TLS 证书添加到系统的信任存储中(详见 传输层安全 以了解更多详细信息)。
现在您应该能够使用服务器的 DNS 名称挂载服务器
# mount -o xprtsec=tls servername.domain:/ /mountpoint/on/client
检查客户端上的 journalctl 应该显示 TLS 握手成功
$ journalctl -b -u tlshd.service
Sep 28 11:14:46 client tlshd[227]: Built from ktls-utils 0.10 on Sep 26 2023 14:24:03 Sep 28 11:15:37 client tlshd[571]: Handshake with servername.domain (192.168.122.100) was successful
故障排除
有一篇专门的文章 NFS/故障排除。
参见
- 另请参阅 Avahi,一种 Zeroconf 实现,允许自动发现 NFS 共享。
- HOWTO: 无盘网络启动 NFS 根目录
- Microsoft Services for Unix NFS 客户端信息
- NFS on Snow Leopard
- http://chschneider.eu/linux/server/nfs.shtml
- 如何进行 Linux NFS 性能调优和优化
- Linux:调整 NFS 性能
- 配置仅限 NFSv4 的服务器