# バックアップとリストア

> セルフホスティングの Nodaro を 1 つのコマンドでバックアップし、別のコマンドでリストアして、安全にダウングレードする方法です。アーカイブの中身と、そのキーの守り方も説明します。

Source: https://nodaro.ai/ja/docs/self-hosting/backups

セルフホスティングの Nodaro は、1 つのコマンドで**バックアップ**し、もう 1 つのコマンドで**リストア**します。バックアップのアーカイブには、スタックが作り直せないものがすべて入ります。データベース、メディア、インスタンスの暗号化キー、`.env` です。データベースのマイグレーションは前方向にしか進まないため、リストアはダウングレードの唯一の方法でもあります。以前のバージョンに戻すには、アップデートの前に取ったバックアップをリストアします。

## バックアップの内容
`tools/community-backup.sh` は、1 つの `tar.gz` アーカイブを書き出します。

| アーカイブ内のファイル | 内容 |
| --- | --- |
| `db.dump` | pg_dump のカスタム形式による Postgres のデータです。ワークフロー、ユーザー、ジョブ、メディアのレコードが含まれます |
| `minio-data.tar` | 生成したメディアです。画像、動画、オーディオが含まれます |
| `encryption-key` | プロバイダーキーと SNS のログイントークンを暗号化する、インスタンスのキーです。**このキーなしでリストアしたデータベースには、誰にも読めない行が残ります。** |
| `env` | `.env` です。プロバイダーキーとシークレットが含まれます |
| `manifest.json` | アプリのバージョンとバックアップの日時です。リストア用のスクリプトが使います |

Redis は意図的に含めていません。Redis が保持するのは、一時的なジョブの状態だけだからです。

**アーカイブは認証情報そのものです:** 
アーカイブには、`.env` と暗号化キーが含まれます。スクリプトは、ファイルのアクセス権を所有者だけに制限します（`chmod 600`）。この設定を変えずに、アーカイブはパスワードと同じように保管してください。Windows では、`chmod` は実質的に効果がありません。ファイルを同期フォルダーや共有ドライブに置かないでください。ほかの人もそのコンピューターを使う場合は、NTFS のアクセス許可で制限してください。

## バックアップを取る
スタックを**起動したまま**、`docker-compose.community.yml` があるインストールディレクトリで、次を実行します。

```bash
tools/community-backup.sh
# -> ./backups/nodaro-backup-<date>-v<version>.tar.gz
```

| オプション | 動作 |
| --- | --- |
| `tools/community-backup.sh /path/to/backups` | アーカイブを別のディレクトリに書き出します |
| `COMPOSE_FILE=my-compose.yml tools/community-backup.sh` | 別の名前の Compose ファイルを使います |

スクリプトは、アーカイブに入れたものを表示します。暗号化キーが見つからない場合は、そのことを目立つように表示し、エラーで終了するので、スケジュール実行のジョブでも気付けます。そのアーカイブでは、プロバイダーキーをリストアできません。

データベースのダンプは、常に整合性が保たれています。一方、バックアップの実行中に書き込まれたメディアは、アーカイブに入らないことがあります。メディアのスナップショットの整合性を確実に保つには、先にアプリを停止します。

```bash
docker compose -f docker-compose.community.yml stop nodaro
```

**Windows では**、Git for Windows がインストールするシェル、**Git Bash** からスクリプトを実行してください。PowerShell や WSL の bash では、コンテナのパスが壊れます。

### バックアップのタイミング
**メジャー**バージョンのアップデート（最初の数字が変わるもの）の前には、必ずバックアップを取ります。それとは別に、データの重要度に見合ったスケジュールでも取ってください。次の cron の設定は、そのまま使えます。

```bash
0 3 * * * cd /path/to/install && tools/community-backup.sh >> backup.log 2>&1
```

## バックアップをリストアする
```bash
tools/community-restore.sh backups/nodaro-backup-<date>-v<version>.tar.gz
```

リストアは、データベースとメディアをアーカイブの内容で置き換えます。そのため、何かに手を付ける前に、`RESTORE` と入力するよう求めます。そのあと、次の処理を行います。

1. アプリと、データベースのクライアントである `auth` と `rest` を停止します。これらが開いている接続があると、リストアが妨げられるためです。
2. Postgres をリストアし、終了コードを当てにせず、実際に動作することを確認します。Supabase のイメージから無害なメッセージがいくつか出力されますが、これは想定どおりです。
3. メディアをリストアし、バケットが元に戻り、MinIO が正常に動いていることを確認します。次に暗号化キーをリストアし、ボリューム上のサイズを確認します。続いて、既存の `.env` があれば別の場所に退避してから、`.env` をリストアします。確認に失敗すると、スクリプトはアプリを起動する**前に**止まります。正しいキーがないままアプリを起動すると、新しいキーが作られ、リストアしたプロバイダーキーはすべて二度と読めなくなるためです。
4. すべてを再び起動し、アプリ自身のヘルスチェックを待ちます。スクリプトが成功を報告するのは、アプリが起動してからです。起動しなかった場合は、エラーで終了します。

完了したら、`http://localhost:3000/setup` を開きます。すべてのカードが緑になっているはずです。

## バージョンをダウングレードする
マイグレーションのロールバックはありません。以前のバージョンに戻すには、次の手順を実行します。

1. 上記の手順で、アップデートの**前に**取ったバックアップをリストアします。
2. `NODARO_IMAGE` か `docker-compose.community.yml` で、古いイメージ（たとえば `ghcr.io/nodaroai/nodaro-community:v1.25.1`）に固定します。`vX.Y.Z` 形式の厳密なタグが指すイメージは、変わることがありません。
3. `docker compose -f docker-compose.community.yml up -d nodaro` を実行します。

タグについては、[アップデート](https://nodaro.ai/docs/self-hosting/updating)を参照してください。

## マネージド構成のバックアップ
Compose スタックを使わない構成では、状態を持つものが 4 つあります。

| 対象 | 保護の方法 |
| --- | --- |
| **Supabase の Postgres**：ワークフロー、プロフィール、ジョブ、メディアのレコード | 有料プランで使える Supabase のポイントインタイムリカバリを使うか、定期的に `pg_dump` を実行します。これが最も重要なバックアップです。 |
| **ストレージのバケット**：生成した画像、動画、オーディオ | バケットのバージョニングと、保持期間の長いライフサイクルルールを有効にして、削除したファイルを復元できるようにします。災害復旧が必要な場合は、リージョン間レプリケーションも追加します。 |
| **Redis** | バックアップするものはありません。Redis が保持するのは、一時的なジョブの状態だけです。Redis を失うと実行中の処理は失敗しますが、それ以外はすべて、次の起動時に Postgres から復旧します。 |
| **インスタンスの暗号化キー**（`NODARO_ENCRYPTION_KEY`） | Postgres のバックアップと一緒に保管します。このキーがないと、リストアした行のうち、プロバイダーキー、SNS のログイントークン、**Webhook 出力**（Webhook Output）の認証情報を読めません。その場合、タイルには `missing` と表示され、キーを入力し直す必要があります。ほかに壊れるものはありません。 |

マイグレーションや復旧の最中に Postgres が停止していると、API はデータベースに接続できるまで再起動を繰り返します。Postgres が復旧したら、Nodaro のコンテナを再起動してください。

## トラブルシューティング
- **`the db service is not running` と表示される**：先にスタックを起動します。`docker compose -f docker-compose.community.yml up -d` を実行してください。
- **リストア後、プロバイダーキーが `missing` と表示される**：データベースが、対応する `encryption-key` なしで、または別のキーでリストアされています。キーを含むアーカイブからリストアするか、`/setup` でキーを入力し直してください。
- **リストアの検証に失敗した**：スクリプトは、中途半端にリストアされたデータベースを黙って残すことはしません。リストアをもう一度実行してください。何度も失敗する場合は、アーカイブが途中で切れている可能性があります。元のファイルとサイズを比べてください。
- **Windows でのバックアップ中に `could not read the encryption key` と表示される**：Git Bash を使っていないか、アプリのコンテナが動いていません。スタックを起動した状態で、Git Bash からもう一度バックアップを実行してください。スクリプトが警告したアーカイブは、バックアップとして使えません。
- **`media restore verification FAILED` または `encryption key verification FAILED` と表示される**：スクリプトは意図的に停止し、アプリを起動していません。表示されたボリュームを確認し、原因（多くの場合、停止したコンテナか空きのないディスク）を取り除いてから、リストアをもう一度実行してください。何度実行しても安全です。

## Frequently asked questions

### セルフホスティングの Nodaro は、どのようにバックアップしますか？

スタックを起動したまま、インストールディレクトリで tools/community-backup.sh を実行します。データベース、メディア、インスタンスの暗号化キー、.env を含む 1 つのアーカイブが ./backups に書き出されます。

### バックアップは、どのようにリストアしますか？

アーカイブのパスを指定して tools/community-restore.sh を実行します。リストアは既存のデータを置き換えるため、最初に RESTORE と入力するよう求められます。アプリを再び起動する前に、データベース、メディア、暗号化キーを検証します。

### リストア後、プロバイダーキーが「missing」と表示されるのはなぜですか？

データベースが、対応する暗号化キーなしでリストアされたためです。キーを含むアーカイブからリストアするか、/setup でキーを入力し直してください。ほかに壊れるものはありません。

### Redis をバックアップする必要はありますか？

いいえ。Redis が保持するのは、一時的なジョブの状態だけです。Redis を失うと実行中の処理は失敗しますが、それ以外はすべて、次の起動時にデータベースから復旧します。

### バックアップのスクリプトは Windows で実行できますか？

はい。Git for Windows がインストールするシェル、Git Bash から実行してください。PowerShell や WSL の bash ではコンテナのパスが壊れ、暗号化キーがアーカイブに含まれなくなります。
