| 要素 | 採用 | 理由 |
|---|---|---|
| バックアップ元 | 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 標準 | パスフレーズで全リポジトリ暗号化 |
| 項目 | 設定 | |
| --- | --- | |
| Bucket name | <任意>(例: vps-backup) | |
| Location | Automatic(Asia Pacific が自動選択) | |
| Default Storage Class | Standard(restic は週 1 回 check で読みに行くため) | |
| 項目 | 設定 | |
| --- | --- | |
| Token name | vps-backup-token | |
| Permissions | Object Read & Write(Admin Read & Write は権限が広すぎるので NG) | |
| Specify bucket(s) | 作成したバケットのみ() | |
| TTL | Forever |
Step 2: VPS 側のセットアップ
2.1 restic のインストール
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 で作成:
export AWS_ACCESS_KEY_ID="<R2 Access Key ID>"
export AWS_SECRET_ACCESS_KEY="<R2 Secret Access Key>"
export RESTIC_REPOSITORY="s3:https://<account-id>.r2.cloudflarestorage.com/<bucket-name>"
export RESTIC_PASSWORD="<openssl rand -base64 32 で生成した強パスフレーズ>"
RESTIC_PASSWORD は 3 重保管してください(VPS / 手元 PC / オフライン媒体)。これを失うとバックアップは復元できなくなります。
2.3 リポジトリ初期化
. /root/.config/restic/r2-credentials.env
restic init
# → created restic repository <id> at s3:https://...
これで R2 バケット内に restic のリポジトリ構造が作られます。
Step 3: バックアップスクリプト
/usr/local/bin/vps-backup.sh を作成(chmod 700)。流れは「DB ダンプ → restic backup → 保持ポリシー適用 → 軽い整合性チェック」。
#!/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 に登録
( 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: ログローテート設定
cat > /etc/logrotate.d/vps-backup <<EOF
/var/log/vps-backup.log {
weekly
rotate 8
compress
missingok
notifempty
create 600 root root
}
EOF
これでログが肥大化することを防げます。
Step 4: 初回フルバックアップ
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 |
. /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/を_ed25519 ~/.ssh/と打ち間違えて、SSH コマンドが「Permission denied (publickey)」で延々と弾かれました。Tab 補完を使わずに手打ちで_ed25739 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 ヶ月伴走運用パッケージも提供しています。

