
Restic: резервное копирование на Mac по схеме 3-2-1
У меня есть макбук, на котором я пишу программы, тексты и книги, работаю с документами. Здесь лежат проекты за несколько лет, заметки в Obsidian, рукописи, конфиги, переписка. Если диск умрёт или ноутбук украдут — пропадёт всё, что нажито непосильным трудом. Поэтому мне нужно было организовать качественное резервное копирование по схеме 3-2-1, о которой я подробно рассказывал в одном из предыдущих постов.
Напомню суть: три копии данных, на двух разных типах носителей, одна из которых хранится за пределами дома. Звучит как паранойя, но на самом деле это минимальный здравый смысл. Пожар, кража, случайное rm -rf — и одной копии может не хватить.
Изучив решения для реализации такого копирования, я выбрал restic — и хочу рассказать, почему именно его и как всё реализовано.
Почему restic
Когда выбираешь инструмент для бэкапов, хочется найти что-то одновременно простое и надёжное. Я перебрал несколько вариантов — BorgBackup, Duplicacy, Kopia — и в итоге остановился на restic. Вот что в нём подкупило.
Restic — это программа с открытым исходным кодом, написанная на Go. Один бинарный файл, никаких зависимостей, работает на macOS, Linux, Windows и даже FreeBSD. Ставится через brew install restic и сразу готова к работе.
Мне понравилось, что restic шифрует всё. Не отдельные файлы, а вообще всё: содержимое, имена файлов, структуру каталогов, метаданные. Используется AES-256 с аутентификацией Poly1305, ключи выводятся через scrypt. Это значит, что даже если кто-то получит доступ к хранилищу с бэкапами — без пароля он увидит только набор зашифрованных блоков.
Второе важное свойство — дедупликация. Restic разбивает файлы на блоки переменной длины и сохраняет только уникальные блоки. Если я изменил три строчки в большом файле, в бэкап попадёт только изменённый кусок, а не весь файл заново. На практике это экономит место в разы, особенно когда бэкапы делаются каждый день.
Третье — restic работает с кучей бэкендов для хранения. Локальная папка, внешний диск, SFTP-сервер, Amazon S3, Backblaze B2, REST-сервер — всё это поддерживается из коробки. Мне это позволяет хранить копии в трёх разных местах, используя один и тот же инструмент.
И наконец — простота. У restic понятный набор команд: init для создания репозитория, backup для копирования, restore для восстановления, snapshots для просмотра истории, forget для удаления старых снапшотов. Не нужно читать документацию неделями, чтобы начать пользоваться.
Что копируется и куда
Я собрал все настройки в одном конфигурационном файле — restic-config.sh. В нём описано три вещи: какие папки копировать, куда копировать и что исключить.
Список папок — это просто массив путей. У меня туда входят рабочие проекты, заметки, сайты, рукописи и блог. Выглядит это примерно так:
BACKUP_SOURCES=(
"$HOME/Documents/Notes"
"$HOME/Projects"
"$HOME/Sites"
"$HOME/Documents/Book"
"$HOME/Documents/Blog"
)
Дальше — список репозиториев, то есть мест, куда restic складывает бэкапы. У каждого репозитория есть имя, путь и необязательная проверка доступности. Например, для внешнего диска проверка — это наличие точки монтирования. Если диск не подключён, скрипт это поймёт и пропустит.
RESTIC_REPOS=(
"local|$HOME/backup/restic_repo|$HOME/backup"
"remote|sftp://user@myserver/restic_repo|"
"disk|/Volumes/BackupDisk/restic_repo|/Volumes/BackupDisk"
)
Три репозитория — три копии. Локальная папка на встроенном диске, удалённый сервер по SFTP и внешний USB-диск. Это и есть схема 3-2-1: три копии, два типа носителей (встроенный SSD и внешний диск), одна копия удалённо (сервер).
Исключения тоже задаются в конфиге. Нет смысла копировать node_modules, vendor, кеши сборки и прочий мусор, который легко восстановить. Для этого используются glob-паттерны, а ещё есть механизм файлов-маркеров: если в папке лежит файл .nobackup, её содержимое не копируется.
Пароль для шифрования хранится в отдельном файле. Все репозитории используют один и тот же пароль — это важно, потому что иначе копирование между ними не будет работать.
Как устроено копирование
Скрипт backup.sh — это обёртка над restic, которая делает всю работу автоматически. Запускаешь его, и он последовательно копирует данные во все настроенные репозитории.
Но делает он это умнее, чем просто «запустить restic backup три раза». Есть два режима работы.
В основном режиме скрипт сначала делает бэкап в «основной» репозиторий — у меня это локальная папка. Это самый быстрый вариант, потому что данные пишутся на локальный диск. Restic создаёт снапшот, запоминает его идентификатор. Потом скрипт берёт этот снапшот и копирует его в «зеркала» — на удалённый сервер и на внешний диск — с помощью команды restic copy. Это экономит время: данные собираются с диска один раз, а не три, и restic передаёт в зеркала только недостающие блоки.
Есть и «прямой» режим (--direct), когда каждый репозиторий бэкапится независимо. Это полезно, если основной репозиторий по какой-то причине недоступен.
После копирования скрипт применяет политику хранения. В моём случае хранятся ежедневные снапшоты за последнюю неделю, еженедельные — за последний месяц и ежемесячные — за полгода. Всё, что старше, удаляется автоматически, а с флагом --prune освобождается и место на диске.
RETENTION_KEEP_DAILY=7
RETENTION_KEEP_WEEKLY=4
RETENTION_KEEP_MONTHLY=6
Скрипт защищён от параллельного запуска через блокировку. Если бэкап уже работает, второй экземпляр не запустится. Если какой-то репозиторий недоступен (диск не подключён, сервер не отвечает), скрипт может либо упасть с ошибкой, либо пропустить его и продолжить — в зависимости от флагов.
Есть режим --dry-run, который показывает, что было бы сделано, но ничего не записывает. Полезно при первой настройке, чтобы убедиться, что всё сконфигурировано правильно.
Как устроено восстановление
Скрипт restore.sh — это удобная обёртка для восстановления данных. Он читает тот же конфиг, знает обо всех репозиториях и предлагает набор подкоманд.
Чтобы посмотреть список доступных репозиториев, достаточно набрать ./restore.sh repos. Чтобы увидеть все снапшоты в репозитории — ./restore.sh snapshots. По умолчанию используется первый репозиторий из конфига, но можно явно указать любой через --repo.
Для восстановления нужно указать идентификатор снапшота (или latest для последнего) и целевую папку:
./restore.sh restore latest --target ~/restore
Можно восстановить не весь снапшот, а конкретную папку из него — это удобно, когда нужен только один проект или одна заметка:
./restore.sh restore latest /Users/me/Documents/Notes --target ~/restore/notes
Есть команда ls для просмотра содержимого снапшота — можно заглянуть внутрь, не восстанавливая ничего на диск. И команда dump для извлечения одного файла — она выводит содержимое прямо в терминал, что бывает полезно для быстрой проверки.
Флаг --verify после восстановления проверяет целостность восстановленных файлов. Флаг --dry-run показывает, что будет восстановлено, без фактической записи на диск.
Что в итоге получилось
В результате у меня работает полноценная схема 3-2-1. Скрипт backup.sh запускается регулярно, делает снапшот в локальный репозиторий на SSD, затем копирует его на удалённый сервер по SFTP и на внешний USB-диск, если тот подключён.
Все три копии зашифрованы одним паролем. Дедупликация делает так, что ежедневные бэкапы занимают мало места — сохраняются только изменения. Политика хранения автоматически чистит старые снапшоты, не давая репозиториям разрастаться бесконечно.
Если встроенный диск умрёт, я восстановлюсь с внешнего. Если ноутбук украдут вместе с внешним диском (маловероятно, но бывает) — восстановлюсь с сервера. Данные зашифрованы, поэтому даже если кто-то получит физический доступ к любому из хранилищ, без пароля он ничего не увидит.
Восстановление проверено и работает. Это, пожалуй, самый важный момент во всей истории. Бэкап, который ни разу не восстанавливали — это не бэкап, а самоуспокоение. Периодически я делаю тестовое восстановление в отдельную папку и проверяю, что все файлы на месте и читаются. Скрипт restore.sh делает это в одну команду, так что нет причин не проверять.
Restic оказался именно тем инструментом, который мне был нужен: простым, надёжным и достаточно гибким, чтобы реализовать схему 3-2-1 парой скриптов. Если вы до сих пор не делаете бэкапы — самое время начать. А если делаете — проверьте, что умеете из них восстанавливаться.