> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/di-35-zhang-fu-wu-qi/di-35.3-jie-wang-luo-wen-jian-xi-tong-nfs.md).

# 35.3 网络文件系统（NFS）

## NFS 概述

NFS（Network File System，网络文件系统）最初由 Sun Microsystems 于 1984 年研发，是一种分布式文件存储协议，允许远程服务器共享文件目录。

FreeBSD 支持网络文件系统（NFS），包括 NFSv2、NFSv3 和 NFSv4，允许服务器通过网络与客户端共享目录和文件。NFS 通过远程过程调用（Remote Procedure Call，RPC）实现通信，使客户端能够透明地访问远程文件，如同访问本地文件系统一样。

```sh
NFS 服务器
  /home/ykla（共享目录）
     │
     │ RPC 通信
     ▼
NFS 客户端
  /mnt/nfs（本地挂载点）
  ── 透明访问，如同本地文件 ──
```

NFS 有许多实际应用。一些常见的用途包括：

* 需要在多个客户端之间复制的数据，可以集中保存在一个位置，供网络上的所有客户端访问。
* 多个客户端可能需要访问 **/usr/ports/distfiles** 目录。共享该目录可以快速访问源文件，而无需将其下载到每个客户端。
* 在大型网络中，将所有用户的主目录集中存放在一台 NFS 服务器上更为便利。用户可以在网络中的任一客户端登录，并访问自己的主目录。
* NFS 导出的管理更为简便。例如，只需对单个文件系统设置安全策略或备份策略。
* 网络上的其他机器可以共享可移动存储介质。这减少了网络中的设备数量，并提供了集中管理安全性的位置。从集中安装的介质上为多台机器安装软件通常也更为方便。

NFS 由一个服务器和一个或多个客户端组成。客户端远程访问存储在服务器上的数据。

NFS 服务器在 **/etc/exports** 中声明要共享的文件系统。该文件中的每一行指定要导出的文件系统、允许访问的客户端以及访问选项。添加条目时，每个导出的文件系统、其属性和允许的主机必须位于同一行。如果条目中未列出客户端，则网络上任意客户端均可挂载该文件系统。

## 共享目录

首先创建要共享的路径 **/home/ykla**，将需要共享的文件和目录放入其中。

要将本地目录 **/home/ykla** 及其所有子目录共享至远程主机 **192.168.179.1**（可通过 IP 地址或主机名指定），需编辑 **/etc/exports** 文件，添加以下内容：

```ini
/home/ykla -alldirs 192.168.179.1
```

标志 `-alldirs` 允许将子目录作为挂载点。也就是说，它不会自动挂载子目录，而是允许客户端根据需要自行挂载所需的目录。

> **技巧**
>
> 上述示例中的路径 **/home/ykla** 和远程主机地址 **192.168.179.1** 均为占位符，需要替换为实际的值。

配置完成后，远程客户端即可挂载并访问 **/home/ykla** 目录。

对于每个文件系统，同一客户端只能指定一次。

```ini
# 这是错误的格式
/usr/src   192.168.179.1
/usr/ports 192.168.179.1
```

需要在一个条目中指定：

```ini
# 这是正确的格式
/usr/src /usr/ports  192.168.179.1
```

## 共享 ZFS 数据集

以下示例将 **zroot/home/ykla** 数据集导出，允许远程主机 **192.168.179.1** 以读写方式挂载：

```sh
# zfs set sharenfs="-maproot=root -rw 192.168.179.1" zroot/home/ykla
```

说明：

* 导出的文件系统默认为读写（选项 `-rw`），客户端可以对导出的文件系统进行读写操作。若需设为只读，可使用 `-ro` 标志。
* 选项 `-maproot=root` 允许远程系统上的 root 用户以 root 身份写入导出的文件系统。如未指定 `-maproot=root`，客户端的 root 用户将被映射为服务器上的凭证 `-2:-2`（通常对应 nobody 账户），并将受到相应的访问限制。

> **思考题**
>
> 分析为什么 `-2:-2` 通常对应 nobody 账户（**/etc/master.passwd** 中定义 `nobody:*:65534:65534::0:0:Unprivileged user:/nonexistent:/usr/sbin/nologin`）。

> **警告**
>
> 请务必谨慎！`-maproot=root` 操作存在安全风险，建议仅在受信网络中共享。

验证状态：

```sh
# zfs get sharenfs zroot/home/ykla
NAME             PROPERTY  VALUE                          SOURCE
zroot/home/ykla  sharenfs  rw=192.168.179.1,maproot=root  local
```

查看本机导出的路径：

```sh
# showmount -e
Exports list on localhost:
/home/ykla                         rw 192.168.179.1
```

## 服务启动配置

完成共享目录的配置后，还需要启动以下守护进程才能使 NFS 正常工作：

| 守护进程    | 说明                           |
| ------- | ---------------------------- |
| nfsd    | NFS 守护进程，处理来自 NFS 客户端的请求     |
| mountd  | NFS 挂载守护进程，处理来自 NFS 客户端的挂载请求 |
| rpcbind | 允许 NFS 客户端发现 NFS 服务器使用的端口    |

将以下服务设置为开机自启：

```ini
# service rpcbind enable # 启用 RPC 服务以支持 NFS
# service nfsd enable # 启用 NFS 服务
# service mountd enable # 启用 NFS 挂载守护进程
```

* 启动 RPC 服务：

```sh
# service rpcbind start
```

* 启动 NFS 挂载守护进程：

```sh
# service mountd start
```

* 启动 NFS 服务：

```sh
# service nfsd start
```

* 每当启动 NFS 服务器时，mountd 会自动启动。但 mountd 仅在引导时读取 **/etc/exports**。要使后续对 **/etc/exports** 的编辑立即生效，可以让 mountd 重新加载配置：

```sh
# service mountd reload
```

查看本机共享文件：

```sh
# showmount -e
Exports list on localhost:
/home/ykla/                        192.168.179.1
```

## Windows 客户端挂载

要在 Windows（IP 地址 **192.168.179.1**）中启用 NFS 客户端服务，使用管理员权限打开 PowerShell，键入以下命令并按 **回车键**：

```powershell
PS C:\WINDOWS\system32>dism /online /enable-feature /featurename:ClientForNFS-Infrastructure /all /norestart

Deployment Image Servicing and Management tool
Version: 10.0.26100.5074

Image Version: 10.0.26200.8246

启用一个或多个功能
[==========================100.0%==========================]
The operation completed successfully.
```

命令执行成功后，重启计算机使变更生效。

打开 PowerShell 键入以下命令，其中 **192.168.179.128** 是 NFS 服务器地址：

```powershell
PS C:\Users\ykla> showmount -e 192.168.179.128
Exports list on 192.168.179.128:
/home/ykla/                        192.168.179.1
```

检查网络端口：

```powershell
PS C:\Users\ykla> Test-NetConnection 192.168.179.128 -Port 2049


ComputerName     : 192.168.179.128
RemoteAddress    : 192.168.179.128
RemotePort       : 2049
InterfaceAlias   : VMware Network Adapter VMnet8
SourceAddress    : 192.168.179.1
TcpTestSucceeded : True
```

打开 PowerShell（**非管理员模式**），键入以下命令，使用 `mount` 命令将共享路径映射为一个驱动器号（例如 `Z:`）。

```powershell
PS C:\Users\ykla> mount.exe 192.168.179.128:/home/ykla Z:
Z: is now successfully connected to 192.168.179.128:/home/ykla

The command completed successfully.
```

> **警告**
>
> 如果以管理员模式运行 PowerShell 命令，则资源管理器不会加载对应盘符（`Z`）。

查看挂载情况：

```powershell
New connections will be remembered.


Status       Local     Remote                    Network

-------------------------------------------------------------------------------
             Z:        \\192.168.179.128\home\ykla
                                                NFS Network
The command completed successfully.
```

打开资源管理器可以看到网络位置 `ykla (\\192.168.179.128\home)`，即 Z 盘：

![NFS Z 盘](/files/qTonSsPNgwjHzehuLmyo)

浏览文件：

![NFS Z 盘](/files/LnvIAPgYHPo6qcIIqT0s)

## FreeBSD 客户端挂载

在 FreeBSD 客户端（IP 地址 **192.168.179.133**）中启用 NFS 客户端服务：

```sh
# service nfsclient enable
```

然后，在 NFS 客户端上运行以下命令：

```sh
# service nfsclient start
```

挂载前可用 `showmount -e` 命令查看服务器已导出的 NFS 共享列表。将远程服务器 **192.168.179.128** 的 **/home/ykla** 目录挂载到本地挂载点 **/mnt**：

```sh
# showmount -e 192.168.179.128
Exports list on 192.168.179.128:
/home/ykla                         rw 192.168.179.133
# mount 192.168.179.128:/home/ykla /mnt
```

> **技巧**
>
> 请将 **192.168.179.128** 替换为实际的值，可以是 NFS 服务器的 IP 地址或者主机名。

现在，可在客户端的 **/mnt** 目录中访问服务器上 **/home/ykla** 下的文件与目录。

要在每次启动客户端时自动挂载远程文件系统，请将其添加到 **/etc/fstab** 文件中：

```sh
192.168.179.128:/home/ykla    /mnt    nfs    rw    0    0
```

## 使用 autofs 自动挂载

autofs 是一组组件的统称，能够在访问文件系统中的文件或目录时自动挂载远程和本地文件系统。它包括内核组件 autofs 和几个用户空间应用程序：automount(8)、automountd(8)、autounmountd(8)。

autofs 使用的映射格式与其他 SVR4 自动挂载器相同，如 Solaris、macOS 和 Linux 中的自动挂载器。

autofs 虚拟文件系统由 automount(8) 挂载在指定的挂载点，通常在引导时调用。每当进程尝试访问 autofs 挂载点中的文件时，内核将通知守护进程 automountd(8)，并暂停触发的进程。守护进程 automountd(8) 将处理内核请求，通过查找合适的映射并挂载相应的文件系统，随后通知内核释放被阻塞的进程。除非这些文件系统仍在使用，守护进程 autounmountd(8) 将在一定时间后自动卸载自动挂载的文件系统。

autofs 主要配置文件是 **/etc/auto\_master**。它将单独的映射分配给顶级挂载点。

有一个特殊的自动挂载映射挂载在 **/net** 目录下。当访问该目录中的文件时，autofs 会查找相应的远程挂载并自动挂载它。例如，尝试访问 **/net/192.168.179.128/usr** 中的文件将会通知 automountd(8) 挂载来自 **192.168.179.128** 主机的 **/usr** 导出文件系统。

**示例**：使用 autofs 挂载导出的文件系统

可以通过运行以下命令在启动时启用 autofs：

```sh
# service automount enable
```

然后，可以通过运行以下命令启动 autofs：

```sh
# service automount start
# service automountd start
# service autounmountd start
```

在这个示例中，`showmount -e` 命令显示了可以从 NFS 服务器 **192.168.179.128** 挂载的文件系统：

```sh
$ showmount -e 192.168.179.128
Exports list on 192.168.179.128:
/home/ykla                         rw 192.168.179.133
```

`showmount` 输出显示 **/net/192.168.179.128/home/ykla** 是一个导出文件系统。当切换到 **/net/192.168.179.128/** 目录时，automountd(8) 拦截请求并尝试解析主机名 **192.168.179.128**。

```sh
$ cd /net/192.168.179.128/home/ykla
```

查看文件：

```sh
ykla@ykla:/net/192.168.179.128/home/ykla $ ls
1.db	1.txt	2.db	ee.core	test
```

如果成功，automountd(8) 会自动挂载源导出文件系统。

```sh
# mount

……省略其他无关输出内容……

map -hosts on /net (autofs)
192.168.179.128:/home/ykla on /net/192.168.179.128/home/ykla (nfs, nosuid, automounted)
```

## 故障排除与未竟事宜

### 如何关闭 ZFS NFS 共享

如果要关闭对数据集 **zroot/home/ykla** 的共享，可以使用以下命令：

```sh
# zfs set sharenfs=off zroot/home/ykla
```

### NFSv4 演示

Windows 11 Pro 内置的 NFS 客户端仅支持 NFSv2 和 NFSv3，不支持 NFSv4。使用 NFSv4 需借助第三方驱动（如 ms-nfs41-client）。有待在 Windows Server 下测试其原生支持情况。

### Windows 写挂载

Windows 11 Pro 的 NFS 客户端默认以只读方式挂载，需通过注册表配置 AnonymousUID/AnonymousGID 才能写入。有待在 Windows Server 下测试。已在 FreeBSD NFS 客户端上验证读写功能正常。

### showmount 命令无响应

在系统日志 **/var/log/messages** 中查询到如下记录：

```sh
Jun 10 16:38:24 ykla mountd[6415]: bad exports list line '/home/logs/ykla/test': /home/logs: lstat() failed: No such file or directory.
Jun 10 16:38:29 ykla mountd[6416]: bad exports list line '/home/logs/ykla/test': /home/logs: lstat() failed: No such file or directory.
```

说明共享文件配置错误，因为路径 **/home/logs/ykla/test** 不存在。

### 共享目录因使用符号链接导致错误

```sh
mount.nfs: access denied by server while mounting
```

此处的 `access denied` 并非用户权限问题，而是 NFS 服务端拒绝了挂载请求，原因在于 **/etc/exports** 中的导出路径不能包含符号链接。

在系统日志 **/var/log/messages** 中查询到如下记录：

```sh
bad exports list line '/abc/logs': symbolic link in export path or statfs failed
```

该记录表明 **/abc/logs** 路径中存在符号链接，因此无法共享。编辑 **/etc/exports** 文件，将 **/abc/logs** 路径改为符号链接的对象 **/真实路径**。

重新加载 NFS 挂载守护进程的配置：

```sh
# service mountd reload
```

在客户端上执行以下命令，先用 `showmount -e server` 确认服务端已导出共享，再将远程服务器 `server` 的 **/真实路径** 目录挂载到本地挂载点 **/mnt**：

```sh
# showmount -e server
# mount server:/真实路径 /mnt
```

此时远程目录已成功挂载到本地挂载点 **/mnt**。

## 参考文献

* FreeBSD Project. mount\_nfs -- mount NFS file systems\[EB/OL]. \[2026-03-25]. <https://man.freebsd.org/cgi/man.cgi?query=mount_nfs&sektion=8>. 该手册页提供了 mount\_nfs 命令的完整参数说明。
* 李守中. 李守中的技术笔记\[EB/OL]. \[2026-03-25]. <https://note.lishouzhong.com>. 该站点包含大量 Unix/Linux 技术文档的中文翻译。
* chhquan. freebsd nfs 挂载遇到的问题\[EB/OL]. \[2026-03-25]. <https://blog.51cto.com/chhquan/1708250>. 该文章分析了 FreeBSD NFS 挂载常见问题及解决方案。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/di-35-zhang-fu-wu-qi/di-35.3-jie-wang-luo-wen-jian-xi-tong-nfs.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
