復旧準備
Libre WebUI は、バックアップと復元における最初の安全ゲートとして、読み取り専用の復旧インベントリを提供します。既知の状態と、スナップショットを妨げる検出済みの条件を報告します。メンテナンスロックの取得、データのコピー、暗号化、アップロード、削除、修復、復元は行いません。
libre-webui recovery-check --json > recovery-inventory.json
ソースのチェックアウトから実行する場合は、npm run build:backend を一度実行し、libre-webui recovery-check を npm run recovery:check -- に置き換えてください。パッケージ版の npx と Homebrew は、既定で ~/.libre-webui を検査します。DATA_DIR や明示的なパスオプションを指定すると、その場所を上書きします。
ブロッカーが見つからなければ、コマンドはステータス 0 で終了します。レポートは完成したものの復旧ブロッカーがある場合は 1、引数が無効または収集中に予期しない失敗が起きた場合は 2 です。既定以外の場所を検査するには、--data-dir PATH または --database PATH を使います。既定または --data-dir のボリュームインベントリが受け付けるのは、標準の DATA_DIR/data.sqlite ファイルだけです。ハードリンク、シンボリックリンク、通常ファイルではないデータベース/WAL/SHM エントリは拒否します。明示的な --database パスは DATA_DIR の外に置けますが、選択したデータベースと付随ファイルは通常ファイルでなければならず、シンボリックリンクにはできません。--data-dir なしで --database を使うと、復旧処理はデータベースの親ディレクトリをデータルートとして扱い、対応するキー、blob、プラグイン定義をまとめて棚卸しします。
ランタイムはさらに、決定論的なバックエンドパッケージの plugins ディレクトリと、相対パスの PLUGINS_DIR の場合は従来のバックエンド相対位置から、過去形式のプラグイン定義を読み取ります。復旧処理は、これらの有効なレガシーパスを棚卸しし、カスタム定義が含まれる場合はボリュームだけのスナップショットをブロックします。パッケージ版デプロイでイメージのレイアウトにより互換ディレクトリが移動している場合は、--legacy-plugins-dir PATH を複数回指定できます。
非公開 Compose デプロイでは、デプロイ済みコンテナの内部で実行してください。これにより、そのコンテナにマウントされたボリューム、コード、シークレットがレポートの対象になります。
docker exec libre-webui \
libre-webui recovery-check --json --data-dir /app/backend/data
インベントリの検査内容
バージョン付き JSON レポートには、次の内容が記録されます。
- アプリケーション、Node.js、OS、アーキテクチャの各バージョン。
- SQLite ファイルと WAL/SHM のサイズ、
quick_check、外部キー検証、スキーマフィンガープリント、ユーザーバージョン、不足している必須テーブル、非公開の検査スナップショットを作成する前の no-follow ソースファイル検証。 - データディレクトリの読み取り/書き込み可否、ファイル数、バイト数。
- 選択された暗号化キーの供給元と、一方向の 16 文字フィンガープリント。
- 永続的な
.encryption_keyファイルに対する、no-follow および単一リンクの検証。 - カスタムプラグイン定義、暗号化されたローカル blob ルート、埋め込みメディア、音声参照、文書テキスト、レガシー文書ベクトル、ACL/フィルター行を含むプラットフォームベクトルについて、その有無、件数、サイズ、データディレクトリに含まれるかどうか。
- 標準ローカル blob オブジェクトと埋め込みプラットフォームベクトルエンベロープすべてに対する、上限付きの読み取り専用認証。blob の全チャンク/チェックサム検証と、設定済みキーの利用可否も含みます。
- チャット、ノート、文書、設定、プラグインシークレット、ギャラリー/メディア状態、アカウントメールに含まれる、認識可能なレガシーテキスト AES-GCM エンベロープすべてに対する、上限付きの読み取り専用認証。さらに、AAD に関連付けられた保存済み音声の名前、録音、文字起こしの各エンベロープも対象です。
- Work のタスク/実行/プレビュー件数と、想定される Docker ボリューム、Kubernetes PVC、ハッシュ化されたホストパス ID。Docker ボリュームには、管理対象ラベルと正確な所有タスク ID の両方が必要です。
- レガシーのメディア生成ジョブ状態、および状態別の永続ジョブ、結果別の試行、イベントストリーム/イベント件数、最後のグローバルイベントカーソル。
- 暗号化されたすべての永続ジョブ/イベントペイロードに対する上限付きの読み取り専用認証、および不透明な参照ペイロードすべてに対する上限付き構文検証。
- 明示的なブロッカー、警告、アプリケーションデータディレクトリ外にあるデータ。
レポートに、暗号化キー、JWT/セッションシークレット、プロバイダー認証情報、プラグインの内容、ユーザーコンテンツ、ホストワークスペースの実際のパスが含まれることはありません。出力されるのは、シークレットの有無を示す真偽値と、逆算できない暗号化キーフィンガープリントだけです。
読み取り専用でマウントしたデータは復旧検査に有効であり、ブロッカーではなく警告になります。アプリケーションを ready 状態にするには、引き続き書き込み可能なストレージが必要です。バックアップヘルパーで使用する読み取り専用スナップショットに対して Libre WebUI を起動してはいけません。
ブロッカー
ブロッカーが 1 つでもあれば、復旧ゲートは失敗として扱ってください。代表例は、データベースの欠落や破損、不完全なスキーマ、キーの欠落や競合、破損または未認証のレガシー/プラットフォーム暗号文、検証上限の超過、読み取れないデータディレクトリ、リンクされた、または通常ファイルではない SQLite ソース、実行中の Work 実行やプレビュー、メディアジョブや永続ジョブ、Work ワークスペースの欠落または誤ったラベル、永続イベントの先頭不一致やシーケンスの欠落、データディレクトリ外にあるカスタムプラグイン定義、外部ワークスペースを検証できないランタイム制御プレーンです。スナップショットを取得する前に、進行中の処理を静止させ、不足している依存関係を解決してください。ブロッカーを隠すためにレポートを編集してはいけません。
暗号化された永続ペイロードは、そのジョブ/イベント ID に照らして認証され、上限付きの正規 JSON として検証されます。不透明な参照ペイロードは、上限と構文だけを検査します。現在の基盤には、参照先の存在やアクセス権を復旧処理が証明するための正式な blob 参照リポジトリがないためです。このような参照があると、レポートは referenceTargetsVerified を false にして警告しますが、ペイロードや参照値を公開することはありません。
レガシーテキストフィールドは、必須のエンベロープマーカーが導入される前から存在します。そのため、古い世代のスキーマにある真正な平文行は読み取り可能なままで、認証済み暗号文としては報告されません。標準エンベロープは必ず認証されます。エンベロープ幅の IV または認証タグを持つ 3 部構成の値は、不正な場合に安全側へ閉じて失敗します。保存済み音声フィールドには曖昧さのないバイナリエンベロープがあり、プロファイル、所有者、フィールド ID に照らした認証が常に必要です。JSON の encryption.legacyCiphertext セクションは、平文を公開せず、認証済みテキスト/バイナリのレコード数とバイト総数を報告します。
スキーマ v4 の users.email_lookup 列がある場合、復旧処理は null ではない全メールアドレスも認証し、ドメイン分離されたキー付き検索トークンを再計算します。トークンがない、または一致しない場合、あるいは null のメールアドレスにトークンが付いている場合は、スナップショットをブロックします。v4 より前のデータベースにはこの派生検索列がないため、引き続き互換性があります。
現在のバックアップ境界
非公開デプロイ用ヘルパーは、アプリケーションが実行中なら停止し、そのコンテナの不変イメージ、マウント済みデータボリューム、環境を使って統合された solo アーカイブを作成します。マニフェストは Ed25519 で署名され、完全なペイロードは運用者が保持する AES-256-GCM バックアップキーで暗号化されます。アーカイブには SQLite、ローカル blob と埋め込みベクトル、ランタイムセレクター、復元した状態を復号するために必要な保護設定が含まれます。ヘルパーはアーカイブとメタデータレポートを公開する前に、署名、暗号文チェックサム、復号済みペイロードを検証します。libre-webui-restore は新しい Docker ボリュームだけを受け付け、データをコピーする前に復号済みの復旧インベントリを検証し、復元された設定を新しい対象ディレクトリへ非公開ファイルとして公開します。
保護対象のランタイム設定には、PostgreSQL のプール、接続、アイドル、ステートメント、移行ロックの各タイムアウト、Redis 接続タイムアウト、2 つの永続 blob クォータ設定、プラットフォームセレクター、S3 プレフィックスとアドレッシングモードが含まれます。これらの値は平文マニフェストではなく、署名、暗号化されたペイロード内にあり、適用済み復元ではモード 0600 の設定として再公開されます。
solo アーカイブには、Docker の Work ボリューム、Kubernetes PVC、ホストに結び付いたワークスペースフォルダ、Ollama モデル、外部プロバイダーの状態は含まれません。署名済みマニフェストに記載されたこれらの除外項目を見える状態に保ち、外部の Work ストレージは別途スナップショットしてください。team プロファイルは、別のオフライン team ワークフローを使います。PostgreSQL のエクスポート済みスナップショット、正確なバージョン付き S3 暗号文オブジェクト、PGVector インベントリ、ランタイム設定、キー ID を、同じ署名/暗号化アーカイブ形式に封入し、復元時にクリーンな PostgreSQL/S3 対象に照らして検証します。Redis のキャッシュ、プレゼンス、ウェイクアップ、リースは、正式な SQL 状態から再構築されます。
team バックアップは、エクスポートした正確な PostgreSQL スナップショット内にある、上限付きの暗号化済み永続ジョブ/イベントペイロードもすべて認証します。保護された署名済みインベントリには、ジョブ、イベント、ストリーム、カーソル、エンベロープ、参照、認証済み平文の合計が記録されます。すべてのイベントストリームには、連続したシーケンス 1..last_sequence が正確に含まれている必要があります。また PostgreSQL のグローバルカーソルシーケンスは、保存された最大カーソルより遅れてはなりません。復元時にクリーンな対象へ同じ検査を繰り返し、完全な結果が署名済みソースインベントリと一致しなければ、成功とは報告しません。PostgreSQL の ID 割り当てはトランザクションではないため、異なるグローバルカーソル値の間に欠番があっても有効です。ストリームごとのシーケンスは連続順序でなければなりません。
PLUGINS_DIR が DATA_DIR の外を指す場合、復旧処理はその正確なディレクトリを棚卸しし、アプリケーションボリュームのアーカイブから除外されるものとして記録します。そこに定義が 1 つでもあれば、運用者が対応するプラグインディレクトリのスナップショットを手配するまで、ボリュームだけのスナップショットはブロックされます。有効なレガシープラグインディレクトリにも同じルールを適用します。シンボリックリンク、通常ファイルでない、または読み取れない JSON 定義は常にブロッカーとなり、リンク先をたどったり黙って省略したりすることはありません。
永続ジョブと順序付きイベントは、両方のプロファイルで有効です。ジョブ試行または Work 実行が進行中なら復旧処理はブロックし、ジョブ/イベントのペイロードと連続したストリーム先頭を検証し、正式な SQL 状態を保持します。solo は上限付きの組み込みワーカーを実行します。team は同じ登録済みハンドラーを外部ワーカーで実行し、Redis はウェイクアップとファンアウトだけに使います。
本番環境では、暗号化シークレットと JWT シークレットを保護されたシークレットマネージャーへ保存し、バックアップアーカイブを暗号化してホスト外に保管し、クリーンで互換性のある環境への復元をテストしてください。インベントリは既知の状態を事前確認するスナップショットであり、メンテナンスロックでも、すべての外部リソースが復元可能であることの独立した証明でもありません。
署名、暗号化されたバックアップコマンド
以下の例では、グローバル npm または Homebrew からインストールした libre-webui コマンドを使います。グローバルにインストールしない場合は、libre-webui を npx --yes libre-webui@latest に置き換えます。ソースのチェックアウトからは、バックエンドを一度ビルドし、libre-webui backup を npm run recovery:backup -- に置き換えます。本番 Docker イメージでは、同じコマンドが /usr/local/bin/libre-webui にあります。team のバックアップと復元には、さらに PostgreSQL 16 の pg_dump と pg_restore が必要です。これらは本番イメージと Homebrew formula のコマンドパスに含まれます。通常の npm/npx からこれらのコマンドを使う場合は、互換性のある PostgreSQL クライアントを明示的にインストールしてください。
運用者が保持する AES-256-GCM アーカイブキーと Ed25519 署名キーペアを非公開ディレクトリに生成し、秘密鍵を保護されたホスト外ストレージへ移動します。
install -d -m 0700 /absolute/private/libre-backup-keys
libre-webui backup keygen \
--directory /absolute/private/libre-backup-keys
静止させた solo データディレクトリについて、アーカイブを作成し、独立して検証します。
libre-webui backup create \
--offline \
--data-dir /absolute/path/to/libre-data \
--output /absolute/backups/libre-solo.lwbackup \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-private-key /absolute/private/libre-backup-keys/backup-signing-private.pem
libre-webui backup verify \
--archive /absolute/backups/libre-solo.lwbackup \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-public-key /absolute/private/libre-backup-keys/backup-signing-public.pem
まず復元の事前確認を行い、その後、新しい空の対象ディレクトリにだけ適用します。
libre-webui backup restore-preflight \
--archive /absolute/backups/libre-solo.lwbackup \
--target /absolute/restore/libre-data \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-public-key /absolute/private/libre-backup-keys/backup-signing-public.pem
libre-webui backup restore-apply \
--archive /absolute/backups/libre-solo.lwbackup \
--target /absolute/restore/libre-data \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-public-key /absolute/private/libre-backup-keys/backup-signing-public.pem
libre-webui backup restore-verify \
--target /absolute/restore/libre-data
team モードでは、すべてのアプリケーションレプリカとワーカーを停止し、ソースの PostgreSQL/S3/キーリング環境を読み込んだまま、整合の取れたアーカイブを作成します。
libre-webui backup create-team \
--offline \
--output /absolute/backups/libre-team.lwbackup \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-private-key /absolute/private/libre-backup-keys/backup-signing-private.pem
復元前に、別の空の PostgreSQL データベースと、バージョニングを有効にした空の S3 バケット用の環境変数を読み込みます。事前確認は署名と暗号化アーカイブを検証し、保護されたインベントリを検査し、データを公開せずに選択した対象データベースとバケットプレフィックスが空であることを証明します。適用処理はそのクリーンな対象へ復元し、生成された PostgreSQL スキーマ、正確な S3 オブジェクト、PGVector レコードを検証して、保護されたランタイム設定を新しい非公開ディレクトリへ書き込みます。
libre-webui backup restore-team-preflight \
--archive /absolute/backups/libre-team.lwbackup \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-public-key /absolute/private/libre-backup-keys/backup-signing-public.pem
libre-webui backup restore-team-apply \
--archive /absolute/backups/libre-team.lwbackup \
--configuration-output /absolute/restore/libre-team-config \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-public-key /absolute/private/libre-backup-keys/backup-signing-public.pem
復元先に、ソースデータベース、ソースバケット、既存のデータディレクトリ、ファイルを含む設定ディレクトリを指定してはいけません。公開署名鍵は復元手順書と一緒に保管してください。アーカイブと公開鍵を持っているだけでは、ペイロードを復号できません。
team の復元でロールバックが不完全だと報告された場合、選択した両方の対象を汚染済みとして扱い、すぐに再試行してはいけません。対象 PostgreSQL データベースを検査してクリーンにした後、正確な対象 S3 プレフィックス配下にある全オブジェクトバージョンと削除マーカーを列挙し、削除します。restore-team-preflight を再実行してください。クリーンな対象に対する事前確認が成功した後にだけ、安全に適用を再試行できます。
スケジュールされた検証済み復旧訓練
一度も復元したことのないバックアップは、復旧ではなく希望にすぎません。訓練は、上記のパイプラインを最初から最後まで正確に実行し、ダウンタイムも運用者の操作もなしで、インスタンスを実際に復旧できることを証明します。
- データディレクトリの静止スナップショットをステージングします。SQLite データベースはオンラインバックアップ API で、blob とファイルは物理コピーで取得します。訓練は静かなタイミングを待ちます。永続ジョブの実行中は開始を拒否し、これは
recovery-checkと同じルールです。 - ステージングしたコピーに完全な復旧インベントリを実行し、一時的な訓練用キーを使って、署名済みの AES-256-GCM 暗号化アーカイブにします。
- アーカイブを検証し、隔離された一時対象へ復元し、復元済み環境をもう一度検証します。
- 訓練で測定した内容を記録します。復元所要時間は実証された RTO となり、成功した訓練の間隔は現在のスケジュールで達成可能な RPO の上限になります。その後、すべての成果物を削除します。訓練は検証であってバックアップではありません。アーカイブもキーも保持しません。
RECOVERY_DRILL_INTERVAL_HOURS(例: 24)でスケジュールを有効にします。訓練は調整用リースの下で共有スケジューラーから実行されるため、レプリカや重複するティックによる二重実行はありません。システムページには訓練履歴と、管理者用の「今すぐ訓練を実行」ボタンが表示されます。背後では GET /api/recovery/drills と POST /api/recovery/drills/run を使います。無人訓練に失敗すると、通知受信箱と購読済み Webhook の対象を通じて全管理者に警告します。手動実行では、開始拒否をその場で直接報告します。RECOVERY_DRILL_HISTORY は保持する履歴数を制限します(既定は 60 件)。
訓練の対象は、ファイルシステムアーカイブが正式なバックアップ経路である solo(SQLite)プロファイルです。team プロファイルでは、整合された backup create-team フローを引き続き使い、その復元リハーサルは現時点では運用者が手順書に従って実施します。