Immichのアップデートボタンを押したあと、写真管理サーバーが起動しなくなりました。
作業開始時の環境はTrueNAS SCALE 25.10.4のCommunity Apps版Immichでした。更新前の保全を済ませたあと、TrueNAS SCALEを25.10.5へ更新。再起動と25.10.5での起動を確認してから、Immich v2.4.1からv3.0.3への更新を開始しました。このImmich更新には、PostgreSQL 15から18への移行も含まれていました。
最終的には、いったんPostgreSQL 15へ戻してサービスを復旧し、データを論理バックアップしたうえで新しいPostgreSQL 18へ復元。Immich v3.0.3を安定稼働させるところまで到達しました。
この記事は「ボタンを押せば直る手順書」ではありません。起動しないImmichを前に、何を疑い、どこで判断を誤り、どうやってデータを守りながら復旧したかを残した障害対応記録です。
今回の障害と最終結果
最初に、更新前後と最終状態を整理します。
| 項目 | 作業開始時 | Immich更新直後 | 最終状態 |
|---|---|---|---|
| TrueNAS SCALE | 25.10.4 | 25.10.5 | 25.10.5 |
| Immich | v2.4.1 | v3.0.3へ更新失敗 | v3.0.3 |
| TrueNAS App | 1.11.8 | 1.14.30 | 1.14.30 |
| PostgreSQL | 15 | 18への移行失敗 | 18 |
| 状態 | 正常 | server再起動ループ | 正常稼働 |
| 確認結果 | 写真表示OK | Web UI利用不可 | Web UI、複数写真、サムネイル、検索、アセット24,501件を確認 |
重要なのは、途中で成功したPostgreSQL 15へのロールバックが最終ゴールではないことです。これは写真へ再アクセスし、正しいデータを確保するための一時的な退避地点でした。
アップデート前にスナップショットを作成
Immichには家族の写真が入っています。アプリ更新より先に考えたのは、新機能ではなく「失敗しても戻せるか」でした。
そこで、TrueNASの定期スナップショットに加えて、更新直前の手動スナップショットを作成しました。

ただし、今回のようなPostgreSQLメジャーバージョン移行では、スナップショットだけに頼るのは不安があります。データセット全体を戻す方法と、データベースを論理的に書き出して戻す方法は役割が異なるからです。
この時点ではまだ、あとでPostgreSQL 15の論理バックアップが復旧の中心になるとは考えていませんでした。
Immich v3.0.3への更新を開始
更新前のImmichは、v2.4.1/App 1.11.8で正常に動作していました。

手動スナップショット作成時のTrueNAS SCALEは25.10.4でした。その後、TrueNAS SCALEを25.10.5へ更新し、再起動後のバージョンと起動環境を確認してから、Community AppsのImmich更新を開始しました。表示された更新内容は、Immich v3.0.3/App 1.14.30です。

ところが、最初の更新はすぐに止まりました。表示されたのは次のエラーです。
immich.postgres_image_selector:
Input should be 'vectorchord_15_image' or 'vectorchord_18_image'

更新画面を見直すと、PostgreSQL 15と18を選択する項目が追加されていました。今回は15から18へ移行するつもりだったため、PostgreSQL 18を選択して更新を再実行しました。
PostgreSQL 18を選んでもImmichが起動しない
再実行後、アップデート処理はFAILEDになりました。

アプリの表示はv3.0.3へ変わったものの、ImmichのserverコンテナだけがExitedになり、再起動を繰り返します。つまり「新バージョンの構成が作られた」ことと、「移行後のデータベースを使ってサービスが起動した」ことは別でした。

ログで特に目立ったのは、次の2種類です。
FATAL: no pg_hba.conf entry for host "...", user "immich",
database "immich", no encryption
FATAL: database "immich" does not exist
最初はpg_hba.confの接続許可だけが原因に見えました。しかし、database "immich" does not existも同時に出ていました。
接続設定だけを直しても、移行先に必要なImmichデータベースが正しく作成・復元されていなければ起動しません。ここで「HBA設定の問題だけ」と決めつけないことが重要でした。
原因を追って試したこと
TrueNAS Appsのカタログ定義を確認
まず、ImmichがどのPostgreSQLイメージとアップグレード用イメージを使おうとしているのか確認しました。

調査中には、アップグレード用イメージのタグを1.1.7から1.1.11へ変更する方法も試しました。TrueNAS AppsのGitHubには、古いPostgreSQL 15のバイナリが見つからず移行に失敗する類似報告があり、1.1.11への変更例も示されています。
しかし、今回の環境では、この変更だけで最終復旧したわけではありません。実施した事実は残しつつ、万能な修正方法としては扱わないことにしました。
PostgreSQL内部を直接確認
次に、コンテナが起動しているかだけでなく、psqlでデータベース一覧を確認しました。

ログには照合順序(collation)のバージョン差を示す警告もありました。これも無視はできませんが、今回の直接原因だったとは確認できていません。
障害対応中は、目立つ警告を見つけると「これが原因だ」と考えたくなります。しかし実際には、警告、接続拒否、データベース不在が同時に発生していました。確認できた事実と仮説を分けないと、データベースへ不要な変更を重ねる危険があります。
pg_hba.confの編集では解決しなかった
接続拒否に引かれてpg_hba.confの確認・編集も試しましたが、改善しませんでした。
結果から振り返ると、壊れた移行先PG18をその場で継ぎはぎするより、正常なPG15から論理バックアップを取り、新しいPG18へ復元するほうが安全で検証しやすい状態でした。
まずPostgreSQL 15へ戻してサービスを一時復旧
調査を続ける前に、「写真が見える正常なデータベース」を取り戻すことを優先しました。
TrueNAS Appsのロールバック機能でApp 1.11.8を選び、PostgreSQL 15の構成へ戻します。

ここでも、停止中のアプリをそのままロールバックしようとしてエラーになりました。

状態を整えて再実行し、App 1.11.8/Immich v2.4.1へ復帰しました。

その後、アプリ一覧でImmichがRunningへ戻り、Web UIと写真表示を確認できました。

この時点で「復旧完了」とすることもできました。しかし、PostgreSQL 15はあくまで一時復旧です。今回の更新が要求するPostgreSQL 18への移行問題は残ったままでした。
壊れたPG18を直すのではなく、新しいPG18へ復元
最終的に採用したのは、次の考え方です。
- 正常に動くPostgreSQL 15を復旧元として固定する
- Immichを停止し、書き込みを止める
- PostgreSQL 15から論理バックアップを取得する
- 新しいPostgreSQL 18環境を初期化する
- エラー時に中断する設定と単一トランザクションでバックアップを復元する
- 移行元と移行先の
asset件数を比較する - スキーマを読み出せることを確認してからImmichへ接続する
新しいPG18には、Immich公式イメージghcr.io/immich-app/postgres:18-vectorchord0.5.3を使用しました。PG18が接続を受け付けることを確認してから、PG15のダンプをON_ERROR_STOPと単一トランザクション付きで復元しています。
この方法なら、復元途中でエラーが出たのに処理だけ進み、「一部だけ戻ったデータベース」を正常と誤認する危険を減らせます。
TrueNAS AppsのGitHubにも、PG15から論理ダンプを取得し、新しいPG18へ復元する類似の復旧例があります。ただし、データセット構成や拡張機能の状態は環境ごとに異なります。コマンドをそのままコピーするのではなく、自分の保存先、PostgreSQLイメージ、拡張機能、バックアップを確認する必要があります。
Immich v3.0.3+PostgreSQL 18で復旧完了
PG18への復元後、ImmichをPostgreSQL 18へ接続し、v3.0.3まで更新しました。
最終状態は、アプリの表示だけでなく、データベースとWeb UIを含む次の確認結果を根拠に復旧完了と判断しました。
- TrueNAS AppsでImmich v3.0.3/App 1.14.30が起動し、
serverコンテナが再起動ループに戻らないことを確認 - 移行元PG15の論理バックアップ取得前と、移行先PG18への復元後に
SELECT count(*) FROM asset;を実行し、どちらも24,501件で一致することを確認 - Web UIへログインし、タイムライン上で複数のサムネイルが表示されることを確認
- 複数の写真を個別に開き、表示できることを確認
- Web UIで検索を実行し、検索結果が返ることを確認
このように、最終確認は「アプリがRunningか」だけではなく、PG15とPG18のasset件数の一致、複数写真の表示、検索結果まで段階的に行っています。
今回の障害で学んだこと
アプリがRunningでも復旧確認は終わらない
緑色のRunning表示だけでは、写真データやDB整合性まで保証できません。Web UI、複数写真、サムネイル、検索、件数照合まで確認して、ようやく復旧と判断できます。
ロールバックはゴールではなく、安全な足場になる
PostgreSQL 15へ戻したことで、サービスを使える状態に戻し、正しいデータからバックアップを取り直せました。新バージョンへ進めないから戻ったのではなく、安全に前へ進むために一度戻った形です。
エラーメッセージを1行だけで判断しない
no pg_hba.conf entryだけを見れば接続許可の問題に見えます。しかし今回は、database "immich" does not existも同時に発生していました。複数のログとデータベース内部を照合したことで、単なるHBA設定変更では不十分だと判断できました。
メジャーバージョン移行では論理バックアップが強い
スナップショットは重要ですが、PostgreSQL 15から18のようなメジャーバージョン移行では、論理ダンプを新しいクラスタへ復元する方法が、状態を切り分けやすく、件数比較もしやすいと実感しました。
次回は完全な復旧手順を公開します
今回は、障害発生から判断、失敗、一時ロールバック、最終復旧までの流れを中心にまとめました。
第2弾では、実際に採用したPostgreSQL 15から18への復旧手順を、コマンドの目的、期待される結果、確認ポイント、失敗時の戻し方まで含めて整理します。
データベース復旧は、環境差を無視してコマンドを貼り付ける作業ではありません。まずバックアップを確保し、移行元を壊さず、1段階ずつ結果を確認する。それが今回、24,501件のアセットレコードを維持しながら復旧できた最大の理由でした。


コメント