resticでDockerバックアップを暗号化して外付けSSDへ保存する【Ubuntu Server 26.04】

Ubuntu Server上のDockerバックアップをresticで暗号化し外付けSSDへ保存する流れ はじめての自宅サーバー

前回は、Docker Composeのnamed volumeを停止中に.tgzへ保存し、SHA-256と復元テストまで行いました。しかし保存先が同じサーバー内なら、内蔵ディスクの故障や誤操作で元データとバックアップを同時に失う可能性があります。

今回はUbuntu Server 26.04 LTSでresticを使い、前回作った.tgz.sha256を暗号化して外付けSSDへ保存します。保存後はスナップショット確認、リポジトリの完全読取検査、別ディレクトリへの復元、チェックサム検証、安全な取り外しまで行います。

前提は、前回のDocker Composeのnamed volumeをバックアップ・復元する手順を完了し、~/docker/nginx-lan/backups.tgzと対応する.sha256があることです。

この記事では、外付けSSDのパーティション作成・フォーマット・マウント設定は行いません。

すでに/mnt/backup-driveへマウント済みで、書き込み可能な専用媒体を使います。媒体の識別に自信がない場合は、書き込みを始めず管理者へ確認してください。

この記事のゴール

  • 外付けSSDが想定した媒体だと照合する
  • resticの復号パスワードを権限制限し、別経路にも保管する
  • 暗号化リポジトリを外付けSSDへ作成する
  • Dockerバックアップ一式をスナップショットとして保存する
  • restic check --read-dataで全データを読み取って検査する
  • 別ディレクトリへ復元し、すべてのSHA-256を確認する
  • 保持ルールを削除なしのdry-runで確認する
  • 外付けSSDを安全にアンマウントする

「サーバー外」「オフライン」「遠隔地」は別の強さ

外付けSSDへのコピーは、元の内蔵ディスクとは別媒体になります。ただし接続したままなら、誤操作やマルウェアの影響を同時に受ける可能性があります。検証後に取り外せばオフラインになりますが、同じ家に置く限り火災・盗難・水害に対する遠隔地保管にはなりません。

3-2-1は「データを3つ、2種類の媒体、1つは別拠点」という有用な目安です。この記事で完成するのは別媒体と、取り外した場合のオフライン保管までです。遠隔地コピーは別の設計として追加します。

1. 外付けSSDを正確に識別する

findmntとlsblkで外付けSSDのマウント先、接続方式、容量を照合する手順
書き込み前にマウントポイントだけでなく、接続方式・容量・型番まで照合します。想定と違う媒体なら作業を止めます。

最も危険なのは、別のディスクやルートファイルシステムへ誤って書き込むことです。findmnt -Tだけでは、対象が未マウントでも親の/が表示される場合があります。ここでは--mountpointで、その場所自体がマウントポイントか確認します。

MOUNT_POINT='/mnt/backup-drive'

findmnt --mountpoint / --output SOURCE,TARGET,FSTYPE,OPTIONS
findmnt --mountpoint "$MOUNT_POINT" --output SOURCE,TARGET,FSTYPE,OPTIONS
lsblk --output NAME,PATH,TYPE,TRAN,SIZE,MODEL,FSTYPE,MOUNTPOINTS
df -h -- "$MOUNT_POINT"
test -w "$MOUNT_POINT"

2つのSOURCEが同じなら、外付けSSDではなくルート側へ書こうとしている可能性があります。TRAN、容量、型番、ファイルシステム、マウント先が予定と一致し、書き込み可能な場合だけ進みます。

2. resticをインストールする

sudo apt update
sudo apt install restic
restic version

Ubuntuのパッケージから導入します。バージョンが表示されなければ先へ進みません。

3. 復号パスワードを安全に作る

resticリポジトリと復号パスワードを別の経路で保管する考え方
暗号化したリポジトリと復号パスワードを同じ媒体だけに置くと、媒体紛失時に両方を失います。復旧用パスワードは別経路で保管します。

resticリポジトリは暗号化されます。パスワードを失うと復号できないため、長くランダムな値を使い、サーバーとは別の信頼できるパスワード管理手段にも保存します。チャット、Issue、シェル履歴へ値を書かないでください。

(
  set -eu
  install -d -m 700 "$HOME/.config/restic"
  PASSWORD_FILE="$HOME/.config/restic/ouchi-lab-password"
  test ! -e "$PASSWORD_FILE" || {
    echo "STOP: パスワードファイルは既に存在します"
    exit 1
  }
  install -m 600 /dev/null "$PASSWORD_FILE"
  nano "$PASSWORD_FILE"
  test -s "$PASSWORD_FILE"
  stat -c '%a %U %G %n' "$PASSWORD_FILE"
)

期待する権限は600です。復旧用コピーは紙や別のパスワードマネージャーなど、外付けSSDとは別経路へ保管します。パスワードファイル自体を同じSSDだけにコピーしても、SSD紛失時の復旧にはなりません。

4. 暗号化リポジトリを初期化する

MOUNT_POINT='/mnt/backup-drive'
export RESTIC_REPOSITORY="$MOUNT_POINT/restic/ouchi-lab"
export RESTIC_PASSWORD_FILE="$HOME/.config/restic/ouchi-lab-password"

findmnt --mountpoint "$MOUNT_POINT" --output SOURCE,TARGET,FSTYPE,OPTIONS
test -r "$RESTIC_PASSWORD_FILE"
test -w "$MOUNT_POINT"
mkdir -p "$(dirname "$RESTIC_REPOSITORY")"

if test -e "$RESTIC_REPOSITORY"; then
  echo "STOP: リポジトリ候補が既に存在します"
  exit 1
else
  restic init
fi

created restic repositoryと表示されたことを確認します。既存パスがある場合、内容を確認せず再初期化・削除しません。

5. Dockerバックアップを保存する

対象ディレクトリとファイルを先に確認します。

SOURCE_DIR="$HOME/docker/nginx-lan/backups"
test -d "$SOURCE_DIR"
find "$SOURCE_DIR" -maxdepth 1 -type f   ( -name '*.tgz' -o -name '*.sha256' )   -printf '%f	%s bytes
'

(
  cd "$SOURCE_DIR"
  test -n "$(find . -maxdepth 1 -type f -name '*.sha256' -print -quit)"
  sha256sum -c -- *.sha256
)

すべてOKならresticへ保存します。

restic backup --tag ouchi-lab-nginx "$SOURCE_DIR"
restic snapshots --tag ouchi-lab-nginx
restic ls latest

スナップショットID、ホスト名、パス、タグ、保存対象の.tgz.sha256を確認します。暗号化されても、対象を間違えたバックアップは正しくなりません。

6. リポジトリ全体を検査する

resticのスナップショット作成、完全検査、別ディレクトリへの復元、外付けSSDの取り外し
バックアップ後は一覧を見るだけで終えず、完全読取検査と別ディレクトリへの復元を行います。確認後に安全にアンマウントします。
restic check
restic check --read-data

通常のcheckは構造を検査します。--read-dataはリポジトリ内のデータをすべて読み取り、保存データの整合性まで確認するため時間がかかります。初回作成時と定期的な保守で実施し、エラーがあればSSDを取り外す前に記録します。

7. 別ディレクトリへ復元してSHA-256を確認する

元のbackupsへ上書きせず、所有ユーザーだけが使う一時ディレクトリへ復元します。

RESTORE_DIR="$(mktemp -d "$HOME/restic-restore-test.XXXXXX")"
chmod 700 "$RESTORE_DIR"
printf 'RESTORE_DIR=%s
' "$RESTORE_DIR"

restic restore latest --target "$RESTORE_DIR"

RESTORED_BACKUPS="$RESTORE_DIR$SOURCE_DIR"
test -d "$RESTORED_BACKUPS"
(
  cd "$RESTORED_BACKUPS"
  test -n "$(find . -maxdepth 1 -type f -name '*.sha256' -print -quit)"
  sha256sum -c -- *.sha256
)

すべてOKになれば、「暗号化して保存したデータを、パスワードで開き、別の場所へ復元し、元のチェックサムまで一致する」ことを確認できました。一時ディレクトリは確認が終わるまで残し、削除する場合も表示された具体的なパスを再確認します。

8. 世代保持ルールをdry-runする

例として日次7、週次4、月次6を保持する候補を確認します。今回は削除しません。

restic forget   --tag ouchi-lab-nginx   --group-by host,paths,tags   --keep-daily 7   --keep-weekly 4   --keep-monthly 6   --dry-run

保持・削除候補が意図どおりか、複数回のバックアップを重ねてから判断します。この記事ではforgetの実行、--prune、自動削除を行いません。

9. 外付けSSDを安全に取り外す

バックアップ、検査、復元確認が成功し、SSDを使っているシェルやプロセスがないことを確認します。

MOUNT_POINT='/mnt/backup-drive'
cd "$HOME"
sync
sudo umount -- "$MOUNT_POINT"

if findmnt --mountpoint "$MOUNT_POINT" >/dev/null; then
  echo "STOP: まだマウントされています"
else
  echo "取り外し可能です"
fi

target is busyなら、強制・lazyアンマウントで回避せず、開いている端末やプロセスを確認します。アンマウント成功を確認してからケーブルを抜きます。

トラブルシューティング

wrong password or no key found

RESTIC_PASSWORD_FILEが正しいか、末尾の不要な空白がないか確認します。思いつきで上書きせず、別経路に保管した復旧用パスワードと照合します。

repository does not exist

printf '%s
' "$RESTIC_REPOSITORY"
findmnt --mountpoint /mnt/backup-drive
ls -ld /mnt/backup-drive/restic/ouchi-lab

外付けSSDが未マウントのまま、内蔵ディスク上の空ディレクトリを見ていないか確認します。

check –read-dataでエラーになる

出力を保存し、同じSSDへの新しい書き込みや削除を止めます。接続、ファイルシステム、媒体状態を確認し、正常な別バックアップから復旧できるかを優先します。

完了チェックリスト

  • マウント元、接続方式、容量、型番を照合した
  • resticパスワードファイルが600で、別経路にも復旧情報がある
  • 外付けSSD上へ暗号化リポジトリを初期化した
  • 元の.sha256がOKのバックアップだけを保存した
  • スナップショットと保存ファイルを確認した
  • checkcheck --read-dataが成功した
  • 別ディレクトリへ復元し、すべてのSHA-256が一致した
  • 保持ルールを--dry-runだけで確認した
  • アンマウント成功後にSSDを取り外した

まとめ

外付けSSDへファイルをコピーするだけでなく、媒体を正しく識別し、暗号化し、全データを検査し、別の場所へ復元して、取り外すところまでを一連のバックアップ運用にします。パスワードはリポジトリと別経路で守り、削除ルールは複数世代を確認してから導入します。

resticのリポジトリ作成とパスワード、整合性検査、復元、保持ルールは、リポジトリ準備リポジトリ検査復元スナップショット削除方針の公式文書で確認できます。マウントポイント判定はfindmntのマニュアルを確認しました。公式情報の確認日は2026年8月3日です。

次は、マウント確認、バックアップ、検査、結果通知をsystemd timerで自動化します。失敗時にはSSDを勝手に取り外さず、人が原因を確認できる設計にします。

コメント

タイトルとURLをコピーしました