Windows のファイル履歴では速度的にクラウドへのバックアップが非現実的だったので、restic でバックアップしてみたところうまくいきました。
restic は Linux ユーザーが多い印象ですが、VSS スナップショットをバックアップすることもできて、Windows のバックアップ ソフトとしても素晴らしいと思いました。
Windows のハード リンクや、開発者モード無効時に作成した WSL や cygwin のシンボリック リンクの扱いに課題がありますが、大きな問題にならない場合が多いのではないかと思います。
この記事では、低価格な S3 互換ストレージ、Backblaze B2 で使う手順を紹介します。
インストール
VSS を使う場合は管理者権限で使うことになるので、SYSTEM アカウントを使うことがあると思います。以下のように --scope Machine を指定して %ProgramFiles% にインストールするのがおすすめです。
winget install --id restic.restic --scope Machine
環境変数の設定
環境変数 RESTIC_PASSWORD を設定します。
私は iPhone のパスワード アプリで提案されたものをそのまま使っていますが、オフラインでの攻撃に耐えられる強度になっているかは不安です。Git Bash の openssl などで、もっと長いパスワードを生成したほうが良いかもしれません。
$ openssl rand -base64 27
Backblaze B2 のバケット作成
Backblaze B2 でバケットを作成します。以下の設定としました。
エラー ハンドリングの問題を避けるために S3 互換 API で操作しますが、そうするとファイルを削除できず、隠すだけになってしまいます。高額課金を防ぐために、Keep only the last version of the file と設定し、隠したファイルが1日で削除されるようにすることが推奨されています。
- Bucket Unique Name: hanotch
- Type: Private
- Default Encryption: Enable
- Object Lock: Disable
- Endpoint: s3.us-west-004.backblazeb2.com (私の場合)
- Lifecycle Settings: Keep only the last version of the file
Endpoint は人によって異なります。後で使います。
App Key の作成
https://secure.backblaze.com/app_keys.htm の Add a New Application Key をクリックし、以下の設定で作成しました。
- Name of Key: hanotch-restic
- Allow access to Bucket(s): hanotch
- Type of Access: Read and Write
S3 互換 API 利用の設定
環境変数の設定が必要です。以下では、スクリプトとして作成しました。バックアップに VSS を使う場合は管理者として PowerShell を実行してください。
$env:AWS_ACCESS_KEY_ID = keyID
$env:AWS_SECRET_ACCESS_KEY = applicationKey
以降、以下のようにこのスクリプトを使うなどして、これらの環境変数が設定されている前提とします。
. .\restic_env.ps1
普通の変数ではなく環境変数の設定なので、. ではなく & でも動くのですが、一応 . にしました。
リポジトリーの初期化
以下のコマンドでリポジトリーを初期化します。
restic init -r s3:endpoint/bucket_name/restic-repo
バックアップの実行
restic backup -r s3:endpoint/bucket_name/restic-repo に以下のオプションを使って "$env:USERPROFILE" をバックアップします。
バックアップ対象やオプションはお好みで調整してください。私は以下を指定しています。
-
--use-fs-snapshot: VSS を使うための設定 -
-o vss.exclude-all-mount-points=true: 外付けドライブに VSS を使わないための設定 (バックアップ中に取り外せるように) -
--iexclude "$env:TEMP": 一時ディレクトリーを除外。--iexcludeは大文字小文字を区別せず指定されたものを除外する。 -
--iexclude "$env:LOCALAPPDATA\Microsoft\WindowsApps": 管理者でもアクセスできないファイルがあって気になるので除外 -
--exclude-caches: Cache Directory Tagging Specification
に準拠したお行儀のよいキャッシュ ディレクトリーを除外 -
--iexclude "cache":cacheという名前のものを除外 -
--iexclude ".cache":.cacheという名前のものを除外 -
--iexclude "__pycache__": コンパイルされた Python コードを除外 -
--iexclude "$env:USERPROFILE\.m2\repository": Java の Maven リポジトリー (キャッシュのようなもの) を除外 -
--iexclude ".venv":.venvという名前の Python 仮想環境を除外 -
--iexclude "venv":venvという名前の Python 仮想環境を除外 -
--iexclude "node_modules": npm や bun がインストールしたモジュールを除外
完成したコマンドは以下のようになりました。
restic backup `
-r s3:endpoint/bucket_name/restic-repo `
--use-fs-snapshot `
-o vss.exclude-all-mount-points=true `
--iexclude "$env:TEMP" `
--iexclude "$env:LOCALAPPDATA\Microsoft\WindowsApps" `
--exclude-caches `
--iexclude "cache" `
--iexclude ".cache" `
--iexclude "__pycache__" `
--iexclude "$env:USERPROFILE\.m2\repository" `
--iexclude ".venv" `
--iexclude "venv" `
--iexclude "node_modules" `
"$env:USERPROFILE"
VSS は便利ですが、過信は禁物です。以下のような性質があるようです。
- ある時点の NTFS の状態をバックアップできる
- アプリがロックしているファイルをバックアップできる
- SQL Server のデータベースの整合性の取れたバックアップが取れる (VSS writer があるため)
- PostgreSQL のデータベースの整合性の取れたバックアップは取れない (VSS writer がないため)
- WSL2 のファイルシステムの整合性の取れたバックアップは取れない
リポジトリーが壊れていないことの確認
下記コマンドで確認できます。キャッシュが壊れた時にも使います。
restic check -r s3:endpoint/bucket_name/restic-repo
--read-data フラグを付けると、データまで読み込みます。通常、クラウドでは利用料がかかるので避けたほうが良いと思います。
スナップショットの一覧
下記コマンドで一覧できます。
restic snapshot -r s3:endpoint/bucket_name/restic-repo
スナップショットの削除
forget サブコマンドで論理削除できます。以下のオプションと組み合わせて使います。
-
--prune: 物理削除する -
--keep-last n: 最後の n 個を残す -
--keep-hourly n: 直近 n 時間分について、各時間の最新のみを残す -
--keep-daily n: 直近の n 日分について、各日の最新のみを残す -
--keep-weekly n: 直近の n 週分について、各週の最新のみを残す -
--keep-monthly n: 直近の n 月分について、各月の最新のみを残す -
--keep-yearly n: 直近の n 年分について、各年の最新のみを残す -
--keep-within duration: latest から遡って duration (例:1y5m7d2h) より新しいスナップショットは残す -
--keep-within-hourly duration: latest から遡って duration より新しい、各時間の最新のみを残す -
--keep-within-daily duration: latest から遡って duration より新しい、各日の最新のみを残す -
--keep-within-weekly duration: latest から遡って duration より新しい、各週の最新のみを残す -
--keep-within-monthly duration: latest から遡って duration より新しい、各月の最新のみを残す -
--keep-within-yearly duration: latest から遡って duration より新しい、各年の最新のみを残す -
--tag "": タグのついていないもののみを対象とする (PowerShell 5.1 では""ではなく""""と指定する)
すべてのカレンダー関連オプション (--keep-{hourly,daily,...}) には unlimited も指定可能です。
以下のようにすれば macOS の Time Machine っぽい設定になります。
# PowerShell 7 で """" を空文字列の引数として使う
$PSNativeCommandArgumentPassing = "Legacy"
restic forget `
-r s3:endpoint/bucket_name/restic-repo `
--keep-within-hourly 1d `
--keep-within-daily 1m `
--keep-weekly unlimited `
--tag """" `
--prune
定期実行化
スクリプトを作成します。内部で前述の環境変数設定スクリプトを呼び出しています。このスクリプトの隣に配置しておいてください。
$ErrorActionPreference = "Stop"
. $PSScriptRoot\restic_env.ps1
# ここに restic backup コマンドを書く
# ここに restic forget コマンド (--prune 指定) を書く
# トラブルシューティングが必要な場合、ログ ファイルにリダイレクトしておいてください
# 個人環境なので、ズボラな私はやっていません
PowerShell を新しく開いて動作確認します。バックアップに VSS を使う場合は管理者として PowerShell を実行してください。
powershell.exe -ExecutionPolicy RemoteSigned -File "C:\Path\to\backup.ps1"
タスク スケジューラを開き、タスク スケジューラ ライブラリを選択し、右ペインのタスクの作成... をクリックします。
- 全般
- 名前: restic backup
- タスクの実行時に使うユーザー アカウント:
$env:USERPROFILEが適切に設定されるアカウント-
SYSTEMだと自分のアカウントの$env:USERPROFILEにならないので注意
-
- ユーザーがログオンしているかどうかにかかわらず実行する
- 最上位の特権で実行する (VSS のために必要)
- トリガー
- タスクの開始: スケジュールに従う
- 設定: 毎日
- 有効
- 操作
- 操作: プログラムの開始
- プログラム/スクリプト: powershell.exe
- 引数の追加: -ExecutionPolicy RemoteSigned -File "C:\Path\to\restic_backup.ps1"
作成したら、イベント ビューアーや履歴にログが残るように、右ペインの「すべてのタスク履歴を有効にする」をクリックしておいてください。(有効化済みだと「すべてのタスク履歴を無効にする」という表示になっています。)
準備ができたら、動作確認します。
- restic backup タスクを右クリックして「実行する」
- 履歴タブを開く
- タスクのカテゴリ「Action completed」が出るまで、右ペインの「最新の情報に更新」をクリック
- 「Action completed」のログを選択して、リターン コード: 0 であることを確認
リターン コード: 0 でない場合は、スクリプトでログを残すように修正して、トラブルシューティングしてください。
リストアー
下記コマンドで最新スナップショットを C:\restore にリストアーできます。Windows のシンボリック リンクや security descriptors を復元するために管理者で実行したほうが良さそうです。
restic restore `
-r s3:endpoint/bucket_name/restic-repo `
--sparse `
--target C:\restore `
latest
--sparse は sparse files を sparse files のままリストアーするためのオプションです。
特殊なファイルやディレクトリーの扱いの制限事項
冒頭に書いた通り、Windows のハード リンクや、開発者モード無効時に作成した WSL や cygwin のシンボリック リンクの扱いに課題があります。
私のよく使う範囲で、嫌がらせのようなファイルを作成してバックアップとリストアーを試してみました。
対象は以下のファイルです。
$ ls -l src
total 0
drwxrwxrwx 1 hanotch hanotch 4096 Jan 6 08:31 testdir
lrwxrwxrwx 1 hanotch hanotch 7 Jan 6 09:30 testdir_cygwin_symlink -> testdir
lrwxrwxrwx 1 hanotch hanotch 42 Jan 6 08:31 testdir_junction -> /mnt/c/Users/hanotch/restic_test/src/testdir
lrwxrwxrwx 1 hanotch hanotch 7 Jan 6 08:32 testdir_symlink -> testdir
lrwxrwxrwx 1 hanotch hanotch 7 Jan 6 08:41 testdir_wsl_symlink -> testdir
-rwxrwxrwx 2 hanotch hanotch 0 Jan 6 08:31 testfile
lrwxrwxrwx 1 hanotch hanotch 8 Jan 6 09:30 testfile_cygwin_symlink -> testfile
-rwxrwxrwx 2 hanotch hanotch 0 Jan 6 08:31 testfile_hardlink
lrwxrwxrwx 1 hanotch hanotch 8 Jan 6 08:32 testfile_symlink -> testfile
lrwxrwxrwx 1 hanotch hanotch 8 Jan 6 08:41 testfile_wsl_symlink -> testfile
cygwin symlinks は Git Bash で作成しました。Windows ネイティブのシンボリック リンクの作成を阻害するため、WSL、Git Bash 操作中は開発者モードを切り、通常権限で操作します。
$ export MSYS=winsymlinks:native
$ ln -s testfile testfile_cygwin_symlink
$ ln -s testdir testdir_cygwin_symlink
管理者権限でバックアップしてみます。
restic backup -r restic-repo src
repository a0ffe26b opened (version 2, compression level auto)
no parent snapshot found, will read all files
[0:00] 0 index files loaded
error: src\testdir_cygwin_symlink: unsupported file type "irregular"
error: openfile for readdirnames failed: open \\?\C:\Users\hanotch\restic_test\src\testdir_wsl_symlink: The file cannot be accessed by the system.
error: src\testfile_cygwin_symlink: unsupported file type "irregular"
error: src\testfile_wsl_symlink: unsupported file type "irregular"
Files: 2 new, 0 changed, 0 unmodified
Dirs: 2 new, 0 changed, 0 unmodified
Added to the repository: 3.634 KiB (1.318 KiB stored)
processed 2 files, 0 B in 0:00
snapshot ab937440 saved
Warning: at least one source file could not be read
WSL、cygwin で作成したシンボリック リンクが読み取れずエラーになってしまいました。
管理者権限でのリストアーはエラーなく終了しました。
どのように復元されたか確認してみます。
$ ls -l restore/src
total 0
drwxrwxrwx 1 hanotch hanotch 4096 Jan 6 08:31 testdir
lrwxrwxrwx 1 hanotch hanotch 42 Jan 6 08:31 testdir_junction -> /mnt/c/Users/hanotch/restic_test/src/testdir
lrwxrwxrwx 1 hanotch hanotch 7 Jan 6 08:32 testdir_symlink -> testdir
-rwxrwxrwx 1 hanotch hanotch 0 Jan 6 08:31 testfile
-rwxrwxrwx 1 hanotch hanotch 0 Jan 6 08:31 testfile_hardlink
lrwxrwxrwx 1 hanotch hanotch 8 Jan 6 08:32 testfile_symlink -> testfile
ハード リンクは普通のファイルとして復元されてしまいました。ハード リンクはPython 環境構築ソフトの uv などが利用しています。リストアーすると環境が少し変わってしまうこと、バックアップ元よりもリストアー先のほうがサイズが大きくなることに注意が必要です。
商用製品だとどうなのか気になって $env:USERPROFILE のバックアップを Acronis True Image で VSS (ライターあり) で取ってみたところ、以下のような状態でした。
-
$env:LOCALAPPDATA\Microsoft\WindowsAppsは restic 同様、バックアップされていない - ハード リンクやシンボリック リンクは正常に復元できる
感想
良いところ
- Windows 標準のファイル履歴よりも高速
- クラウドへのバックアップが想定された設計
- 紹介しませんでしたが、rclone の任意のリモートを使えます
- VSS を使ってシステムのスナップショットをバックアップできる
- 今のところ、btrfs や zfs ではできない
悪いところ
- Windows のハード リンクが普通のファイルとしてバックアップされてしまう
- 開発者モード無効時に作成した WSL や cygwin のシンボリック リンクをバックアップできない
その他
今回は Windows のバックアップに利用しましたが、.gitignore 対象がコーディング エージェントなどに破壊される場合に備えてローカルで使うのも面白そうです。