macOS Tahoe 26 broke Time Machine backups to Samba NAS shares. The old trick of creating a sparsebundle with hdiutil and pointing tmutil at a mounted volume stopped working. You get cryptic Structure has wrong type errors, thinning failures, and backups that refuse to start. The fix: stop making the sparsebundle yourself and let macOS create it over SMB, using Samba’s fruit:time machine VFS module.
Below is the full setup: Samba share on a Proxmox container, macOS SMB client config, a LaunchAgent that detects your home network and prevents sleep during writes, and an exclusion list that keeps backup size sane by skipping dev caches and cloud-synced data. Tested on macOS Tahoe 26.x with Samba 4.17 in a Proxmox LXC container. All config files are in the macos-timemachine repository.
- Architecture
- Why the Old Method Broke on Tahoe
- Setting Up Samba on the NAS
- Global Configuration
- Time Machine Share
- Configuring macOS
- SMB Client Settings
- SMB Password in Keychain
- Setting the Time Machine Destination
- Automating Backups with a LaunchAgent
- The Backup Script
- The LaunchAgent
- Exclusions That Save Space
- Diagnostics
- Troubleshooting macOS Tahoe Issues
- signing_required Not Set
- Structure has wrong type (thinning errors)
- SMB Disconnects During Sleep
- Full Disk Access for Terminal
- Non-ASCII Characters in Computer Name
- NFS as a Fallback
- FAQ
- Can I use this setup with a non-Proxmox Samba server?
- Does this work with macOS Sonoma or older versions?
- How much storage do I need on the NAS?
- What happens if the NAS is offline when a backup is scheduled?
- Can multiple Macs back up to the same Samba share?
- Summary
Architecture
macOS connects to a Samba share over SMB3, creates its own APFS-compatible sparsebundle, and manages everything from there: full backups, incremental snapshots, thinning old data. No NFS, no manual disk images.
macOS (tmutil) → SMB3 → Samba 4.17 (fruit:time machine) → ZFS storage
↓
Proxmox LXC container
/mnt/storage/_TIMEMACHINE/
bind-mounted from /sn850x/storage/ The Samba server runs inside a lightweight Proxmox LXC container with a bind mount to the actual ZFS pool on the host. This separates the Samba process from the storage hardware while keeping I/O direct. The container has a dedicated VIP (10.0.1.250) for HA failover, though a static IP works fine for a single-node setup.
Why the Old Method Broke on Tahoe
Before Tahoe, the standard approach for Time Machine over SMB was to create a sparsebundle manually with hdiutil create, mount it as a volume, and run tmutil setdestination /Volumes/TM-Backup. This worked reliably on Monterey, Ventura, and Sonoma.
Tahoe changed the internal backup structure. Time Machine now expects APFS-compatible metadata inside the sparsebundle that only macOS itself can write correctly. A manually created disk image passes the initial setdestination check but fails during thinning with TMStructureErrorDomain Code=7 errors. The backup data still writes, but macOS can never clean up old snapshots, and the sparsebundle grows until it fills the disk.
The solution is to stop creating the sparsebundle yourself. Point tmutil at an SMB share with fruit:time machine = yes, and macOS will create the right structure from scratch.
Setting Up Samba on the NAS
The Samba configuration has two parts: global settings for Apple SMB extensions, and the Time Machine share itself.
Global Configuration
Apple’s SMB extensions require fruit:aapl = yes in the global section. Without it, macOS won’t detect the share as Time Machine-compatible.
[global]
workgroup = WORKGROUP
security = user
# SMB3 only (required for Tahoe)
server min protocol = SMB2
server max protocol = SMB3_11
client min protocol = SMB2
client max protocol = SMB3_11
# Performance tuning for 10GbE / large MTU
server multi channel support = yes
aio read size = 1
aio write size = 1
socket options = TCP_NODELAY SO_RCVBUF=8388608 SO_SNDBUF=8388608
use sendfile = yes
# Apple extensions (must be global)
vfs objects = fruit streams_xattr
fruit:aapl = yes
fruit:nfs_aces = no
fruit:metadata = stream Time Machine Share
The share needs fruit:time machine = yes and several supporting options. fruit:model = TimeCapsule6,116 makes your NAS show up as a Time Capsule icon in Finder, which is purely cosmetic but looks nice.
[timemachine]
comment = Time Machine Backups
path = /mnt/storage/_TIMEMACHINE
browseable = yes
writable = yes
valid users = private
# Apple Time Machine support
vfs objects = catia fruit streams_xattr
fruit:aapl = yes
fruit:time machine = yes
fruit:time machine max size = 900G
fruit:metadata = stream
fruit:model = TimeCapsule6,116
fruit:posix_rename = yes
fruit:veto_appledouble = no
fruit:wipe_intentionally_left_blank_rfork = yes
fruit:delete_empty_adfiles = yes
# Locking (important for sparse bundle integrity)
durable handles = yes
kernel share modes = no
posix locking = no
create mask = 0660
directory mask = 0770
force user = root
force group = root After editing /etc/samba/smb.conf, reload the configuration:
smbcontrol all reload-config Create the Samba user if it doesn’t exist:
smbpasswd -a private Configuring macOS
SMB Client Settings
Tahoe changed the default SMB signing behavior. Without signing_required=yes in /etc/nsmb.conf, backups may silently fail or produce corrupted data. This file applies system-wide to all SMB connections from your Mac.
# /etc/nsmb.conf
[default]
signing_required=yes
streams=yes
soft=yes
dir_cache_max_cnt=0
protocol_vers_map=6
mc_prefer_wired=yes Copy it into place:
sudo cp nsmb.conf /etc/nsmb.conf protocol_vers_map=6 forces SMB3 (value 6 = SMB 2 + SMB 3). dir_cache_max_cnt=0 disables directory caching, which prevents stale metadata issues with sparsebundles. mc_prefer_wired=yes routes traffic over Ethernet when both Wi-Fi and Ethernet are connected. If you run a multi-gateway setup, see Linux Network Manager routing for handling complex network topologies on the NAS side.
SMB Password in Keychain
Store the Samba password in your macOS Keychain so the backup script can authenticate without hardcoding credentials:
security add-internet-password -s "10.0.1.250" -a "private" -w "YOUR_PASSWORD" Setting the Time Machine Destination
Instead of mounting a volume and pointing to a local path, tell tmutil to use the SMB share directly:
sudo tmutil setdestination "smb://private@10.0.1.250/timemachine" macOS will connect to the share, create a sparsebundle named after your computer (something like MacBook Pro - Ilia.sparsebundle), and start the first full backup. This process can take several hours depending on your data size and network speed.
Important: Terminal (or iTerm) needs Full Disk Access in System Settings > Privacy & Security > Full Disk Access. Without it, tmutil setdestination will fail silently.
Automating Backups with a LaunchAgent
macOS runs Time Machine on its own schedule, but that schedule assumes the backup disk is always available. With a network destination that might be unreachable (laptop away from home, NAS rebooting, Wi-Fi down), you need something smarter. The LaunchAgent in this project checks every 5 minutes whether you’re on the home network and whether a backup is overdue, then triggers one if needed.
The Backup Script
The script (timemachine-smb.sh) deals with edge cases that Apple’s built-in scheduler ignores:
- Checks if the current IP is in the 10.0.1.x range before doing anything. If you’re at a coffee shop or on cellular, it exits immediately.
- Uses a lock file to prevent multiple instances if the LaunchAgent fires while a previous check is still running.
- Waits for Keychain at boot (retries up to 30 seconds) since the Keychain may not be unlocked yet when the LaunchAgent starts.
- Wraps the backup in
caffeinate -sso macOS doesn’t sleep mid-write and corrupt the sparsebundle. - Only triggers a backup if the last one finished more than 23 hours ago. Roughly one backup per day.
- Rotates the log file, keeping it under 300 lines.
Install the script:
mkdir -p ~/.local/bin
cp timemachine-smb.sh ~/.local/bin/
chmod +x ~/.local/bin/timemachine-smb.sh The LaunchAgent
The plist file (com.user.timemachine-smb.plist) runs the script on three triggers:
- At login (
RunAtLoad) to catch up if the Mac was off overnight. - Every 5 minutes (
StartInterval: 300) to poll for overdue backups. - On network change (
WatchPaths) so it fires immediately when you plug into Ethernet or join home Wi-Fi, instead of waiting for the next 5-minute tick.
Install and load it:
cp com.user.timemachine-smb.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.user.timemachine-smb.plist Exclusions That Save Space
Time Machine backs up everything by default, but a developer’s machine has tens of gigabytes of regenerable data: build caches, simulator images, package manager downloads, Docker layers. Excluding these paths cuts backup size and duration without losing anything that can’t be reinstalled or rebuilt.
The timemachine-exclusions.json file in the repository contains 24 exclusion paths. Here are the main categories:
| Category | Paths | Why exclude |
|---|---|---|
| Cloud-synced data | iCloud Drive, CloudStorage | Already backed up by Apple/Google/Dropbox |
| Xcode | DerivedData, CoreSimulator, iOS DeviceSupport | Regenerates on build, 20-50 GB typically |
| Android Studio | ~/.gradle, Android SDK | Downloaded on demand |
| Package managers | npm, rustup, cargo, cocoapods, go | Reinstalled from lockfiles |
| Docker | com.docker.docker container | Images pulled from registry |
| Large media | Downloads, Movies, Steam, Parallels | Replaceable or too large |
| Dev tools | VS Code workspaceStorage, Claude vm_bundles | Cache and temp files |
Apply all exclusions at once:
python3 -c "
import json, subprocess
data = json.load(open('timemachine-exclusions.json'))
for path in data['SkipPaths']:
subprocess.run(['tmutil', 'addexclusion', path])
print('Done: excluded', len(data['SkipPaths']), 'paths')
" Diagnostics
A few commands you’ll use regularly to verify everything works:
# Current backup status (running / idle)
tmutil status
# Last completed backup timestamp
tmutil latestbackup
# Configured destinations
tmutil destinationinfo
# LaunchAgent log (real-time)
tail -f ~/Library/Logs/timemachine-smb.log
# Backup size on the NAS
ssh root@nas 'du -sh /path/to/_TIMEMACHINE/MacBook*/' Troubleshooting macOS Tahoe Issues
signing_required Not Set
Tahoe changed the default SMB signing policy. If you skip the /etc/nsmb.conf step, connections to Samba may fail intermittently or produce IO errors mid-backup. The symptom is usually a backup that starts, writes a few hundred MB, then aborts with a generic “backup disk not available” message.
Structure has wrong type (thinning errors)
If you see TMStructureErrorDomain Code=7 in Console.app during thinning, these are cosmetic errors caused by metadata incompatibilities between Samba 4.17 and Tahoe. Your backup data is intact and new backups continue to work. Samba 4.23+ resolves this fully, but even on 4.17 the errors don’t block anything.
SMB Disconnects During Sleep
When macOS sleeps, the SMB connection drops. If a backup is running, it fails with BACKUP_FAILED_TARGETVOL_NOT_FOUND (18). This is expected. The script uses caffeinate -s to keep the Mac awake during active writes. If the Mac sleeps between checks, the next wake-up detects the overdue backup and restarts it. Time Machine picks up incrementally from where it stopped.
Full Disk Access for Terminal
The tmutil setdestination command requires Full Disk Access for your terminal emulator. Go to System Settings > Privacy & Security > Full Disk Access and add Terminal.app (or iTerm). Without it, the command exits with no error and no effect.
Non-ASCII Characters in Computer Name
macOS uses your computer name for the sparsebundle filename. If it contains an em dash (U+2014) or non-breaking space (U+00A0), Samba may have trouble with file operations. If you hit path-related errors, simplify the name:
sudo scutil --set ComputerName "MacBook-Ilia" NFS as a Fallback
SMB is the only protocol Time Machine supports for network backups, but NFS is useful for maintenance: browsing the backup directory from another machine, checking disk usage, or deleting old sparsebundles. If your Proxmox host exports the storage directory over NFS:
sudo mount_nfs -o rw,resvport 10.0.1.223:/sn850x/storage/_TIMEMACHINE /Volumes/timemachine-nfs This is handy for quick cleanup but should never be used as the Time Machine destination itself.
FAQ
Can I use this setup with a non-Proxmox Samba server?
Yes. The Samba configuration is identical regardless of the host platform. Any Linux machine running Samba 4.11+ with fruit VFS support will work. Proxmox is just the virtualization layer in this particular setup.
Does this work with macOS Sonoma or older versions?
The fruit:time machine approach works on Sonoma, Ventura, and Monterey as well. The difference is that on those versions, the manual sparsebundle method also works. On Tahoe 26.x, only the SMB-native approach works reliably.
How much storage do I need on the NAS?
A good rule of thumb is 2-3x your Mac’s used disk space. The fruit:time machine max size = 900G parameter in the Samba config caps the total backup size, so the sparsebundle won’t consume your entire disk if thinning falls behind.
What happens if the NAS is offline when a backup is scheduled?
The LaunchAgent script checks for the home network (10.0.1.x range) before attempting anything. If the NAS is unreachable, the script exits silently. The next 5-minute check will try again. No errors, no alerts.
Can multiple Macs back up to the same Samba share?
Yes. Each Mac creates its own sparsebundle with a unique name based on its computer name and hardware UUID. You can add more users to the valid users line or use a shared account. The fruit:time machine max size applies per-share, not per-machine, so plan your storage accordingly.
Summary
On macOS Tahoe, fruit:time machine is the only way to get Time Machine working over SMB to a Samba NAS. Once the share is configured and macOS creates its own sparsebundle, you get incremental snapshots, automatic thinning, and encryption. The LaunchAgent makes it hands-off: backup once a day when home, skip when not, stay awake during writes.
All configuration files, the backup script, and the exclusion list are in the macos-timemachine repository on GitHub. For monitoring the Proxmox host and containers that run your NAS, check out server inventory with golauncher.
