Ubuntu Weekly Recipe

第927回「Backrest」でResticのバックアップをWebから管理する

第765回と第766回では、多機能で使いやすいバックアップツールとしてResticを紹介しました。今回はResticのWeb UI兼オーケストレーターであるBackrestを紹介します。

Resticとは

本連載で既に解説しているとおり、ResticはGo言語で実装されたオープンソースのバックアップツールです。バックアップ先にはローカルのディレクトリをはじめ、SFTPサーバー、Amazon S3やS3互換のオブジェクトストレージなどにも対応しています。Rcloneを介せば、Rcloneがサポートしているさらに多くのストレージサービスへもバックアップできます。

Resticではバックアップの保存先を「リポジトリ」と呼び、リポジトリはパスワード(キーとも呼ばれます)で保護されています。Resticはファイルを複数のチャンクに分割し、すでにリポジトリに存在するチャンクを重複して保存しません。この仕組みにより、2回目以降のバックアップでは新規または変更されたデータを転送・保存するため、効率のよいバックアップを実現できます。

バックアップを実行するたびに、その時点におけるディレクトリ構造とファイルを表すスナップショットが作成されます。実際のファイルデータは重複が排除され、複数のスナップショット間で共有されていますが、各スナップショットから任意の時点の完全なディレクトリ構造を参照できるようになっています。そのため利用者は、フルバックアップか増分バックアップかといった違いを意識することなく、任意の時点のファイルを復元できるのです。

Backrestとは

Resticはコマンドラインから扱うツールなので、定期的なバックアップを行うにはsystemd.timerなどを別途設定する必要があります。また、過去のバックアップから目的のファイルを探すには、スナップショットの一覧や内容をコマンドで確認しなければなりません。そこで登場するのがBackrestです。

Backrestは、ResticにWeb UIとスケジューラーを追加するソフトウェアです。Backrestを使うと、バックアップ先と対象ディレクトリの設定、実行スケジュール、保存する世代数などをWebブラウザーから設定できます。作成済みのスナップショットを閲覧し、必要なファイルを選んで復元もできます。

BackrestはあくまでResticにかぶせる「ガワ」であり、内部ではResticを呼び出して処理を行っています。そのためBackrestの利用をやめた場合でも、リポジトリの場所とパスワードさえわかれば、resticコマンドを直接実行して内容の確認や復元が可能です。

Backrestでは、主に次の操作をWebブラウザーから行えます。

  • Resticリポジトリの作成と、既存リポジトリの登録
  • バックアップ対象と実行スケジュールの設定
  • 保存するスナップショットの世代数の設定
  • バックアップの手動実行と実行結果の確認
  • スナップショットに含まれるファイルの閲覧と復元
  • バックアップ前後に任意のコマンドを実行するフック

Resticはスクリプトへ組み込みやすい優れたコマンドラインツールです。しかし異常がないかを確認したり、古いスナップショットからファイルを探したりする用途では、グラフィカルなUIがあると便利です。最近ではサーバーの管理機能をWebへ集約することも一般的ですから、Resticを運用しているのであれば、Backrestの導入は検討する価値があるでしょう。

Backrestからは、バックアップの削除や復元も実行できます。そのためLAN内だけに閉じて運用するか、VPNや認証機能を備えたリバースプロキシーを介してアクセスするなど、セキュリティには十分配慮してください。

リポジトリサーバーの用意

本記事ではバックアップ取得の対象となり、Backrestを動かすサーバー(server1と表記します)と、バックアップを保存するリポジトリサーバー(backrest-repoと表記します)の2台のサーバーを使って解説します。またバックアップの転送には、シンプルにSFTPを使用した例を紹介します。

まずはバックアップの保存先となる、backrest-repoサーバーを準備します。サーバー版のUbuntuをインストールしたPC(あるいは仮想マシン)を1台用意してください。サーバーにログインしたら、以下のコマンドでRestic専用のユーザーを作成します。コマンドの指示に従い、ユーザーのパスワードなどを対話形式で設定してください。

$ sudo adduser restic

続いて、リポジトリの保存先を作成します。所有者を先ほど作成した「restic」ユーザーにし、第三者に読まれないようなパーミッションを指定してください。なおinstallコマンドを使っていますが、mkdirした後にchown/chmodしても構いません。

$ sudo install -d -o restic -g restic -m 0750 /srv/restic
$ sudo install -d -o restic -g restic -m 0750 /srv/restic/server1

「/srv/restic」が、Resticのリポジトリ置き場のルートになります。その中に「server1」というサブディレクトリを作り、今回バックアップを取るサーバー用のリポジトリを置くこととしました。もし別のサーバーもバックアップする場合は、別途「/srv/restic/server2」のように、異なる保存先を作ると管理しやすくなります[1]。

Backrestのインストール

続いてBackrest本体をインストールしましょう。こちらはバックアップの対象となる、server1上で作業します。

Backrestは、サーバー上に実行バイナリを直接インストールすることでも動かせます。ですが今回は(今回も)環境の構築やクリーンアップが容易なDocker Composeを使用します[2]。例によって、以下のコマンドでDockerとDocker Composeプラグインをインストールしておいてください。

$ sudo apt install -U -y docker.io docker-compose-v2

ホームディレクトリの下に、Backrest用のディレクトリを作成します。なおDockerコンテナはroot権限で動作するため、こちらは普段使いのホームディレクトリ下に用意して構いません。

$ mkdir -p ~/backrest/{data,config,cache,tmp,ssh,restore}
$ chmod 700 ~/backrest/ssh
$ cd ~/backrest

それぞれのディレクトリの役割は以下のとおりです。

ディレクトリ 保存されるデータ
data Backrestの内部データや処理履歴
config リポジトリやプラン、Web UIの認証情報を含む設定
cache Resticが使用するキャッシュ
tmp 一時ファイル
ssh SFTP接続に使用するSSH鍵と設定
restore リストアしたファイルをホストに取り出すための出力先

次の内容でcompose.yamlを作成してください。

services:
  backrest:
    image: ghcr.io/garethgeorge/backrest:v1.14.1
    container_name: backrest
    hostname: server1
    restart: unless-stopped
    ports:
      - "9898:9898"
    volumes:
      - ./data:/data
      - ./config:/config
      - ./cache:/cache
      - ./tmp:/tmp
      - ./ssh:/root/.ssh:ro
      - ./restore:/restore
      - /srv/data:/userdata:ro
    environment:
      - BACKREST_DATA=/data
      - BACKREST_CONFIG=/config/config.json
      - XDG_CACHE_HOME=/cache
      - TMPDIR=/tmp
      - TZ=Asia/Tokyo

「/srv/data」は、今回バックアップするホスト上のディレクトリです。後述するバックアップのテストがわかりやすいよう、なにか適当なファイルを置いておいてください。既に運用しているサーバー上で実行するのであれば、実際にバックアップしたいディレクトリを指定してください。Backrestがこのホスト上のデータをバックアップできるよう、このディレクトリをコンテナ内に「/userdata」としてマウントします。またバックアップ元のデータを書き換える必要はないため、読み込み専用としてマウントしています。これにより、万が一BackrestやResticの操作を誤った場合にも、バックアップ元に与える影響を抑えられます。一方、リストア先となる「/restore」は書き込み可能でなければなりません。

「config」にはBackrestの設定が、「⁠data」には内部データや処理履歴が保存されます。この2つはコンテナを作り直しても保持されるよう、必ず永続化してください。「⁠cache」はresticのキャッシュであり、永続化しなくても動作しますが、再作成に時間がかかる場合があります。「⁠tmp」は処理中の一時ファイルなので、永続化しなくても構いません。また「config/config.json」というファイルには、リポジトリへアクセスするための情報が含まれるため、第三者に読まれないよう注意してください。

「ssh」はリポジトリサーバーへSFTPでアクセスするための、SSH鍵と設定を含むディレクトリです。こちらも書き込みを行う必要はないため、読み込み専用でマウントしています。なおこのディレクトリは秘密鍵を含むため、セキュリティには十分気をつけてください。

SSH鍵の作成と登録

Backrest専用のSSH鍵を、先ほど作成した「ssh」ディレクトリ内に作成します。なお自動バックアップでは対話的にパスフレーズを入力できないため、今回は「-N ''」オプションを指定し、パスフレーズを設定せず鍵を作成します。

$ cd ~/backrest
$ ssh-keygen -t ed25519 -f ./ssh/id_ed25519 -N '' -C 'backrest@server1'

秘密鍵の「id_ed25519」と、公開鍵の「id_ed25519.pub」という2つのファイルが作成されます。このうち公開鍵をリポジトリサーバーの「restic」ユーザーへ登録しましょう。以下のように、「⁠ssh-copy-id」コマンドを実行してください[3]。

SSH接続が行われますので、先ほど設定した「restic」ユーザーのパスワードを入力してください。これで公開鍵の登録は完了です。

$ ssh-copy-id -i ./ssh/id_ed25519.pub restic@backrest-repoサーバーのIPアドレス
(...略...)
restic@backrest-repoサーバーのIPアドレス's password:         ← resticユーザーのパスワードを入力

Number of key(s) added: 1

Now try logging into the machine, with: "ssh -i ./ssh/id_ed25519 'restic@backrest-repoサーバーのIPアドレス'"
and check to make sure that only the key(s) you wanted were added.

続いて、Backrestが使用するSSHの設定ファイルを作成します。以下のコマンドでSSHクライアントの設定ファイルを作成してください。

$ cat <<EOF > ./ssh/config
Host backrest-repo
    HostName backrest-repoサーバーのIPアドレス
    User restic
    IdentityFile /root/.ssh/id_ed25519
    IdentitiesOnly yes
    Port 22
    UpdateHostKeys no
    StrictHostKeyChecking yes
EOF

「backrest-repo」は、この接続設定に付けた名前です。「⁠IdentityFile」には秘密鍵ファイルを指定しますが、ホスト上のパスではなく、起動したBackrestコンテナ内で秘密鍵が見える「/root/.ssh/id_ed25519」を指定していることに注意してください。さらに、backrest-repoサーバーのホスト鍵を「known_hosts」へ登録します。

$ ssh-keyscan -t ed25519 -H backrest-repoサーバーのIPアドレス > ./ssh/known_hosts

Backrestの標準Dockerイメージでは、SSHクライアントはコンテナ内のrootユーザーとして実行されます。bind mountではホスト側のUIDとGIDが維持されるため、一般ユーザーが作成したSSH設定をそのままマウントすると、OpenSSHから所有者が不正だと判断されます。このためSSHの設定が完了したら、以下のコマンドでsshディレクトリのパーミッションを設定した上で、所有者をrootに変更します。

$ chmod 600 ./ssh/*
$ sudo chown root:root -R ./ssh

Backrestの起動

以下のコマンドでBackrestを起動します。

$ cd ~/backrest
$ sudo docker compose up -d

起動が完了したら、コンテナの状態を確認しておきましょう。

$ sudo docker compose ps
NAME       IMAGE                                   COMMAND                  SERVICE    CREATED         STATUS         PORTS
backrest   ghcr.io/garethgeorge/backrest:v1.14.1   "/sbin/tini -- /dock…"   backrest   6 seconds ago   Up 5 seconds   0.0.0.0:9898->9898/tcp, [::]:9898->9898/tcp

またコンテナ内からbackrest-repoサーバーへSSH接続ができるかも、念のため確認しておきましょう。以下のコマンドを実行し、backrest-repoサーバーのホスト名が表示されれば成功です。

$ sudo docker exec backrest ssh -o BatchMode=yes backrest-repo hostname
backrest-repo

Webブラウザーで「http://server1のIPアドレス:9898/」を開きます。最初のアクセスでは、BackrestのインスタンスIDを設定します。インスタンスIDはスナップショットの作成元を識別するために使われます。今回は「server1」としました。ほかのBackrestと重複しない名前を指定してください。

なお今回は解説の都合上、認証を無効にし、ユーザーの作成を省略しています。このままでは誰もがバックアップにアクセスできてしまうため、本格的に運用する場合は「認証を無効にする」をOFFにし、ユーザーを追加してください。

図1 インスタンスIDを設定する

リポジトリの登録

初期設定が終わったら、リポジトリを登録します。左ペインにある「リポジトリを追加」をクリックしてください。次の画面が表示されますので、必要な設定を入力します。

「リポジトリ名」はBackrestのUI上で、リポジトリを識別するためのIDです。全体で一意である必要があり、今回は「backrest-repo」としました。

「リポジトリのURI」には、接続に使うスキーマ、backrest-repoサーバーに接続するためのユーザー名やアドレス、サーバー上のパスを指定します。SFTPを使用するため、スキーマは「sftp:」となります[4]。続いて「ユーザー名@サーバーのアドレス:リポジトリのパス」を入力します。今回はbackrest-repo上にresticユーザーを作成しており、かつ「ssh/config」ファイル内でこのユーザー名を指定しているため、ユーザー名は省略できます。また接続に使うアドレスには、「⁠ssh/config」ファイル内の「Host」で指定した名前(今回はbackrest-repo)が使えます。リポジトリ用に作成したディレクトリは「/srv/restic/server1」でしたから、結果としてここに入力するURIは「sftp:backrest-repo:/srv/restic/server1」となります。

図2 追加するリポジトリの識別名と、リポジトリのURIを入力する

「パスワード」には、Resticリポジトリを暗号化するための十分に長いパスワードを入力します。「⁠生成」ボタンをクリックして、ランダムな文字列を生成してしまうとよいでしょう。

図3 リポジトリのパスワードを生成する

それ以外はデフォルトのままでよいでしょう。「⁠この設定でテスト」をクリックしてください。ここまでの設定が正しければサーバーにSFTP接続が行われ、以下のようにメッセージが表示されます。もしもエラーが表示された場合は、ここまでの手順(特にssh/configや公開鍵まわり)を確認してみてください。

図4 接続テストに成功した

「決定」をクリックすると、リポジトリが追加されます。

図5 追加されたリポジトリ

なおここで入力したリポジトリのパスワードを失うと、バックアップからの復元ができなくなります。Backrestの設定ファイルだけに保存せず、パスワードマネージャーなど、バックアップ対象とは独立した安全な場所にも保存するよう注意してください。

バックアップする

Backrestでは、バックアップ対象のディレクトリ、バックアップ先のリポジトリ、スケジュール、保持ポリシーなどをまとめた設定を「プラン」と呼びます。1つのリポジトリに対して、対象や実行間隔が異なる複数のプランも作成できます。実際にバックアッププランを作成してみましょう。左ペインから「プランを追加」をクリックします。

「プラン名」はBackrest上でこのプランを識別するための名前です。これも一意な名前を入力してください。なお後から変更はできません。「⁠リポジトリ」はプルダウンになっており、Backrestに登録されているリポジトリが選択できます。先ほど追加したリポジトリを選択してください。

図6 プラン名を入力し、バックアップ先のリポジトリを選択した

「バックアップのスコープ」にはバックアップの対象と、除外する項目を設定します。バックアップ対象はホストの「/srv/data」ですが、Backrestのコンテナ内には「/userdata」としてマウントされていますので、これを入力してください[5]。なお「追加」をクリックすることで、複数のパスを指定できます。「⁠除外項目」には、バックアップ対象のパス以下にあるファイルやディレクトリのうち、除外したいものを指定します。例えば機密情報が含まれるディレクトリはバックアップしたくないといった時に利用できます。詳しくはResticのドキュメントを参照してください。

図7 /userdataをバックアップ対象とした上で、拡張子が.bakのファイルを除外した例

「バックアップスケジュール」には、このプランを自動実行するスケジュールを設定します。スケジュールはCron形式で設定できるほか、「⁠12時間おき」「⁠3日おき」といった指定もできます。

図8 Cron形式で、毎週日曜の午前4時を指定した例

バックアップを自動実行していると、いずれはリポジトリの容量を使い切ってしまいます。適度な間隔で古いスナップショットは削除していくとよいでしょう。「⁠保持ポリシー」では、スナップショットをどれくらい保持するかを設定できます。「⁠件数で指定」は文字どおり、直近から指定した個数のスナップショットを保持します。「⁠期間で指定」は、スナップショットが存在するX個の各時間枠について、それぞれ最新の1個を残すという挙動をします。デフォルトでは「毎時 24」「⁠毎日 7」「⁠毎週 4」となっています。これは、スナップショットが存在する直近24個の時間について各時間の最新1個、直近7個の日について各日の最新1個、直近4個の週について各週の最新1個を保持するという設定です。ただし、これらの条件はORで評価されるため、24+7+4個が必ず残るわけではありません。たとえば最新のスナップショットは、その時間、その日、その週における最新のスナップショットでもあるため、「⁠毎時」「⁠毎日」「⁠毎週」の条件を同時に満たします。このように複数の条件に該当するスナップショットは1個として数えられます。このUIによる設定はやや直感に反するため、Resticのドキュメントも合わせて参照してください。

なお保持ポリシーにもとづいて実行されるのは「restic forget」コマンドです。forgetを実行すると、保持対象から外れたスナップショットは削除されます。ただし、そのスナップショットからのみ参照されていたデータは、まだリポジトリ内に残ります。実際に空き容量を回収するには、別途pruneを実行する必要があります。Backrestでは、pruneの実行間隔をリポジトリ設定のPruneポリシーで指定できます。

図9 スナップショットを保持するポリシーを設定する

プランの設定を入力し終わったら「決定」をクリックします。左ペインにプランが登録されますので「今すぐバックアップを作成」をクリックしてみましょう。スケジュールを待たず、即座にバックアップを試せます。

図10 作成したプランを手動で実行する

バックアップ処理中は、読み取ったファイル数や転送量が表示されます。作業が終了すると、作成されたスナップショットがツリーに追加されます。

図11 作成されたスナップショット

backrest-repoサーバー上では、以下のようにファイルが作成されていることも確認できます。

$ sudo -u restic ls -l /srv/restic/server1
total 24
-r--------   1 restic restic  155 Sep  9 13:29 config
drwx------ 258 restic restic 4096 Sep  9 13:29 data
drwx------   2 restic restic 4096 Sep 10 11:01 index
drwx------   2 restic restic 4096 Sep  9 13:29 keys
drwx------   2 restic restic 4096 Sep 10 11:01 locks
drwx------   2 restic restic 4096 Sep 10 11:01 snapshots

当然ですが、このディレクトリにあるファイルを個別に編集したり削除してはいけません。スナップショットの削除やリポジトリの保守作業は、BackrestやResticを介して行いましょう。

スナップショットからリストアする

リストアできないバックアップに価値はありません。スナップショットを取得したら、実際にリストアできることを確認しましょう。Backrestでは、リポジトリまたはプランの画面にスナップショットが時系列で表示されます[6]。

リストアしたいスナップショットを選択してから、右側にある「スナップショットブラウザ」をクリックしてください。そのスナップショットに含まれるディレクトリツリーが表示されます。

図12 スナップショットの内容を確認できる

スナップショット全体をリストアしたい場合は、ここからルートディレクトリに対してリストアを行います。ルートディレクトリの右側の、点が3つ並んだ「…」のアイコン[7]をクリックしてから、「⁠Restore to path」をクリックします。するとリストア先のディレクトリを指定するダイアログが開きます。

図13 スナップショットをリストアする

Backrestはコンテナ内で実行されているため、リストアしたディレクトリツリーもコンテナ内に展開されてしまいます。そこでリストアしたファイルをホストに取り出せるよう、あらかじめホストの「~/backrest/restore」ディレクトリを、コンテナ内の「/restore」としてマウントしていたというわけです。リストア先には「/restore/userdata-20260910」のように、「⁠/restore」以下の新しいディレクトリを指定しましょう。

図14 リストア先には、リストア用にマウントしたディレクトリを指定する

これでホスト上の「~/backrest/restore/userdata-20260910」以下に、スナップショットの内容がリストアされます。内容を確認した上で、rsyncコマンドなどで本来の場所へ戻すとよいでしょう。なおここではスナップショット全体をリストアしましたが、一部のファイルやディレクトリだけでも復元できます。


Backrestを使うと、Resticの堅牢なリポジトリ形式や多彩な保存先をそのまま利用しながら、バックアップのスケジュール、世代管理、リストアをWebブラウザーから操作できます。Resticを使いつつ、バックアップの成否や世代を手軽に管理したいという用途に適しています。またバックアップは目的ではなく手段です。Backrestを導入し、バックアップをスケジュールしただけで満足せず、データを確実に復旧できるようテストを忘れないでください。

おすすめ記事

記事・ニュース一覧