# 基于 Samba 的时间机器备份

* 原文链接：[Samba-based Time Machine Backups](https://freebsdfoundation.org/our-work/journal/browser-based-edition/storage-and-filesystems/samba-based-time-machine-backups/)
* 作者：Benedict Reuschling

“我真希望我能把带宽节省下来做备份之类的有用事情，因为我永远不会需要它们”——从未有人这么说过。在发生灾难时——而灾难总是不期而至——备份是 IT 弹性的重要组成部分。硬盘故障、笔记本电脑被盗、固件驱动程序损坏导致数据不可读等等，都是备份所要应对的情况。定期备份并确保其可用性对于持续的业务运营至关重要，而测试备份的可恢复性同样重要。但如果备份解决方案不再受支持，并且无法在较新的系统上工作该怎么办？新的系统如何备份，又如何与现有的解决方案集成？

我在《FreeBSD 期刊》2022 年 3/4 月号中写了一篇关于如何设置 FreeBSD 苹果时间机器的文章。这个设置我已经运行了很久，没有遇到问题——无论是在备份方面，还是在我需要恢复数据时。随着时间的推移，苹果改变了底层的 Apple 文件协议（AFP）。在更新的 macOS 版本中（我一直定期升级以获得安全和功能增强），该协议经历了一些变化，使得我原来的设置不再适用了。如上所述，当前的设置仍然有效，但对于新的时间机器系统，我再也无法使用它了。从 macOS 10.9（Mavericks）开始，Apple 将 SMB（Samba 更广为人知）集成到协议中。此次迁移在 macOS 11（Big Sur）完成，该版本移除了 AFP 服务器部分，改为将 SMB 作为新的标准，时间机器也开始内部使用 SMB。

当我设置新的时间机器备份系统时，我发现了这一点。许多年前，我将我在 2022 年的文章中的设置写成了一个 Ansible playbook 以便更轻松地部署。这个 playbook 仍然有效，但它导致新版本的 macOS 无法将导出的驱动器挂载为时间机器的存储位置。幸运的是，我发现其他人碰到了同样的问题，并且已经找到了相应的解决方案。哪怕这些说明并不像我希望的那样简洁，但它们已经解决了问题。以下的设置结合了不同的来源——Reddit、个人博客、FreeBSD 论坛以及 Samba 文档。我已经在两台不同的机器上进行了测试，补充了一些说明，并添加了缺失的命令以确保它按预期工作。我保留了早期的“基于 ZFS”，因为那是我用来存储重要数据的系统。你可以选择不使用 ZFS，去用别的文件系统，但如果没成功，也别怪我！

## 系统要求

为了设置此备份系统，你需要一台机器（在我的例子中是 FreeBSD）来存储备份。它应该有良好的网络连接和快速的存储。存储还需要以某种方式实现冗余，比如 RAID1 及更高等级的 RAID。存储容量取决于两个因素：备份数据的人数和他们的数据量。时间机器配置对话框允许你设置磁盘配额和加密，这两者都是不错的选择。ZFS 支持配额和保留空间，因此我在文件系统层面上设置了相同的值。时间机器会自动删除较旧的备份，当可用存储空间不足以容纳新的备份数据时。存储越多，你可以恢复的备份历史也就越长。

加密功能也很有用，特别是当我们将数据通过可能未加密或者经 VPN 网络传输时。在接收系统上，可以为静态数据添加加密的 ZFS 数据集。但是，值得注意的是，当备份目标需要重新启动时，除非有人输入用于挂载数据集的密码，否则加密的数据集将不会被挂载。你可以配置 ZFS 从某个文件获取密码，但我将其作为一个安全访问的练习，来保障存储密码的文件不被泄露。

在发送端，所有 macOS 系统都能够挂载、配置该驱动器，并通过个别用户凭证进行保护。这能让多人向同一时间机器备份。考虑到可能同时进行多个备份，因此有足够带宽的服务器变得尤为重要。当在 Mac 上配置多个时间机器备份位置时，系统会智能地避免同时备份到两个位置，从而防止系统 I/O 被长时间的备份任务所阻塞。

## 配置备份服务器

首先安装你选择的 FreeBSD 版本（理想情况下仍在支持范围内），并确保安装了最新的安全补丁。我们在这里不选择使用 jail，但我们用 jail 也没问题。首先安装 Samba 包：

```sh
# pkg install samba419
```

接下来，我们为 ZFS 配置备份存储。在我的例子中，我有一个专门的池，命名为 `backup`，并挂载在目录 `/backup`。我为时间机器创建了一个单独的数据集，并设置了配额和保留空间，因为我还在其中存储其他数据，并且希望为这些文件保留一定的空间。

```sh
# zfs create -o quota=1.5T -o reservation=1.5T backup/timemachine
```

我知道会有两个用户（Tammy 和 Tim；Alice 和 Bob 在度假）将他们的 Mac 备份到该位置。我平等地对待他们，因此我为两者设置了相同的空间保留和配额。请记住，数据集上的配额和保留空间也会应用于其下的所有数据集。1.5 TB 也将应用于他们的数据集，已对其进行了限制。但每人 500GB 是足够的，因此我为每个数据集分别设置了 `refquota` 和 `refreservation`。

```sh
# zfs create -o refquota=500g -o refreservation=500g backup/timemachine/tammy
# zfs create -o refquota=500g -o refreservation=500g backup/timemachine/tim
```

他们两人都永远无法登录到我的备份服务器（他们也不在乎），但他们仍然需要在系统上拥有一个用户来挂载时间机器的存储。我为他们两人都运行了 `adduser`，不给他们家目录（`/var/empty`），也不给他们 shell 访问权限（`/usr/sbin/nologin`）。

运行命令 `chmod` 和 `chown` 来保护他们的数据集挂载点，防止外部窥探。

```sh
chmod -R 0700 /backup/timemachine/tammy
chmod -R 0700 /backup/timemachine/tim
chown -R tim /backup/timemachine/tim
chown -R tammy /backup/timemachine/tammy
```

最后，设置 Samba 端的密码，供这两个用户使用。这就是在 macOS 中挂载时间机器备份时的密码提示。

```sh
# smbpasswd -a tim
# smbpasswd -a tammy
```

### Avahi 配置

到此为止，所需的软件已经安装完毕——简单易行。接下来，我们需要创建两个配置文件，一个是时间机器服务的配置，另一个是 Samba 配置。时间机器服务通过 Avahi 运行——不是来自《马达加斯加》的狐猴，而是这个软件。Avahi 是一款 Zeroconf 网络实现，允许程序在本地网络中发布和发现服务（比如我们的时间机器）。配置文件是基于 XML 格式的，位于 `/usr/local/etc/avahi/services/timemachine.service`（如果该文件不存在，需要创建），文件内容如下：

```xml
<?xml version=”1.0” standalone='no'?>
<!DOCTYPE service-group SYSTEM “avahi-service.dtd”>
<service-group>
<name replace-wildcards=”yes”>%h</name>
<service>
<type>_smb._tcp</type>
<port>445</port>
</service>
<service>
<type>_device-info._tcp</type>
<port>0</port>
<txt-record>model=RackMac</txt-record>
</service>
<service>
<type>_adisk._tcp</type>
<txt-record>sys=waMa=0,adVF=0x100</txt-record>
<txt-record>dk0=adVN=FreeBSD TimeMachine,adVF=0x82</txt-record>
</service>
</service-group>
```

该文件定义了监听 Samba 服务端口（445），挂载驱动器的图标样式（`RackMac`）和显示名称（`FreeBSD TimeMachine`）。你可以更改显示名称，以便为其指定一个更具陈述性的名称。我未更改文件中的其他部分。

### Samba 配置

Samba 是 SMB 协议的开源实现，已经有 32 年历史。最初，它的主要目的是实现 Unix 系统与 Windows 之间的兼容性。随着 Windows 添加了更多附加功能，Samba 也加入了 Active Directory（AD，活动目录）集成、域控制器等功能。由于此设置中不涉及任何 Windows 系统（你能听到松了一口气的声音），我们在这里使用 Samba 的文件共享功能来代替 AFP。

Samba 的配置文件位于 `/usr/local/etc/smb4.conf`，内容如下：

```ini
[global]
workgroup = WORKGROUP
security = user
passdb backend = tdbsam
fruit:aapl = yes
fruit:model = MacSamba
fruit:advertise_fullsync = true
fruit:metadata = stream
fruit:veto_appledouble = no
fruit:nfs_aces = no
fruit:wipe_intentionally_left_blank_rfork = yes
fruit:delete_empty_adfiles = yes

[TimeMachine]
path = /backup/timemachine/%U
valid users = %U
browseable = yes
writeable = yes
vfs objects = catia fruit streams_xattr zfsacl
fruit:time machine = yes
create mask = 0600
directory mask = 0700
```

两个部分（`global` 和 `TimeMachine`）定义了备份目标所需的参数。以 `fruit:` 为前缀的行用于与 macOS 的兼容性。有关这些行的详细文档，请参见 Samba 文档（见文章末尾的参考文献）。在 `[TimeMachine]` 部分中，将路径行更改为之前在 FreeBSD 上创建的路径。`%U` 部分是一个占位符，表示个别用户名（在我们的例子中是 tammy 和 tim）进行文件备份。这样，当以后添加另一个用户时，我们就不需要更改此行了。`create mask` 和 `directory mask` 确保正确的权限，避免文件被混合，且用户无法看到和更改其他用户的备份。

## 启动

剩下的步骤就是启用并启动 dbus（avahi）和 samba 服务。

```sh
# service dbus enable
# service dbus start
# service samba_server enable
# service samba_server start
```

在 macOS 端（备份客户端），打开 Finder 并按下 CMD-K（“连接到服务器”的快捷键）。输入 `smb://server.ip.or.dns`。若一切顺利，输入用户名和密码。这就是我们之前在 `smbpasswd` 对话框中为 tim 和 tammy 设置的密码。如果成功，共享目录将挂载到系统中。接下来，进入时间机器配置对话框，再添加新的 Time Machine 卷。记得点击其中的选项按钮，再勾选加密备份框。此设置只能在初次备份之前设置，之后无法更改。你还可以限制备份占用的磁盘空间，但这不是强制的，因为我们已经在 ZFS 层面上设置了。然后，首次备份将开始进行。当完成后，时间机器将自动挂载和卸载该共享，进行定期的备份。

## 总结

就这样，Samba 配置相当简单，用户应该能够根据自己的需求进行调整。我发现这个新解决方案和旧的解决方案一样可靠。我已经调整了我的 Ansible playbook，以便使用新的基于 Samba 的设置。我依然喜欢那种“一键备份”的方式，知道在需要时，我能恢复单个文件和整个系统，恢复的文件都是我最近使用的最新文件。

## 参考文献和来源

* [Samba 文档](https://www.samba.org/samba/docs/current/man-html/vfs_fruit.8.html)
* [Reddit 帖子](https://www.reddit.com/r/homelab/comments/83vkaz/howto_make_time_machine_backups_on_a_samba/)
* [FreeBSD 论坛帖子](https://forums.freebsd.org/threads/samba-functions-but-unable-to-use-it-as-a-macos-time-machine-destination.79896/#post-655905)
* [Dan Langille 的博客](https://dan.langille.org/2023/09/28/creating-a-time-capsule-instance-using-samba-freebsd-and-zfs/)

***

**BENEDICT REUSCHLING** 是 FreeBSD 项目的文档提交者，也是文档工程团队的成员。过去，他曾两次担任 FreeBSD 核心团队成员。他在德国达姆施塔特应用技术大学管理一个大数据集群，并为本科生开设了“开发者的 Unix”课程。Benedict 也是每周 [bsdnow.tv](https://bsdnow.tv/) 播客的主持人之一。


---

# Agent Instructions: 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:

```
GET https://freebsd-journal-cn.bsdcn.org/20240708-cun-chu-yu-wen-jian-xi-tong/samba.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
