プログラミング

自宅サーバーから暗号化HDDへ毎日自動バックアップする仕組みを作る

自宅サーバーのデータを、暗号化した外付けHDDへ毎日自動でバックアップする仕組みの中身です。LUKSと /etc/crypttab(nofail・keyfile-timeout)での自動解除、rsync --link-dest によるスナップショット(日次14世代+週次4世代)、データベース・ファイル・設定・復元手順書の4層構成、systemdタイマーでの毎日実行、異常時だけ通知する番犬スクリプトまでまとめました。

目次

はじめに

自宅サーバーにいろいろなデータを集めたのはいいけれど、「もしこのディスクが壊れたら、全部消えるのでは……」と不安になったことはありませんか。

私は、写真もファイルもメモも健康データも、自分のサーバーに集めてきました。
便利な反面、データを自分で持つということは、その安全も自分で守る責任を負うということです。
クラウドサービスなら業者が裏でバックアップしてくれていましたが、自宅サーバーではそうはいきません。

そこで、外付けのHDDを買ってきて、毎日自動でバックアップが取られる仕組みを作りました。
そのHDDは暗号化して、失敗したらスマホに通知が来るようにしてあります。
この記事では、その仕組みを中身まで紹介します。

前提として、Ubuntuを入れてCasaOSまで用意した自宅サーバーの土台があり、データは /DATA の下に置いてあるものとして進めます。
面倒な設定作業はサーバーに入れたClaude Codeに手伝ってもらう前提で、記事の後半には実際に渡した指示書も載せておきます。

なぜバックアップが要るのか(3-2-1の考え方)

理由はシンプルで、ディスクはいつか必ず壊れるからです。
パソコンやサーバーのディスクは消耗品で、何年も使えば、ある日突然読めなくなることがあります。
バックアップが無ければ、その瞬間に、ためてきた写真もファイルも全部失われます。

バックアップの世界には「3-2-1」という有名な目安があります。
データは3つ持つ(オリジナル+バックアップ2つ)/2種類の違う媒体に置く/そのうち1つは別の場所に、という考え方です。
家庭で完璧に守るのは大変ですが、少なくとも「元データとは別の物理ディスクに、もう1つコピーを持つ」だけでも、安心感はまるで違います。
今回作るのは、その「別ディスクにもう1つ」を、毎日自動で・暗号化して・失敗に気づける形で実現する仕組みです。
クラウドにさらにもう1つ置けば、より3-2-1に近づきます。

方針:暗号化した外付けHDDに、毎日自動で

私が決めた方針は、次の3つです。

  • 専用の外付けHDDにバックアップする:元データと同じディスクに取っても、そのディスクが壊れたら一緒に消えるので意味がありません。物理的に別のディスクに取ります。
  • HDDは暗号化する:バックアップHDDには写真も書類も丸ごと入ります。盗まれたり紛失したりしても中身を読まれないよう、ディスクごと暗号化します。
  • 毎日、自動で取る:手動だと結局やらなくなります。決まった時間に勝手に取られるようにします。

この3つを満たす仕組みを、Claude Codeと一緒に作っていきました。

ディスクの暗号化(LUKSと /etc/crypttab

Linuxには「LUKS(ルクス)」という、ディスクを丸ごと暗号化する標準の仕組みがあります。
これを使うと、バックアップ用のHDDは、正しい鍵が無いかぎり中身がまったく読めません。
HDDを抜き取って他のパソコンにつないでも、ただの意味不明なデータにしか見えません。

私の設定では、サーバーの起動時に、用意した鍵ファイルでこの暗号を自動的に解除して、バックアップ用のHDDが使える状態になるようにしています。
これには /etc/crypttab という設定ファイルを使います。
ここで2つ、運用のための工夫を入れています。

  • nofail:このHDDがつながっていなくても、サーバーの起動を妨げないようにする指定です。これが無いと、バックアップHDDを外しているときにサーバーが起動しなくなって慌てます。
  • 鍵ファイルのタイムアウト(keyfile-timeout):鍵での開錠を、一定の短い時間(私は15秒)だけ待つ指定です。HDDが見つからなければさっさと先に進むので、起動がいつまでも止まりません。

暗号化したHDDは、解除されると /mnt/backup のような場所で使えるようになり、ここをバックアップの保存先にします。

スナップショット方式:毎日の状態を丸ごと、でも省容量で

バックアップの取り方には工夫があります。
私が使っているのは「スナップショット」方式で、/mnt/backup/snapshots/daily/2026-06-06/ のように、日付ごとのフォルダにその日の状態を丸ごと残していきます。
私は日次のスナップショットを14世代(約2週間分)、さらに週次を4世代、保持しています。
週次は、日曜の日次を週次の側に昇格させて作っています。

「2週間分も丸ごと保存したら、ディスクがすぐいっぱいになるのでは?」と思いますよね。
ここで効いているのが、rsync というコピーの道具の --link-dest という機能です。
新しいスナップショットを作るとき、前回から変わっていないファイルは、実体をコピーせずにハードリンク(同じ実体を指す別名)でつなぎます。
つまり、変わったファイルだけが新しく実体としてコピーされ、変わっていないファイルは容量を消費しません。
見た目は毎日が丸ごと残っているのに、増える容量は「その日変わった分」だけ、という賢い仕組みです。

コピーには rsync -aHAX --numeric-ids のように、ファイルの権限・所有者・ハードリンクなどをそのまま保つオプションを付けています。
後で復元したときに、権限まわりが崩れて困らないようにするためです。

4つの層でバックアップする

ただファイルをコピーするだけでは不十分です。
私のバックアップは、4つの層に分けて、必要なものを漏れなく保存しています。

4つの層でバックアップする(層/保存するもの/やり方)

とくに大事なのが0層のデータベースです。
ImmichNextcloud、健康管理MCPなどは、データベースに情報を持っています。
データベースは、書き込みの途中で複数のファイルを少しずつ更新していることがあり、その最中にファイルを単純コピーすると、「半分だけ更新された矛盾した状態」をつかんでしまい、いざ戻したときに開けない、ということが起こります。
これを避けるため、アプリごとに「いま整合の取れた状態」を安全に書き出す、正しい方法を使います。

  • PostgreSQL系(Immich・Miniflux):専用の書き出しコマンド(pg_dumpall)で、まるごと安全に書き出します。
  • Nextcloud:一時的に「メンテナンスモード」にして書き込みを止めてから、データベースを取り出します。
  • SQLite系(健康管理MCPなど):壊れない形でコピーする専用の方法(.backup)を使います。

2層では /etc などのシステム設定、CasaOSやSambaの設定、各コンテナの構成ファイル、インストール済みアプリの一覧などを控えます。
3層では、「新しいサーバーに引っ越すとき、どういう順番で戻せばよいか」を書いた手順書を、バックアップのたびに自動で作って一緒に保存しています。
いざというときは慌てるので、この手順書があるだけで安心感がまったく違います。

毎日、自動で動かす(systemdタイマー)

このバックアップは、毎日決まった時間(私の場合は深夜3時)に自動で動きます。
Linuxには、決まった時刻に処理を実行する「systemdタイマー」という仕組みがあり、これを使っています。

ひとつ大事な設定が Persistent=true です。
これは、「実行予定の時刻にサーバーの電源が入っていなかった(取りこぼした)場合、次に起動したときに取り直す」という指定です。
これが無いと、たまたまその時刻に止まっていた日のバックアップが、まるごと抜けてしまいます。
「自動で、勝手に、取りこぼさず」を実現するための、地味だけれど効く設定です。

失敗を見張る「番犬」(watchdog)

自動化で怖いのは、いつのまにか失敗していて、それに気づかないことです。
バックアップを取っているつもりが、実は何週間も止まっていた、というのが最悪のパターンです。

そこで、バックアップがちゃんと取れているかを毎日見張る「番犬」のスクリプトも、別のタイマーで動かしています。
番犬は、次の3つをチェックします。

  • バックアップ用HDDがちゃんとマウントされているか(外れていないか)
  • 最新のバックアップが古すぎないか(私は30時間より古ければ異常と判断)
  • 前回の処理が、最後まで「完了」で終わっているか(途中で止まっていないか)

このどれかに引っかかったときだけ、スマホに通知(ntfyなどの通知サービス)が飛んでくるようにしてあります。
正常なときは何も言ってこないので、通知が来たら「何かあったな」とすぐ分かります。
順調なときは静かに、異常時だけ知らせる、という形です。

Claude Codeへの指示書

ここまでの仕組みを作ってもらうための、指示書の例です。
本格的なので、段階を分けて進めるのがおすすめです。

あなたはこのUbuntuサーバーの構築を手伝うエンジニアです。
私は非エンジニアなので、専門用語は噛み砕いて、操作の前には何をするか一言説明してください。

目的:外付けHDDに、サーバーのデータを毎日自動でバックアップする仕組みを作りたい。
HDDは暗号化し、失敗したらスマホに通知がほしい。

進め方:
1. 接続した外付けHDDをLUKSで暗号化して使えるようにし、起動時に鍵ファイルで自動解除したい。
   crypttab で nofail と keyfile-timeout を付けて、HDD未接続でも起動を妨げないようにすること。
2. バックアップのスクリプトを作る。0層=各アプリのデータベースを正しい方法でダンプ
   (PostgreSQLはpg_dumpall、Nextcloudはメンテモード、SQLiteは.backup)、
   1層=/DATA をrsync、2層=/etc や各種設定、3層=復元手順書の自動生成、の4層構成にしたい。
   日次スナップショットは rsync --link-dest(変更分だけ実体コピー)で14世代、週次4世代残したい。
3. これを systemd タイマーで毎日深夜に自動実行(Persistent=true で取りこぼしも拾う)。
4. バックアップが未マウント・古すぎ・未完了でないかを毎日チェックし、異常時だけ通知する番犬も作る。
各段階で、何をしたか・どう確認すればいいかを説明してください。

「暗号化」「4層」「変更分だけ(--link-dest)」「異常時だけ通知」という方針を伝えておくのがコツです。

たまに「本当に戻せるか」を試す

最後にひとつ、運用上の大事な点です。
バックアップは、取っているだけでは半分です。
本当に戻せるかを、ときどき試しておくことが大切です。
「バックアップはあるのに戻し方が分からない」「ファイルが壊れていた」では意味がありません。

私は、ときどきバックアップから適当なファイルを取り出して、ちゃんと開けるかを確認しています。
0層のデータベースのダンプも、たまに別の場所で読み込めるかを試します。
さきほどの自動生成の「復元手順書」も読み返して、構成が変わって内容が古くなっていないかを見ています。
取れていることと、戻せることは別なので、ここは定期的に確認しておくと安心です。

よくあるトラブルと対処

つまずきやすい点をQ&Aでまとめておきます。

Q. バックアップがちゃんと動いているか不安
番犬が「異常時だけ通知」なので、通知が来ていなければ順調、と考えて大丈夫です。
気になるときは「最後のバックアップはいつ成功した?」とClaude Codeに聞けば、状況を確認してくれます。

Q. 暗号化の鍵やパスワードを忘れたらどうなる?
暗号化したHDDは、鍵が無いと中身を読めません。
これは安全の裏返しでもあるので、鍵やパスワードは絶対に失くさないよう、別の安全な場所にも控えておきましょう。
ここを失うと、自分でも復元できなくなります。

Q. バックアップでサーバーが重くならない?
深夜の使っていない時間に動かしているので、ふだんの使用で重さを感じることはありません。
気になる場合は、実行時間帯をClaude Codeに相談して調整してもらうとよいです。

Q. バックアップHDDを一時的に外したら、サーバーが起動しなくなった
/etc/crypttabnofail が付いていないと起きます。
本文の設定(nofailkeyfile-timeout)を入れておけば、HDDが無くても普通に起動します。

まとめ

いかがでしたか。
今回は、暗号化した外付けHDDへ、毎日自動でバックアップする仕組みを紹介しました。

振り返ると、

  1. LUKSでHDDを暗号化し、/etc/crypttabnofailkeyfile-timeout)で起動時に自動解除する
  2. rsync --link-dest のスナップショットで、毎日の状態を省容量で14世代+週次4世代残す
  3. データベース(pg_dumpall・メンテナンスモード・.backup)・ファイル・設定・復元手順書の4層で保存する
  4. systemdタイマー(Persistent=true)で、取りこぼさず毎日自動実行する
  5. 番犬が未マウント・古すぎ・未完了を見張り、異常時だけスマホに通知する
  6. ときどき「本当に戻せるか」を試しておく

という内容でした。

バックアップは地味で、うまくいっているときは存在を忘れるくらいのものですが、自宅サーバーを安心して使い続けるためのいちばんの土台だと思います。
ここまで作っておけば、大事なデータを自分のサーバーに預けるのも怖くなくなります。

この記事が誰かの役に立てばうれしいです。