ИТ

Time Machine по SMB: автоматический бэкап macOS Tahoe на Samba NAS

macOS Tahoe 26 сломала бэкапы Time Machine на Samba NAS. Старый способ с ручным созданием sparsebundle через hdiutil и указанием tmutil на примонтированный том перестал работать. Вместо бэкапа вы получаете ошибки Structure has wrong type, падения при thinning и отказ запускаться. Решение: перестать создавать sparsebundle вручную и дать macOS сделать это самой через SMB, используя модуль Samba fruit:time machine.

Ниже полная настройка: шара Samba на контейнере Proxmox, конфиг SMB-клиента macOS, LaunchAgent с определением домашней сети и защитой от засыпания во время записи, и список исключений, который держит размер бэкапа в рамках. Проверено на macOS Tahoe 26.x с Samba 4.17 в LXC-контейнере Proxmox. Все конфиги лежат в репозитории macos-timemachine.

Архитектура

macOS подключается к шаре Samba по SMB3, сама создает APFS-совместимый sparsebundle и дальше управляет им: полные бэкапы, инкрементальные снапшоты, очистка старых данных. Без NFS, без ручных образов дисков.

macOS (tmutil) → SMB3 → Samba 4.17 (fruit:time machine) → ZFS storage
                         ↓
              Proxmox LXC контейнер
              /mnt/storage/_TIMEMACHINE/
              bind mount с /sn850x/storage/

Samba работает в легковесном контейнере Proxmox с bind mount на ZFS-пул хоста. Это отделяет процесс Samba от железа хранилища, но I/O идет напрямую. У контейнера выделенный VIP (10.0.1.250) для HA-фейловера, хотя для одного узла хватит и статического IP.

Почему старый способ сломался на Tahoe

До Tahoe стандартный подход для Time Machine по SMB был такой: создать sparsebundle вручную через hdiutil create, примонтировать как том и выполнить tmutil setdestination /Volumes/TM-Backup. На Monterey, Ventura и Sonoma это работало без проблем.

В Tahoe Apple изменила внутреннюю структуру бэкапов. Time Machine теперь ожидает APFS-совместимые метаданные внутри sparsebundle, которые может правильно записать только сама macOS. Образ, созданный вручную, проходит начальную проверку setdestination, но падает при thinning с ошибками TMStructureErrorDomain Code=7. Данные бэкапа пишутся, но macOS не может удалять старые снапшоты, и sparsebundle растет, пока не заполнит диск.

Решение: перестать создавать sparsebundle самому. Указать tmutil на SMB-шару с fruit:time machine = yes, и macOS создаст правильную структуру с нуля.

Настройка Samba на NAS

Конфиг Samba состоит из двух частей: глобальные настройки для Apple SMB-расширений и определение шары Time Machine.

Глобальная конфигурация

Apple-расширения для SMB требуют fruit:aapl = yes в глобальной секции. Без этого macOS не определит шару как совместимую с Time Machine.

[global]
   workgroup = WORKGROUP
   security = user

   # Только SMB3 (обязательно для Tahoe)
   server min protocol = SMB2
   server max protocol = SMB3_11
   client min protocol = SMB2
   client max protocol = SMB3_11

   # Тюнинг производительности для 10GbE / большой 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-расширения (должны быть в global)
   vfs objects = fruit streams_xattr
   fruit:aapl = yes
   fruit:nfs_aces = no
   fruit:metadata = stream

Шара Time Machine

Шаре нужен fruit:time machine = yes и несколько дополнительных параметров. fruit:model = TimeCapsule6,116 заставляет NAS отображаться в Finder как Apple Time Capsule. Чисто косметика, но выглядит приятно.

[timemachine]
   comment = Time Machine Backups
   path = /mnt/storage/_TIMEMACHINE
   browseable = yes
   writable = yes
   valid users = private

   # Поддержка Apple Time Machine
   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

   # Блокировки (важно для целостности sparse bundle)
   durable handles = yes
   kernel share modes = no
   posix locking = no

   create mask = 0660
   directory mask = 0770
   force user = root
   force group = root

После редактирования /etc/samba/smb.conf перезагрузите конфиг:

smbcontrol all reload-config

Создайте пользователя Samba, если его еще нет:

smbpasswd -a private

Настройка macOS

Параметры SMB-клиента

В Tahoe изменилось поведение SMB signing. Без signing_required=yes в /etc/nsmb.conf бэкапы могут молча падать или записывать поврежденные данные. Этот файл действует на все SMB-подключения с вашего мака.

# /etc/nsmb.conf
[default]
signing_required=yes
streams=yes
soft=yes
dir_cache_max_cnt=0
protocol_vers_map=6
mc_prefer_wired=yes

Скопируйте на место:

sudo cp nsmb.conf /etc/nsmb.conf

protocol_vers_map=6 форсирует SMB3 (значение 6 = SMB 2 + SMB 3). dir_cache_max_cnt=0 отключает кэширование директорий, что предотвращает проблемы с устаревшими метаданными sparsebundle. mc_prefer_wired=yes направляет трафик через Ethernet, если подключены и Wi-Fi, и кабель. При сложной сетевой топологии на стороне NAS смотрите мультишлюзовую маршрутизацию в Linux.

Пароль SMB в Keychain

Сохраните пароль Samba в macOS Keychain, чтобы скрипт бэкапа мог авторизоваться без захардкоженных паролей:

security add-internet-password -s "10.0.1.250" -a "private" -w "ВАШ_ПАРОЛЬ"

Назначение destination для Time Machine

Вместо монтирования тома и указания на локальный путь, направьте tmutil на SMB-шару напрямую:

sudo tmutil setdestination "smb://private@10.0.1.250/timemachine"

macOS подключится к шаре, создаст sparsebundle с именем вашего компьютера (что-то вроде MacBook Pro - Ilia.sparsebundle) и запустит первый полный бэкап. Это может занять несколько часов в зависимости от объема данных и скорости сети.

Важно: Terminal (или iTerm) нужен Full Disk Access в System Settings > Privacy & Security > Full Disk Access. Без этого tmutil setdestination завершится молча без эффекта.

Автоматизация бэкапов через LaunchAgent

macOS запускает Time Machine по своему расписанию, но это расписание подразумевает, что диск бэкапа всегда доступен. С сетевым destination, который может быть недоступен (ноутбук не дома, NAS перезагружается, Wi-Fi отвалился), нужно что-то поумнее. LaunchAgent из этого проекта каждые 5 минут проверяет, находитесь ли вы в домашней сети и не просрочен ли бэкап, и запускает его при необходимости.

Скрипт бэкапа

Скрипт (timemachine-smb.sh) обрабатывает граничные случаи, которые встроенный планировщик Apple игнорирует:

  • Проверяет, что текущий IP в диапазоне 10.0.1.x. Если вы в кафе или на мобильном интернете, скрипт сразу завершается.
  • Использует lock-файл для защиты от параллельного запуска, если LaunchAgent сработает, пока предыдущая проверка еще идет.
  • Ждет разблокировки Keychain при загрузке (до 30 секунд), потому что при старте системы Keychain может быть еще заблокирован.
  • Оборачивает бэкап в caffeinate -s, чтобы мак не уснул посреди записи и не повредил sparsebundle.
  • Запускает бэкап, только если последний завершился более 23 часов назад. Примерно один бэкап в сутки.
  • Ротирует лог-файл, держа его не больше 300 строк.

Установка скрипта:

mkdir -p ~/.local/bin
cp timemachine-smb.sh ~/.local/bin/
chmod +x ~/.local/bin/timemachine-smb.sh

LaunchAgent

Plist-файл (com.user.timemachine-smb.plist) запускает скрипт по трем триггерам:

  • При логине (RunAtLoad), чтобы наверстать, если мак был выключен всю ночь.
  • Каждые 5 минут (StartInterval: 300) для проверки просроченных бэкапов.
  • При смене сети (WatchPaths), чтобы запуститься сразу при подключении к домашнему Ethernet или Wi-Fi, не дожидаясь следующего 5-минутного тика.

Установка и загрузка:

cp com.user.timemachine-smb.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.user.timemachine-smb.plist

Исключения для экономии места

Time Machine по умолчанию бэкапит все, но на машине разработчика десятки гигабайт данных, которые пересоздаются по требованию: кэши сборки, образы симуляторов, загрузки пакетных менеджеров, слои Docker. Исключение этих путей сокращает размер и время бэкапа без потери чего-либо, что нельзя переустановить или пересобрать.

Файл timemachine-exclusions.json в репозитории содержит 24 пути исключений. Основные категории:

КатегорияПутиПочему исключаем
Облачные данныеiCloud Drive, CloudStorageУже бэкапятся через Apple/Google/Dropbox
XcodeDerivedData, CoreSimulator, iOS DeviceSupportПересоздаются при сборке, обычно 20-50 ГБ
Android Studio~/.gradle, Android SDKСкачиваются по требованию
Пакетные менеджерыnpm, rustup, cargo, cocoapods, goПереустанавливаются из lockfile
Dockercom.docker.docker контейнерОбразы качаются из registry
Большие медиаDownloads, Movies, Steam, ParallelsЗаменимые или слишком большие
Dev-инструментыVS Code workspaceStorage, Claude vm_bundlesКэш и временные файлы

Применить все исключения разом:

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')
"

Диагностика

Несколько команд, которые пригодятся для проверки работоспособности:

# Текущий статус бэкапа (запущен / простаивает)
tmutil status

# Время последнего завершенного бэкапа
tmutil latestbackup

# Настроенные destination
tmutil destinationinfo

# Лог LaunchAgent (в реальном времени)
tail -f ~/Library/Logs/timemachine-smb.log

# Размер бэкапа на NAS
ssh root@nas 'du -sh /path/to/_TIMEMACHINE/MacBook*/'

Решение проблем на macOS Tahoe

Не установлен signing_required

В Tahoe изменилась политика SMB signing. Если пропустить шаг с /etc/nsmb.conf, подключения к Samba могут периодически отваливаться или давать IO-ошибки посреди бэкапа. Типичный симптом: бэкап стартует, записывает несколько сотен мегабайт, затем падает с сообщением «backup disk not available».

Structure has wrong type (ошибки thinning)

Если в Console.app видны ошибки TMStructureErrorDomain Code=7 при thinning, это косметическая проблема из-за несовместимости метаданных Samba 4.17 и Tahoe. Данные бэкапа целы, новые бэкапы продолжают работать. Samba 4.23+ решает это полностью, но и на 4.17 ошибки ничего не блокируют.

SMB отключается при засыпании

Когда macOS засыпает, SMB-соединение разрывается. Если бэкап шел в этот момент, он падает с ошибкой BACKUP_FAILED_TARGETVOL_NOT_FOUND (18). Это ожидаемое поведение. Скрипт использует caffeinate -s, чтобы мак не засыпал во время активной записи. Если мак все-таки заснул между проверками, следующее пробуждение обнаружит просроченный бэкап и перезапустит его. Time Machine продолжит инкрементально с того места, где остановилась.

Full Disk Access для Terminal

Команда tmutil setdestination требует Full Disk Access для терминального эмулятора. Откройте System Settings > Privacy & Security > Full Disk Access и добавьте Terminal.app (или iTerm). Без этого команда завершается без ошибки и без результата.

Non-ASCII символы в имени компьютера

macOS использует имя компьютера для названия файла sparsebundle. Если в нем есть длинное тире (U+2014) или неразрывный пробел (U+00A0), у Samba могут возникнуть проблемы с файловыми операциями. При ошибках, связанных с путями, упростите имя:

sudo scutil --set ComputerName "MacBook-Ilia"

NFS как запасной вариант

SMB — единственный протокол, который Time Machine поддерживает для сетевых бэкапов. Но NFS полезен для обслуживания: просмотр директории бэкапа с другой машины, проверка занятого места, удаление старых sparsebundle. Если ваш хост Proxmox экспортирует директорию хранилища по NFS:

sudo mount_nfs -o rw,resvport 10.0.1.223:/sn850x/storage/_TIMEMACHINE /Volumes/timemachine-nfs

Это удобно для быстрой чистки, но никогда не используйте NFS как destination для Time Machine.

FAQ

Можно ли использовать эту настройку без Proxmox?

Да. Конфигурация Samba одинаковая независимо от хост-платформы. Любая Linux-машина с Samba 4.11+ и поддержкой fruit VFS подойдет. Proxmox здесь только слой виртуализации.

Работает ли это на macOS Sonoma или старше?

Подход с fruit:time machine работает и на Sonoma, Ventura, Monterey. Разница в том, что на тех версиях ручной sparsebundle тоже работает. На Tahoe 26.x только SMB-нативный способ работает надежно.

Сколько места нужно на NAS?

Ориентир — 2-3x от занятого места на вашем маке. Параметр fruit:time machine max size = 900G в конфиге Samba ограничивает максимальный размер бэкапа, так что sparsebundle не съест весь диск, если thinning отстает.

Что будет, если NAS недоступен в момент бэкапа?

Скрипт LaunchAgent проверяет наличие домашней сети (диапазон 10.0.1.x) перед любыми действиями. Если NAS недоступен, скрипт молча завершается. Следующая 5-минутная проверка попробует снова. Без ошибок, без уведомлений.

Можно ли бэкапить несколько маков на одну шару?

Да. Каждый мак создает свой sparsebundle с уникальным именем на основе имени компьютера и аппаратного UUID. Можно добавить пользователей в строку valid users или использовать общий аккаунт. Параметр fruit:time machine max size действует на всю шару, а не на отдельную машину, так что планируйте объем хранилища с учетом этого.

Итого

На macOS Tahoe fruit:time machine — единственный рабочий способ запустить Time Machine по SMB на Samba NAS. После правильной настройки шары macOS сама создает sparsebundle, и дальше все работает как задумано: инкрементальные снапшоты, автоматическая очистка, шифрование. LaunchAgent делает процесс полностью автоматическим: бэкап раз в сутки дома, пропуск вне сети, защита от засыпания во время записи.

Все конфиги, скрипт бэкапа и список исключений лежат в репозитории macos-timemachine на GitHub. Для мониторинга Proxmox-хоста и контейнеров, на которых работает NAS, смотрите серверную инвентаризацию через golauncher.

Оцените статью