10 分で読了 #homelab
このページの目次

システムディスクのバックアップと復元

システムディスク(NVMe ext4)を毎日 rsync で ZFS ミラー(tank/backup/system)に同期し、スナップショットを取得して 30 世代保持します。本ドキュメントではバックアップメカニズム、日常点検、3段階の復元シナリオ(単一ファイル→データセットのロールバック→丸ごとベアメタル復元)をカバーし、末尾にバックアップ対象外の項目をリストします。スケジューリングについては timers-and-crons.md を参照してください。

概要

項目
ソース/(ext4,vg_sys/lv_root,898.5G)+ /boot(vfat,nvme0n1p1)
宛先/tank/backup/system(2×4T WD Red ZFS ミラー, lz4 圧縮)
方法rsync によるファイルレベル同期(初回はフルバックアップ、以降は増分)+ 完了ごとに zfs snapshot
バージョン管理最新のスナップショット 30 個を保持、それ以上は自動削除
スケジューリングsystemd timer、毎日 04:00 実行、Persistent=true + idle IO 優先度
スクリプト/usr/local/sbin/backup-system.sh

初回のフルバックアップは 2026-07-09 に実行され、ソースサイズは約 500G です。ブロックレベルのミラーリングを使わない理由: vg_sys の領域はすべて割り当て済みで LVM スナップショットの余裕がありません。ファイルレベルのバックアップであれば直接参照可能で単一ファイルの復元も可能であり、ZFS スナップショットがバージョン管理機能を補完しているため、ブロックレベルのソリューションに必要性はありません。

バックアップメカニズム

スクリプトは毎日以下の3つの処理を行います:

  1. rsync -aHAXx --delete --numeric-ids / → $DEST/root/ を実行し、その後 /boot/ → $DEST/boot/ を同期
  2. zfs snapshot tank/backup/system@<タイムスタンプ> を実行
  3. 作成時刻に基づいてクリーンアップを行い、最新のスナップショット 30 個のみを保持

主要なパラメータ:-x はファイルシステムをまたがない(自動で /proc、/sys、/tank などを回避し、マウントポイントは空ディレクトリとして保持);-HAX はハードリンク/ACL/xattr を保持し、復元時に完全なシステムとなります。終了コード 24(コピー中にファイルが消えた場合)は正常終了として扱います——オンラインバックアップでは必然的に発生します。

除外項目⁠(内容のみ除外、ディレクトリ自体は保持):

パス理由
/tmp/*/var/tmp/*一時ファイル、portage のコンパイルディレクトリを含む
/var/cache/distfiles/*/var/cache/binpkgs/*Gentoo のソースパッケージ/バイナリパッケージのキャッシュ、再ダウンロード・再コンパイル可能
/lost+foundext4 メタデータ

Docker データ(/var/lib/docker)⁠はバックアップ対象に含まれます⁠。

整合性⁠: rsync によるオンラインバックアップはクラッシュ一貫性レベルです。システムディスク上にはデータベースがありません(immich postgres は tank 上にあるため)、リスクは許容範囲です。将来システムディスク上でステートフルなサービスを実行する場合は、バックアップ前にダンプ手順を追加する必要があります。

日常点検

systemctl list-timers backup-system.timer      # 次のトリガー時刻
systemctl is-active backup-system              # activating=実行中、inactive=アイドル
journalctl -u backup-system -n 50              # 実行ログ
zfs list -t snapshot tank/backup/system        # スナップショット一覧(毎日1つずつ新規作成されるはず)
zfs list -o used,avail tank/backup/system      # スペース使用状況

長期的な課題⁠: 現在バックアップ失敗時のアラートはありません。サービスに OnFailure= フックを追加して Bark 通知( monitoring.md 参照)に接続することを検討してください。

既知の課題: UTF-8 以外のファイル名

tank プールは utf8only=on(プール作成時の属性、変更不可)であり、UTF-8 以外のファイル名は ZFS によって拒否され、rsync はエラー 23 を返します。⁠バックアップ全体が失敗し、スナップショットも作成されません⁠。初回のフルバックアップ(2026-07-09)でこの問題に遭遇しました: Wine 内でインストールされた Tencent ゲームの GBK エンコーディングのディレクトリ/ショートカット名で、mkdirInvalid or incomplete multibyte or wide character を報告しました。

調査と修正⁠(除外するのではなく UTF-8 に変換し、根本解決を図る):

# 全ディスクで UTF-8 以外のファイル名を検索(-x オプション必須、指定しないと空一致ですべて通過してしまう)
find / -xdev \( -path /proc -o -path /sys \) -prune -o -print 2>/dev/null | grep -avx '.*'

# 1つずつ名前を変換(GBK→UTF-8)、問題のあるディレクトリ内で実行:
for f in *; do n=$(printf '%s' "$f" | iconv -f GBK -t UTF-8 2>/dev/null) || continue; [ -n "$n" ] && [ "$n" != "$f" ] && mv -n "$f" "$n"; done

原因は GBK ロケールで Wine の中国語ゲームインストーラーを実行したことにあります。今後新しいゲームをインストールした後はスキャンを実行する価値があります。バックアップログ(journalctl -u backup-system)内の recv_generator: mkdir ... failed が問題のパスを直接指摘します。

シナリオ 1: 単一ファイルの誤削除/破損

スナップショットは隠しディレクトリとしてオンラインで読み取り可能であり、直接コピーして戻すことができます:

ls /tank/backup/system/.zfs/snapshot/                # すべてのタイムポイントを一覧表示
cp -a /tank/backup/system/.zfs/snapshot/20260709-0400/root/etc/foo.conf /etc/foo.conf

.zfsls -a では表示されませんが、直接 cd してアクセスできます。最新バックアップ(スナップショット未作成の現在の状態)は /tank/backup/system/root/ で直接読み取れます。

シナリオ 2: 壊れた状態がバックアップに同期されてしまった

誤削除やマルウェア感染後にバックアップが検出前に実行され、現在のバックアップツリーがすでに壊れている場合——ロールバックする必要はありません(更新されたスナップショットが破棄されるため)、より古いスナップショットディレクトリからシナリオ 1 の手順で直接コピーして戻すだけです。全体を元の状態に戻すことが確実になった場合にのみ:

zfs rollback -r tank/backup/system@<より古いスナップショット>   # -r はその後のすべてのスナップショットを破棄するため、注意して使用

シナリオ 3: 丸ごとベアメタル復元(システムディスクの破損/交換)

ZFS サポート付きの LiveUSB(SystemRescue で十分)が必要です。全体で約 1〜2 時間かかり、大半の時間は HDD からの 400G 以上のデータ読み込みに費やされます。

1. パーティションと LVM の再構築⁠(fstab ではデバイス名を使用し、VG/LV 名は vg_sys/lv_root のまま維持すればよく、UUID 依存はありません):

parted /dev/nvme0n1 -- mklabel gpt \
  mkpart ESP fat32 1MiB 1GiB set 1 esp on \
  mkpart lvm 1GiB 100%
mkfs.vfat -F32 /dev/nvme0n1p1
pvcreate /dev/nvme0n1p2
vgcreate vg_sys /dev/nvme0n1p2
lvcreate -L 32G -n lv_swap vg_sys && mkswap /dev/vg_sys/lv_swap
lvcreate -l 100%FREE -n lv_root vg_sys && mkfs.ext4 /dev/vg_sys/lv_root

2. プールのインポートと書き戻し⁠:

zpool import -o readonly=on tank        # 読み取り専用でインポートし、バックアップを保護
mount /dev/vg_sys/lv_root /mnt/root
rsync -aHAX /tank/backup/system/root/ /mnt/root/
mount /dev/nvme0n1p1 /mnt/root/boot
rsync -a /tank/backup/system/boot/ /mnt/root/boot/

3. chroot でのブートローダー再インストール⁠(GRUB EFI、/boot/EFI/Gentoo):

for d in dev proc sys; do mount --rbind /$d /mnt/root/$d; done
chroot /mnt/root /bin/bash
grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=Gentoo
grub-mkconfig -o /boot/grub/grub.cfg
exit

4. 後処理⁠:

umount -R /mnt/root
zpool export tank
reboot

再起動後に確認:systemctl --failed に異常がないこと、zpool import tank 後に zpool status が ONLINE であること、systemctl list-timers でバックアップタイマーが有効になっていることを確認します。

バックアップ対象外

内容現状
tank プールのデータ(photos/media/immich)ミラー冗長性のみ、2番目のコピー/遠隔地バックアップなし⁠、ディスク全壊または誤削除でデータ消失
除外項目(/tmp、portage キャッシュなど)再構築可能、復元後の初回 emerge で再ダウンロードされる
swap LVバックアップ不要、復元時に mkswap で再作成

長期的な課題⁠: photos などの再生不可能なデータは単一プールのミラーのみであるため、遠隔地バックアップ(restic → クラウドオブジェクトストレージ、または遠隔地マシンへの zfs send)を追加することを推奨します。

関連ドキュメント