Immichのセルフホスト設定とメモリ不足の回避策
ImmichをVPSで運用する際の注意点を解説します。メモリ4GB環境ではexit 137でプロセスがkillされるため、6GB以上のRAM確保が必須です。また、HTTPS設定やv3へのアップデート時にpgvecto.rsで発生する起動失敗の回避策、データの復元手順についても詳しく説明します。
作成するもの
Immichは、Google Photosの完全な代替となる、セルフホスト型の写真・動画バックアップサービスです。バックグラウンドでカメラロールをアップロードするモバイルアプリ、タイムライン、アルバム、顔認識機能を備えています。また、タグ付けなしで「beach」や特定の人物を検索できる機械学習検索機能も搭載しています。自身の所有するVPS上で動作するため、オリジナルファイルは自身のディスクに保存され、広告のためにスキャンされることもありません。
インストールは、プロジェクト独自の Docker Compose file を使用して4つのコンテナを起動するだけです。これには10分ほどかかります。このガイドの後半では、注意すべき問題点について説明します。機械学習コンテナはリソースの少ないサーバーではメモリを大量に消費します。オリジナルファイルはディスク容量を急速に圧迫します。モバイルアプリは HTTP 接続のみのサーバーでは動作しません。また、Immichは頻繁に破壊的変更を含むアップデートを行うため、不注意な docker compose pull によってデータベースが起動できなくなる可能性があります。これら4つの点に注意を払えば、Immichは非常に安定して動作します。これらを無視すると、作業に週末を費やすことになります。
前提条件と注意点
- RAM: 公式ドキュメントでは最小6 GB、推奨8 GBとされています。4 GBにswapを組み合わせた構成を最低ラインと考えてください。
immich-serverと Postgres コンテナの負荷は低いです。immich-machine-learningコンテナが最もメモリを消費します。検索インデックス作成のために CLIP と顔認識モデルを RAM に読み込むため、2 GB の環境では kernel によってプロセスが kill されます。4 GB 搭載している場合でも swap を追加してください。 - Disk: ライブラリ全体の容量に余裕を持たせたサイズを確保してください。 オリジナルファイルはそのままコピーされ、さらに Immich がサムネイルとプレビュー画像を生成します(元の容量の約10–20%が追加されます)。200 GB の写真コレクションには、300 GB のボリュームが必要です。Postgres のサイズはそれらに比べれば小さいです。
- CPU: 最近の KVM VPS であれば問題ありませんが、CPU による ML 処理は低速です。 大規模なインポート時の Smart-search インデックス作成は、バックグラウンドで数時間かかることがあります。これは正常な動作であり、GPU は必須ではありません。
- ドメイン名: VPS に紐付けられたものが必要です。モバイルアプリは HTTPS エンドポイントを強く推奨しており、リバースプロキシの設置が推奨されます。これは Docker、TLS、バックアップを備えた self-hosted Nextcloud インスタンス と同様の構成になります。Immich は、そのファイルサーバーに対する写真管理版の構成です。
- Docker および Compose plugin: インストール済みであること。Docker Compose basics guide で説明している通り、Docker Engine と Docker 公式の apt リポジトリから取得した Compose v2 plugin を使用してください。
Step 1: 最優先で swap を追加する
小規模な VPS で Immich が失敗する最も一般的な原因は、ML container が OOM-killed されることです。まず、kernel に余裕を持たせてください。
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
free -hfree -h には Swap: の 4.0Gi が表示されるはずです。これにより ML の速度が向上することはありませんが、4 GB のマシンでインデックス作成中に container が停止するのを防ぎます。
Step 2: 公式の compose と env を取得する — コピーではなく公式のものを使用してください
Immich は、同梱されているファイル内でサービスのバージョンと、特にデータベースのイメージを固定しています。ブログ(この記事を含む)からコピーした compose ファイルをソースとして使用しないでください。リリース資産をダウンロードしてください:
sudo mkdir -p /opt/immich && cd /opt/immich
sudo wget -O docker-compose.yml https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
sudo wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.envこれらはタグ付けされたリリースから取得されるため、イメージの参照が一致します。compose ファイルには 4 つのサービスが定義されています。作業を開始する前に、各サービスの内容を確認してください:
immich-server(ghcr.io/immich-app/immich-server, containerimmich_server) — API および Web UI。port2283で待機します。/dataにアップロードディレクトリをマウントします。immich-machine-learning(ghcr.io/immich-app/immich-machine-learning, containerimmich_machine_learning) — CLIP 検索および顔認識。ダウンロードしたモデルをmodel-cacheボリュームにキャッシュします。このサービスはメモリを多く消費します。database(containerimmich_postgres) — VectorChord ベクトル拡張を備えた Postgres。類似性検索を担います。イメージタグは compose ファイル内で digest によって固定されています(例:ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:...)。以前の構成ではpgvecto.rsが使用されていました。Immich v3.0 でそのサポートは削除されたため、現在インストールするものはすべて VectorChord です。このタグを直接編集しないでください。redis(containerimmich_redis) — ジョブキュー用の Valkey/Redis インスタンス。
Step 3: .env の設定 — 写真とデータベースの保存先
.env を開き、4つの項目を設定してください。下線の下の項目は変更不要です。
# Where original uploads are stored on the host
UPLOAD_LOCATION=/opt/immich/library
# Where the Postgres data lives. NEVER put this on an NFS/network share.
DB_DATA_LOCATION=/opt/immich/postgres
# "v3" is a floating tag that tracks the latest v3.x. Pin a full tag like
# v3.0.2 instead — then you upgrade on purpose, not by surprise.
IMMICH_VERSION=v3.0.2
# Change this to a long random string. Letters and digits only.
DB_PASSWORD=REPLACE_WITH_A_LONG_RANDOM_STRING
# Set your timezone so timestamps and "on this day" line up
TZ=Europe/London
###################################################################################
DB_USERNAME=postgres
DB_DATABASE_NAME=immichトラブルを防ぐための2つのルールがあります。UPLOAD_LOCATION は大容量ディスクを指定してください。後からデータボリュームを追加する場合は、最初からそのマウントパスを指定してください。後から変更すると、thumbnails の移動や asset path の更新が必要になります。また、DB_DATA_LOCATION はローカルディスクに設定してください。NFS や SMB シェア上の Postgres はデータが破損します。これは公式ドキュメントにも明記されています。DB_PASSWORD に英数字のみを使用すると、connection-string のエスケープに関するバグを回避できます。
Step 4: 初回実行と管理者ユーザーの作成
cd /opt/immich
sudo docker compose up -d
sudo docker compose ps正しく実行されると、4つのコンテナが起動し、すべて running かつ最終的に healthy になります。
NAME STATUS
immich_machine_learning Up (healthy)
immich_postgres Up (healthy)
immich_redis Up (healthy)
immich_server Up (healthy)最初の up は数GBのイメージをプルするため、時間がかかります。進捗は sudo docker compose logs -f immich-server で確認してください。準備が整うと、サーバーは port 2283 で listen していることをログに記録します。次に、ブラウザで http://YOUR_SERVER_IP:2283 を開いてください。初回アクセス時に Getting Started ウィザードが表示されます。最初に作成したアカウントが管理者(admin)になります。強力なパスワードを設定してください。このアカウントは、サーバー設定、ユーザー管理、および後で使用する ML 設定の権限を持ちます。
Step 5: モバイルアプリとバックグラウンドバックアップ
App StoreまたはPlay Storeから「Immich」をインストールしてください。ログイン画面でServer Endpoint URLの入力を求められます。スキームを含むフルURLを入力してください。例:https://photos.example.com(/apiはアプリが自動的に追加します)。作成したアカウントでログインし、アプリのBackup画面を開きます。バックアップするアルバム(通常はCameraとScreenshots)を選択し、Background backupを有効にします。iOSでは、OSによってバックグラウンドバックアップが制限されます。フォアグラウンドでのアップロードは常に実行されますが、バックグラウンドでの実行はOSが許可したタイミングで行われます。
ここで多くのユーザーが問題に直面します。アプリの設定で苦戦する前に、Step 6を読んでください。
Step 6: リバースプロキシによるHTTPS — とフルURLルール
モバイルアプリはHTTPSを必須とします。port 2283 の前にリバースプロキシを配置し、そこでTLSを終端させてください。すでに複数のコンテナを運用している場合は、複数のDockerアプリに自動TLSを適用するTraefik が最も効率的です。1つのlabelブロックで photos.example.com を immich-server コンテナへルーティングし、証明書を自動取得します。nginxを使用する場合は、Certbotとnginxを使用したLet's Encrypt のガイドに従って、証明書と proxy_pass http://127.0.0.1:2283; ブロックを取得してください。Immichにおいて重要なプロキシ設定が1つあります。アップロードサイズの上限を引き上げてください。スマートフォンの動画はサイズが大きいためです。nginxでは、server block内の client_max_body_size 50000M; を設定します。デフォルトの1 MBでは、413 Request Entity Too Large により動画のアップロードが拒否されます。
アプリが適用するルール:エンドポイントは到達可能である必要があり、実質的にHTTPSである必要があります。http:// エンドポイント、またはポート番号を除いた直接のIPアドレスを使用すると、「アプリがサーバーに接続できません」というエラーが発生します。これについては、以下の「名前付きエラー」のセクションで説明します。
Step 7: External libraries vs uploads — importing an existing photo tree
Immichへの写真の取り込み方法には、性質の異なる2つの方法があります。
- Uploads はImmichが管理するアセットです。アプリまたはWebアップローダーがファイルを
UPLOAD_LOCATIONにコピーします。Immichはこれらのファイルを名前変更、移動、削除できます。 - External libraries は、サーバー上のフォルダに既に存在するファイル(古い
PicturesツリーやNASからのエクスポートなど)を読み取り専用でインポートする機能です。Immichはそれらをその場所でインデックス化してタイムラインに表示しますが、元のファイルを変更または削除することはありません。
既存のツリーをインポートするには、サーバーコンテナにそのディレクトリを読み取り専用でマウントしてください。immich-server: 内の docker-compose.yml を編集し、volumeを追加します。
immich-server:
volumes:
- ${UPLOAD_LOCATION}:/data
- /etc/localtime:/etc/localtime:ro
- /srv/photos:/mnt/media/photos:ro:ro により、Immichが元のファイルに触れることはなくなります。sudo docker compose up -d を使用してコンテナを再作成してください。その後、Web UIでアバターアイコン → Administration → External Libraries → Create Library に進みます。所有ユーザーを選択し、Folders の Add をクリックして、コンテナ内のパス(ホストパスの /srv/photos ではなく /mnt/media/photos)を入力してください。最後に Scan をクリックします。ホストパスではなくコンテナパスを使用していないことが、External Librariesにおける最も一般的な間違いです。この場合、スキャン結果は0件となり、アセットが何も見つかりません。
Step 8: Immichに求められるアップグレードの規律
この手順は、Immichを正常に動作させ続けるために不可欠です。Immichは開発速度が速く、古いバージョンへの修正のバックポートや、ダウングレードのサポートは行われません。v3 タグを無計画に追従すると、最終的にデータベースが破損します。以下の規律を守ってください。
- バージョンを固定する。
IMMICH_VERSIONを、常に最新の v3.x を取得してしまうv3ではなく、v3.0.2のような具体的なタグに設定してください。 - アップグレードの際は必ずリリースノートを確認する。 破壊的変更(特にデータベースや vector-extension に関するもの)は、そこに記載されています。v3.0 のリリースが分かりやすい例です。このバージョンでは pgvecto.rs が完全に削除されたため、古い拡張機能を使用しているユーザーは、アップグレード前に VectorChord への移行(v1.133 で導入)を完了させる必要がありました。
- まずデータベースのバックアップを取る (Step 9)。常に必要ですが、リリースノートにデータベースに関する記述がある場合は特に重要です。
- 新しい compose ファイルも取得する。
IMMICH_VERSIONは server と ML のイメージのみを固定します。Postgres のイメージはdocker-compose.yml内の digest によって固定されているため、新しいデータベース拡張が必要なバージョンでは、新しい compose ファイルが提供されます。両方のリリース資産を再ダウンロードし、.envの値を再適用してからアップグレードしてください。 - モバイルクライアントも同時期にアップデートする。 サーバーは、対応するメジャーバージョンとしか通信できません。アプリは、現在のメジャーバージョンと、その一つ前のメジャーバージョンをサポートしています。サーバーのバージョンがアプリより進んでいると、アプリには
Your app major version is not compatible with the server!が表示されます。そのため、先にアプリをアップデートするのが最も安全です。
新しいファイルが準備できた後の実際のコマンドは以下の通りです:
cd /opt/immich
sudo docker compose pull
sudo docker compose up -d
sudo docker image pruneStep 9: バックアップ — データベースのダンプとオリジナルファイルの両方、およびそのテスト
Immichのバックアップは2つの要素で構成されます。片方だけでは機能しません。databaseには、アルバムの構造、顔認識データ、検索インデックス、およびアセットとファイルへのマップが保存されています。originals directoryには、実際の写真が保存されています。片方だけをリストアすると、整理されていない写真のみの状態になるか、ファイルが見つからない空の構造のみの状態になります。
Postgresコンテナ内から pg_dump を使用して、データベースをダンプします。クラスター全体ではなく、特に immich データベースを指定してください。
sudo docker exec -t immich_postgres pg_dump --clean --if-exists \
--dbname=immich --username=postgres | gzip > /opt/immich/immich-db-$(date +%F).sql.gz次に UPLOAD_LOCATION をバックアップします。/opt/immich/library ツリー全体、特にその library/、upload/、および profile/ サブフォルダを、restic、rsync、または borg を使用して別のマシンやオブジェクトストレージに保存します。データベースを先に、ファイルを後に行うようにしてください。これにより、ダンプがまだコピーされていないファイルを参照することを防げます。外部ライブラリは、元のソースで別途バックアップしてください。Immichはそれらを管理していません。
次に、多くの人が見落とす工程があります。リストアのテストです。リストアは、サーバーが一度も起動していない「新規」のスタックに対して行う必要があります。また、Postgresイメージのvector拡張機能がダンプと互換性があることを確認してください。そのため、DBのイメージタグを適当に選んではいけません。同じcomposeと .env を持つ空の環境で、古い状態を削除し、データベースのみを起動してから、ダンプをロードします。
cd /opt/immich
sudo docker compose down -v
sudo docker compose pull
sudo docker compose create
sudo docker start immich_postgres
sleep 10
gunzip --stdout immich-db-2026-07-15.sql.gz |
sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" |
sudo docker exec -i immich_postgres psql --dbname=immich --username=postgres --single-transaction --set ON_ERROR_STOP=on
sudo docker compose up -dVectorChordデータベースを使用する場合、search_path の sed 書き換えは必須です。これを行わないと、リストアが途中で失敗します。オリジナルファイルが配置された状態でスタックが起動したら、Web UIを開いてください。写真とアルバムが表示されれば、バックアップは成功です。これを一度も実行していない場合、それはバックアップではなく、単なる「期待」に過ぎません。
発生するエラーと表示される文字列
ML container が OOM-killed になる。 sudo docker compose logs immich-machine-learning が突然終了し、docker compose ps に Restarting と表示され、exit code は 137 になります。sudo dmesg | grep -i oom がそれを裏付けます: Out of memory: Killed process ... (python3)。これにより、Search および Face ジョブが停止します。原因は、モデルに対して RAM が不足していることです。解決策は以下の通りです:swap を追加する (Step 1)、VPS の RAM を増設する、または、どうしても不可能な場合は Administration → Settings → Machine Learning Settings で Smart Search と Facial Recognition をオフにして ML を無効化します。この場合、バックアップとアルバムは保持されますが、内容による検索機能は失われます。compose file から immich-machine-learning サービスを削除しても同様の結果になります。
アップグレード後に Postgres が起動しない。 サーバーログに The database currently has VectorChord 0.5.3 activated, but the Postgres instance only has 0.4.2 available. This most likely means the extension was downgraded. のような行が繰り返し表示されます。古いスタックの場合は The pgvecto.rs extension is not available in this Postgres instance. と表示されます。原因は、データベースのイメージの拡張バージョンが、アップグレード済みのデータよりも古いことです。これは、イメージタグを手動で編集した場合や、新しいダンプを古いイメージにリストアした場合にほぼ必ず発生します。解決策は、一致する Postgres イメージを使用することです。データベースと一致するリリースの compose file を使用してください。ダウングレードはせず、互換性のあるイメージに対してのみリストアを行ってください。
モバイルアプリがサーバーに接続できない。 URL 入力後、ログイン画面に connection error / Server is not reachable と表示されます。原因は3つあります:プロキシが https:// のみをサービスしている場所に http:// と入力した、ポートを指定せずにバックエンドに直接接続したため example.com:2283 ではなく example.com (port 443) に接続しようとした、またはリバースプロキシが /api を転送していない、のいずれかです。解決策として、完全な https://photos.example.com URL を入力し、まずスマートフォンのブラウザで読み込めるか確認してください。ブラウザで動作しアプリで動作しない場合は、プロキシがパスを削除しているか、証明書が自己署名です。アプリは信頼できない証明書を拒否します。
インポート中にディスク容量が不足する。 アップロードが失敗し始め、サムネイルが空白になり、ログに ENOSPC: no space left on device または Postgres から could not extend file ... No space left on device と表示されます。df -h は UPLOAD_LOCATION ボリュームが 100% であることを示します。大規模なライブラリをインポートする前にディスク容量を確保すべき理由はこれです。解決策は、より大きなボリュームをアタッチし、スタックを停止して、UPLOAD_LOCATION をそこへ移動し、.env を更新して再開することです。または、プロバイダーが許可している場合は既存のディスクを拡張してください。容量がいっぱいになると Postgres が停止する可能性があるため、データの破損を疑う前に、空き容量を確保してデータベースコンテナを再起動してください。
FAQ
Immichに必要なRAMとディスク容量は?
Immichの公式要件は、最小6 GBのRAM、推奨は8 GBです。小規模なライブラリであれば、swapを含めて4 GBが実用的な下限となります。machine-learningコンテナがリソースを急激に消費するため、必ずswapを設定してください。ディスク容量については、ライブラリ全体のサイズに、サムネイルとプレビュー用に10–20%を加えた分をローカルストレージに用意してください。Postgresのデータディレクトリをネットワーク共有に配置しないでください。他のセルフホストサービスと比較したい場合は、2026年にセルフホストすべきサービスガイドでImmichの負荷を確認できます。
GPUなしでImmichを実行できますか?
はい。machine-learningコンテナはCPUのみでも動作します。GPUは、smart-searchのインデックス作成と、適切なイメージを使用した場合のビデオトランスコードを高速化するだけです。CPUを使用する場合、大規模なライブラリの初回インデックス作成にはバックグラウンドで数時間かかることがありますが、バックアップやブラウジングを妨げることはありません。マシンにMLを実行する余裕がない場合は、管理設定でSmart SearchとFacial Recognitionを無効にすれば、他の機能はそのまま利用できます。
Immichを安全にアップグレードする方法は?
IMMICH_VERSIONをv3.0.2のような特定のタグに固定してください。アップグレードの前に必ずリリースノートを確認し、まずデータベースのバックアップを取ってください。PostgresのイメージはIMMICH_VERSIONではなくdocker-compose.yml内で固定されているため、対象のリリースからcomposeファイルとexample.envの両方を再ダウンロードし、設定値を再適用してからdocker compose pull && docker compose up -dを実行してください。バージョンを放置して自動更新させないでください。Immichには破壊的変更が含まれることがあり、ダウングレードはサポートされていません。
バックアップすべき対象は?
pg_dumpのimmichデータベースと、UPLOAD_LOCATIONのoriginalsディレクトリ全体、この2つをセットでバックアップしてください。データベースにはアルバム、顔、アセットとファイルの紐付け情報が含まれます。ディレクトリには実際の写真が含まれます。リストアには、これら両方に加えて、互換性のあるvector拡張機能を持つデータベースイメージが必要です。データベースのダンプを先に行い、次にファイルのコピーを行ってください。また、テスト用の環境で少なくとも一度はリストアのテストを行ってください。テストされていないバックアップは、バックアップとは言えません。
既存の写真フォルダをインポートする方法は?
インポートしたいフォルダを、追加のボリューム(例:- /srv/photos:/mnt/media/photos:ro)としてimmich-serverコンテナに読み取り専用でマウントしてください。コンテナを再作成した後、Administration → External Librariesからライブラリを作成し、コンテナ内のパスである/mnt/media/photosを追加してください。Immichはファイルをその場でインデックスするだけで、元のファイルを変更または削除することはありません。最も多い間違いは、コンテナ内のパスではなくホストのパスを入力することです。その場合、スキャンしてもファイルが見つかりません。