WEELWORKS

resticprofile で、設定をファイルに移す

前回までで restic の基本操作は一巡しました。取って、戻して、検証して、整理する。ただ、実際に毎晩動かすことを考えると、コマンドラインがそろそろ手に負えません。

export RESTIC_REPOSITORY=/srv/backup/repo
export RESTIC_PASSWORD_FILE=/root/.config/restic/password
restic backup /srv/data --exclude='*.tmp' --exclude=/srv/data/cache --exclude-caches --tag daily
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune --path /srv/data --tag daily

第1回に書いたとおり、restic には設定ファイルがありません。この状態を放置すると、シェルスクリプトが育っていきます。今回は resticprofile を挟んで、これを設定ファイルへ移します。

インストール

公式のインストールスクリプトを使います。

curl -sfL https://raw.githubusercontent.com/creativeprojects/resticprofile/master/install.sh \
  | sudo sh -s -- -b /usr/local/bin v0.33.1

末尾の v0.33.1 がバージョン指定です。省略すると最新版が入ります。この連載ではバージョンを固定しています。

resticprofile version
resticprofile version 0.33.1 commit 49102a5f476be6dcc15a9f0ac092ef23fc528075

resticprofile も Go 製の単一バイナリで、restic 本体とは別物です。resticprofile は restic を呼び出すだけで、restic を置き換えません。

最初の設定ファイル

/etc/resticprofile/profiles.yaml を作ります。

version: 2

global:
  restic-binary: /usr/local/bin/restic

profiles:
  default:
    repository: "/srv/backup/repo"
    password-file: "/root/.config/restic/password"

    backup:
      source:
        - /srv/data
      exclude:
        - "*.tmp"
        - "/srv/data/cache"
      exclude-caches: true
      tag:
        - daily
      verbose: true

    retention:
      after-backup: true
      keep-daily: 7
      keep-weekly: 4
      keep-monthly: 6
      prune: true

構造を確認しておきます。

  • version: 2 — 設定フォーマットのバージョンです。
  • global: — 全 profile に共通の設定です。
  • profiles.default:default という名前の profile。--name で指定しないときに使われます。
  • backup: / retention: — restic の backup コマンドと forget コマンドに渡す内容です。

retention.after-backup: true が今回のポイントの1つです。バックアップが成功した直後に forget を走らせる、という指定です。前回、手で2回叩いていた処理が1回にまとまります。

YAML 以外に TOML・JSON・HCL でも書けます。拡張子で判別されるので、profiles.toml と置けば TOML として読まれます。

設定がどう解釈されたかを見る

書いた設定がそのとおり読まれているとは限りません。show で確認します。

cd /etc/resticprofile
resticprofile show
profile default:
    repository:              /srv/backup/repo
    password-file:           /root/.config/restic/password
    prometheus-push-format:  text

    backup:
        exclude-caches:  true
        host:            true
        tag:             daily
        verbose:         true
        source:          /srv/data
        exclude:         *.tmp
                         /srv/data/cache

    retention:
        host:          true
        keep-daily:    7
        keep-monthly:  6
        keep-weekly:   4
        path:          /srv/data
        prune:         true
        tag:           daily
        after-backup:  true

書いていない項目が増えています。retentionhost: truepath: /srv/datatag: daily が入りました。resticprofile が backup の内容から自動で埋めたものです。

これは地味に重要な安全装置です。第3回で見たとおり forget は取り消せません。もし対象を絞らずに forget --keep-daily 7 を実行すると、同じリポジトリに入っている他のホスト・他の用途のスナップショットまで削除対象になります。 resticprofile は「この profile が作ったスナップショットだけ」に範囲を限定してくれます。

ただし、自動で埋まるということは、意図と違う値が入る可能性もあるということです。次の --dry-run で必ず確認してください。

何が実行されるのかを確認する

resticprofile がやっているのは、設定から restic のコマンドラインを組み立てることです。組み立てた結果はそのまま見られます。

resticprofile --dry-run backup
2026/08/14 12:13:24 using configuration file: profiles.yaml
2026/08/14 12:13:24 profile 'default': starting 'backup'
2026/08/14 12:13:24 dry-run: /usr/local/bin/restic backup --exclude=*.tmp --exclude=/srv/data/cache --exclude-caches --host=backup-host --password-file=/root/.config/restic/password --repo=/srv/backup/repo --tag=daily --verbose /srv/data
2026/08/14 12:13:24 profile 'default': finished 'backup'
2026/08/14 12:13:24 profile 'default': cleaning up repository using retention information
2026/08/14 12:13:24 dry-run: /usr/local/bin/restic forget --host=backup-host --keep-daily=7 --keep-monthly=6 --keep-weekly=4 --password-file=/root/.config/restic/password --path=/srv/data --prune --repo=/srv/backup/repo --tag=daily

冒頭に並べたコマンドラインが、そのまま出てきました。

第1回で「resticprofile は restic を隠さない」と書いたのはこの点です。ラッパーを挟むと、たいてい中で何をしているのか分からなくなります。resticprofile はそこを開けたままにしてあるので、設定を変えたら --dry-run で差分を見るという運用ができます。restic 側のドキュメントもそのまま読めます。

実際に走らせるときは --dry-run を外すだけです。

resticprofile backup

バックアップの後に forget --prune が続けて実行されます。

対象が増えたときの書き方

対象が1つで済むことは、まずありません。ドキュメントと写真、アプリのデータとDB、というように増えていきます。設定をコピーして書き換えると、共通部分が二重管理になります。

resticprofile には inherit があります。

version: 2

global:
  restic-binary: /usr/local/bin/restic

groups:
  nightly:
    profiles:
      - docs
      - photos

profiles:
  # 共通の土台。これ自体は直接実行しない
  base:
    repository: "/srv/backup/repo"
    password-file: "/root/.config/restic/password"
    backup:
      exclude-caches: true
      verbose: true
    retention:
      after-backup: true
      keep-daily: 7
      keep-weekly: 4
      keep-monthly: 6
      prune: true

  docs:
    inherit: base
    backup:
      source: [/srv/data]
      tag: [docs]

  photos:
    inherit: base
    backup:
      source: [/srv/data2]
      tag: [photos]

base に共通部分をまとめ、docsphotos は差分だけを書きます。保持ポリシーを変えたいときに触るのは base の1か所です。

groups.nightly は、複数の profile をまとめて実行するための指定です。

resticprofile --dry-run --name nightly backup
2026/08/14 12:51:32 profile 'docs': starting 'backup'
2026/08/14 12:51:32 dry-run: /usr/local/bin/restic backup --exclude-caches --host=backup-host --password-file=... --repo=/srv/backup/repo --tag=docs --verbose /srv/data
2026/08/14 12:51:32 profile 'docs': finished 'backup'
2026/08/14 12:51:32 profile 'docs': cleaning up repository using retention information
2026/08/14 12:51:32 dry-run: /usr/local/bin/restic forget --host=backup-host --keep-daily=7 ... --path=/srv/data --prune --repo=/srv/backup/repo --tag=docs
2026/08/14 12:51:32 profile 'photos': starting 'backup'
2026/08/14 12:51:32 dry-run: /usr/local/bin/restic backup --exclude-caches --host=backup-host --password-file=... --repo=/srv/backup/repo --tag=photos --verbose /srv/data2
2026/08/14 12:51:32 profile 'photos': finished 'backup'
2026/08/14 12:51:32 profile 'photos': cleaning up repository using retention information
2026/08/14 12:51:32 dry-run: /usr/local/bin/restic forget --host=backup-host --keep-daily=7 ... --path=/srv/data2 --prune --repo=/srv/backup/repo --tag=photos

docsphotos が順に実行されました。それぞれの forget--tag=docs / --tag=photos が付いていることに注目してください。同じリポジトリを共有していても、世代整理は互いに干渉しません。

base(リポジトリ・保持ポリシー)docssource: /srv/datatag: docsphotossource: /srv/data2tag: photosgroup: nightlyinheritinherit

二重起動を防ぐ

第1回で挙げた restic の制約に「1つのリポジトリに同時に書き込めない」がありました。自動実行を始めると、前回の処理が終わらないうちに次が起動する、という事態が普通に起こります。

resticprofile 側でロックを持たせます。

profiles:
  default:
    lock: "/tmp/resticprofile-default.lock"
    force-inactive-lock: true

lock はロックファイルの場所です。force-inactive-lock: true は、ロックを持っていたプロセスがすでに存在しない場合に、そのロックを無効と判断して奪う指定です。これがないと、サーバが強制終了したあとロックファイルが残り、以降のバックアップが全て失敗し続けます。

restic 側にもリポジトリのロックがあり、こちらは global で扱いを指定できます。

global:
  restic-lock-retry-after: 1m
  restic-stale-lock-age: 1h

show の出力にこの2つが既定値として出ていたのは、これです。

今回の到達点

  • restic の引数が profiles.yaml に移った
  • show で解釈結果を、--dry-run で実行内容を確認できる
  • inherit で共通部分を1か所にまとめ、groups でまとめて実行できる
  • retention が profile ごとに範囲を限定してくれる
  • lock で二重起動を防げる

まだ全て手動実行です。ここまでは「シェルスクリプトを設定ファイルに置き換えた」だけで、cron や systemd unit は自分で書く必要が残っています。

次回

次回は schedule を1行足して、systemd timer を resticprofile に生成させます。生成された unit ファイルを開いて、何が書かれているかまで読みます。自動実行を人に見えないところへ隠さないためです。

この回で使ったツール