I recently upgraded Debian on my home server by means of reinstallation. Before this I had Netatalk set up to serve a directory over AFP to be used as the Time Machine backup target for the girlfriend's MacBook. In the beginning Time Machine only supported AFP for remote backups but since quite a few years now it can also use the SMB protocol version 3.

I figured that by now the relevant parts to support that server side ought to have been implemented in Samba, trickled down the distribution chain and with some luck ended up packaged in the latest Debian. That turned out to be correct and what follows is a summary of my configuration and findings during researching the correct settings.

Base configuration

You can find any number of online guides on how to set up a decent base configuration of Samba. The stock smb.conf shipped with Debian is pretty cluttered but contains mostly reasonable default values. These are the deviations from it that I made, in the [global] section:

interfaces = 127.0.0.0/8 br0
bind interfaces only = yes

I have multiple network interfaces for virtualization purposes and only want Samba shares on one of them (br0). The man page for smb.conf(5) tells you that the loopback address must be listed in interfaces:

If bind interfaces only is set and the network address 127.0.0.1 is not added to the interfaces parameter list smbpasswd(8) may not work as expected due to the reasons covered below.

Microsoft has discouraged the use of the original SMB protocol for approximately 100 years now. I don't plan to use any devices that do not support SMB 3.0 so let's set that as the minimum version required:

server min protocol = SMB3_00

I then removed all the default shares (home directories and printers) and added a few of my own. For each share I set a comment, path and read only. I'm not sure whether the comment is necessary. The rest of the parameters should be fine at their default values. I have given up trying to get guest access to work and now have user accounts everywhere instead.

User accounts

Simply run smbpasswd -a <username> for each user. The username should already exist as a Unix user account (create it with useradd otherwise). This allows the use of Unix filesystem permissions also for SMB shares to make things simple.

Additional configuration requirements

We are not done yet. For Time Machine to accept an SMB share as a valid target a few Apple specific protocol extensions need to be enabled. These are needed to support alternate data streams (e.g. Apple resource forks) and are implemented in the Samba VFS module fruit. I recommend that you read through the entirety of the man page vfs_fruit(8).

Mind especially the following paragraph of the description:

Be careful when mixing shares with and without vfs_fruit. OS X clients negotiate SMB2 AAPL protocol extensions on the first tcon, so mixing shares with and without fruit will globally disable AAPL if the first tcon is without fruit.

For this reason I recommend placing some of the fruit configuration in the [global] section so that it affects all shares.

[global] section

To begin with the relevant VFS modules need to be enabled using the vfs objects parameter. fruit is the module that implements the protocol features. It depends on streams_xattr for storing the alternate data streams in extended attributes, so that also needs to be loaded.

As an inheritance from Windows some characters (such as the colon :) are illegal in SMB, while they are allowed on both macOS and Linux. This means that in order to transfer them over SMB they need to be encoded somehow, and Time Machine uses a private Unicode range for this. This is totally fine, but can (allegedly) look a bit weird if listing the files on the server. So, optionally the catia module can be used to reverse this encoding server side.

The Samba wiki page Configure Samba to Work Better with Mac OS X tells me that the module order is important and that the correct order for these three modules is this:

vfs objects = catia fruit streams_xattr

Next, the fruit module needs to be told where to store the alternate data streams. The default storage is a file, which is slow but works with every filesystem. It can also use xattrs, but only with filesystems that support very large xattrs such as ZFS, the greatest filesystem that ever was or will be. As it happens, ZFS is what I use and thus I add:

fruit:resource = xattr

To tell fruit to reverse the encoding of the aforementioned illegal characters using the catia module, the following parameter must be set:

fruit:encoding = native

I also enabled fruit:copyfile which enables a feature that lets the client request a server side file copy for increased performance. It is not enabled by default and I cannot find a quotation why.

Per share configuration

The last part necessary is to mark a specific share as an allowed Time Machine target. This is done using the parameter

fruit:time machine = yes

Since Time Machine will fill the target with as many backups as there is space for before removing old ones it is a good idea to set a reasonable advertised limit. Note according to vfs_fruit(8) that this only works as intended when the share is used solely as a Time Machine target.

fruit:time machine max size = 1536G

While it is possible to place also these parameters in the [global] section, you probably don't want to allow all shares to be used as Time Machine destinations.

ZFS specific configuration

Extended attributes are enabled by default in ZFS (xattr=on). The default storage is directory based, which is compatible with very old (pre-OpenZFS) implementations. The last open source version of OpenSolaris (Nevada b137) as well as all OpenZFS versions as far as I am aware supports storing extended attributes as system attributes, which greatly increase their performance due to fewer disk accesses. To switch to system attributes:

zfs set xattr=sa <pool>/<filesystem>

Conclusion

That should be it! Restart smbd and nmbd (I never learned which service does what) to apply the configuration:

systemctl restart smbd nmbd

With a default Avahi configuration the configured volume should now appear as an available target in Time Machine.