「 の自動バックアップが動いているから安心」と思っていましたが、設定画面を見て気づきました。週 1 回・1 世代のみ。3 日前の誤削除には対応できません。
本記事では、当方が Hostinger ( + + + Traefik + 各種 DB)に対して、 + で毎日を組んだ実装記録を、コマンド付きで公開します。月額 22 円、初回 16.7GB を 2 分 59 秒でアップロード、7 世代保管の構成です。
構成全体像

| 要素 | 採用 | 理由 |
|---|---|---|
| バックアップ元 | Hostinger VPS | Nextcloud / n8n / Postiz / 各 DB が稼働 |
| バックアップツール | restic 0.16.4 | 単一バイナリ、暗号化、、対応 |
| 保存先 | R2 | egress 無料、$0.015/GB/月、S3 互換 |
| スケジュール | 04:00 UTC(13:00 JST) | サーバー負荷の低い時間帯 |
| 日次 7 + 週次 4 + 月次 6 | restic forget で自動運用 | |
| 暗号化 | restic 標準 | パスフレーズで全リポジトリ暗号化 |
Step 1: Cloudflare R2 のセットアップ
1.1 R2 を有効化
Cloudflare ダッシュボード → R2 で「Purchase R2」をクリック。クレジットカードを登録(無料枠内なら課金 0 円)。
1.2 バケット作成
| 項目 | 設定 |
|---|---|
| Bucket name | <任意>(例: vps-backup) |
| Location | Automatic(Asia Pacific が自動選択) |
| Default Storage Class | Standard(restic は週 1 回 check で読みに行くため) |
Infrequent Access クラスは月 1 回未満アクセス前提で、restic の整合性チェックで取り出し料金が発生するため不向きです。
1.3 Account API Token を発行
「Manage R2 API Tokens」→「Create Account API token」。
| 項目 | 設定 |
|---|---|
| Token name | vps-backup-token |
| Permissions | Object Read & Write(Admin Read & Write は権限が広すぎるので NG) |
| Specify bucket(s) | 作成したバケットのみ() |
| TTL | Forever |
発行後に表示される Access Key ID と Secret Access Key を必ずメモ。この画面を閉じると Secret は二度と表示されません。
💡 KEY TAKEAWAYS
Account API Token は必ずバケットスコープで発行。「All buckets」+「Admin Read & Write」は事故時の影響範囲が広すぎます。
Step 2: VPS 側のセットアップ
2.1 restic のインストール
``bash`
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y -qq restic
restic version→ restic 0.16.4 compiled with go1.22.2 on linux/amd64
apt-get の対話プロンプトが表示されると SSH 越しにハングするので、DEBIAN_FRONTEND=noninteractive を必ず設定します。
2.2 認証情報を保存
/root/.config/restic/r2-credentials.env を chmod 600 で作成:
`bash`
export AWS_ACCESS_KEY_ID="
export AWS_SECRET_ACCESS_KEY="
export RESTIC_REPOSITORY="s3:https://
export RESTIC_PASSWORD="
RESTIC_PASSWORD は 3 重保管してください(VPS / 手元 PC / オフライン媒体)。これを失うとバックアップは復元できなくなります。
2.3 リポジトリ初期化
`bash`
. /root/.config/restic/r2-credentials.env
restic init→ created restic repository
これで R2 バケット内に restic のリポジトリ構造が作られます。
Step 3: バックアップスクリプト
/usr/local/bin/vps-backup.sh を作成(chmod 700)。流れは「DB ダンプ → restic backup → 保持ポリシー適用 → 軽い整合性チェック」。
`bash
#!/usr/bin/env bash
set -euo pipefail
LOG_FILE="/var/log/vps-backup.log"
DUMP_DIR="/tmp/restic-dumps-$$"
log() { printf '[%s] %s\n' "$(date -u +%FT%TZ)" "$*" | tee -a "$LOG_FILE"; }
trap 'rm -rf "$DUMP_DIR"' EXIT
. /root/.config/restic/r2-credentials.env
. /root/.config/restic/db-credentials.env
mkdir -p "$DUMP_DIR" && chmod 700 "$DUMP_DIR"
log "= Backup START ="
DB ダンプ(並列で MariaDB + Postgres x N)
docker exec -e MYSQL_PWD="$NEXTCLOUD_DB_PASSWORD" nextcloud-db \ mariadb-dump --single-transaction --quick --skip-lock-tables \ -uroot nextcloud | gzip > "$DUMP_DIR/nextcloud.sql.gz"docker exec -e PGPASSWORD="$POSTIZ_DB_PASSWORD" postiz-postgres \
pg_dumpall -U postiz | gzip > "$DUMP_DIR/postiz.sql.gz"
restic backup
restic backup \ --tag scheduled \ --exclude-caches \ --exclude '/var/log' --exclude '/tmp' \ --exclude '/root/.npm' --exclude '/root/.cache' \ /var/lib/docker/volumes/nextcloud_nc_data \ /var/lib/docker/volumes/n8n_data \ /var/lib/docker/volumes/postiz_postiz-uploads \ /etc /root/.ssh /root/.config \ "$DUMP_DIR"保持ポリシー(日次 7 + 週次 4 + 月次 6)+ 自動 prune
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune軽い整合性チェック(5% サブセット)
restic check --read-data-subset=5%log "= Backup END ="
`
mariadb-dump は --single-transaction でロックなしダンプ。本番稼働中の DB に影響しません。
Step 3.1: cron に登録
`bash`
( crontab -l 2>/dev/null; echo '0 4 * * * /usr/local/bin/vps-backup.sh >> /var/log/vps-backup.log 2>&1' ) | crontab -
毎日 04:00 UTC(13:00 JST)に自動実行。サーバー負荷の低い時間帯です。
Step 3.2: ログローテート設定
`bash`
cat > /etc/logrotate.d/vps-backup <
weekly
rotate 8
compress
missingok
notifempty
create 600 root root
}
EOF
これでログが肥大化することを防げます。
Step 4: 初回フルバックアップ
`bash`
nohup /usr/local/bin/vps-backup.sh >> /var/log/vps-backup.log 2>&1 &
tail -f /var/log/vps-backup.log
当方の実測値:
| 項目 | 値 |
|---|---|
| ファイル数 | 332,446 |
| 元サイズ | 16.730 GiB |
| R2 上の実サイズ | 5.048 GiB(圧縮率 2.56x、60.93% 削減) |
| 所要時間 | 2 分 59 秒 |
| アップロード速度 | 約 95 MB/s |
R2 月額試算: 5GB × $0.015 = $0.075(約 11 円)。7 世代分の差分も含めて月 $0.15(約 22 円)程度に収まります。
Step 5: — 必ずやる
「バックアップは取れている」と思い込んで実は復元できないケースが多すぎます。月 1 回必ず復元テストを行います。
`bash
. /root/.config/restic/r2-credentials.env
任意のファイルを R2 から取り出す
restic restore latest \ --target /tmp/restore-test \ --include /etc/hostnameオリジナルと比較
diff /etc/hostname /tmp/restore-test/etc/hostname && echo "✅ 一致"後片付け
rm -rf /tmp/restore-test `
当方の実測:単一ファイル復元は1 秒以内、フル復元は 5〜15 分。
💡 KEY TAKEAWAYS
復元テストをしていないバックアップは、バックアップではありません。月 1 回必ず実行する習慣をつけてください。
ハマりポイント 3 つ

restic + R2 構築で踏んだ 3 つの罠
落とし穴 1: SSH 鍵パスのタイプミス
~/.ssh/ を ~/.ssh/ と打ち間違えて、SSH コマンドが「Permission denied (publickey)」で延々と弾かれました。Tab 補完を使わずに手打ちで ed25519 を入れる場合、数字部分は要注意です。
突破: SSH 鍵パスはエイリアスを
~/.ssh/config に登録して、ssh で接続するスタイルが安全です。
落とし穴 2: apt-get install がプロンプトでハング
apt-get install restic が SSH 越しに実行中、Configuration file modified の対話プロンプトが出てハングしました。SSH は「待機中」と見えるだけで、何も進みません。
突破:
export DEBIAN_FRONTEND=noninteractive` をスクリプト先頭で必ず宣言。これだけで対話プロンプトを全て自動回答に切り替えられます。
落とし穴 3: restic の保持ポリシー試算ミス
「日次 7 + 週次 4 + 月次 6 = 17 世代分の容量が必要」と思いがちですが、restic は重複排除しているため、実容量は初回 + 変更分のみ。当方の場合 16.7GB の元データに対し、7 世代維持しても R2 上は 7〜10GB 程度で済みます。
突破: 試算は「初回 × 1.5」程度を上限の目安に。月額計算は実測でみて初月で確定させます。
次のアクション
「バックアップは大事」と頭で分かっていても、実際に組まないと災害復旧はできません。本記事の構成は VPS 1 台あたり月 22 円から始められ、構築 30〜60 分で運用に乗ります。
本シリーズ第 1 回「Nextcloud のロック詰まりは Redis 化で解決する」、第 3 回「Dropbox 代替を自社で組む判断軸」と合わせて読むと、自社のクラウドストレージを / サブスクリプションから卒業する全体像が掴めます。
「自社で組むのは技術的に厳しい」「組んだが運用が続かない」という方は、まず 細マッチョ企業診断 で耐久力(事業継続性)の現在地を把握ください。EXBANK ではバックアップ構築 + 6 ヶ月伴走運用パッケージも提供しています。
