Immich を 4GB の VPS で動かす: Google フォトから移行して、機械学習と日本語検索まで実測
Google フォト代替の Immich v3 を 4GB の VPS に Docker で立て、Google Takeout から immich-go で移行し、Pixel から自動バックアップするまでを実機で試しました。機械学習なし・あり・多言語モデルのメモリ実測と、日本語で検索できるようにする設定まで。
本記事にはプロモーション (アフィリエイト広告) が含まれます。
「Immich の使い方」「Google フォトから移したい」「VPS で動くのか」と調べている人向けに、先に結論を置きます。
Immich は月 2,480 円の 4GB の VPS でも動きます。Google フォトからの移行は、撮影日時・位置情報・Pixel のモーションフォトまで保ったまま、79 件 (写真 71 枚と動画 8 本) が 6 秒で終わりました。 顔認識や「花火」で探せる検索 (機械学習) も、公式の最小要件 (6GB) を下回る 4GB で動きました。ただし余裕はありません。日本語で検索できる多言語モデルに替えると、スワップを 2GB 中 1.5GB まで使いました。
私の結論は、写真が数百〜数千枚で、機械学習を使うなら 4GB は「動くが、ぎりぎり」、本格的に使うなら 8GB です。以下、その数字を順に見せます。
Immich とは
Google フォトとほぼ同じことを、自分のサーバーで動かすためのオープンソースのソフトです。2022 年に始まり、2025 年 10 月に安定版の v2、2026 年 7 月に v3 が出ました。GitHub のスターは 11.5 万あります (2026-09-23 時点)。
- スマホのアプリから、写真を自動でバックアップ
- タイムライン、アルバム、地図、共有リンク
- 顔でまとめる、写真の中身を言葉で検索する (機械学習)
- 家族のアカウントを分けて、1 台で共有
流行っている理由は、私の見立てでは 3 つです。1 つ目は、写真の保管に月額を払い続ける形になったことです。Google フォトは 2021 年 6 月に無料の容量無制限が終わり、iCloud も無料は 5GB です。写真は増える一方なので、払う額も毎年増えます。2 つ目は、自前でも Google フォトと同じ使い心地になったこと。3 つ目は、家族の写真を他社に預けることへの不安です。
逆に言うと、バックアップの責任も自分に来ます。これは最後の「バックアップ」の節で扱います。
この記事で使う環境
- VPS: XServer VPS クラウド 4GB (4 コア / NVMe 50GB)、Ubuntu 24.04。初期設定 と Tailscale が済んだ状態。同じ VPS に Claude Code の常駐エージェントが動いていて、それだけで 700MB ほど使っている
- Immich: v3.2.2
- Docker: 29.8.1、Compose v5.5.1
- スマホ: Pixel 7a (Android)。Google フォトのバックアップをオンにして使っていた
- 移行した写真: Google フォトの「2026 年の写真」(写真 71 枚、動画 8 本、1.37GB)
公式の要件と、この記事の結論
公式の要件 は、RAM が最小 6GB・推奨 8GB、CPU が最小 2 コア・推奨 4 コアです。ただし「機械学習を無効にすれば 4GB でも動く」と書かれています。サムネイルと変換した動画で、ライブラリの容量は平均 10〜20% 増えるそうです。
4GB の VPS で実際に測った結果を、先に表にしておきます (常駐エージェントの 700MB 込み)。
| 状態 | VPS 全体の使用 | 残り | スワップ |
|---|---|---|---|
| 機械学習なし、待機中 | 2.1GB | 1.7GB | 25MB |
| 機械学習なし、動画の変換中 | 2.6GB | - | 731MB |
| 機械学習あり (英語モデル)、296 枚の処理中 | 3.2GB | 0.6GB | 816MB |
| 機械学習あり (多言語モデル)、296 枚の処理中 | 3.5GB | - | 1.48GB |
| 機械学習あり、待機中 | 2.7〜3.3GB | 0.6〜1.1GB | 0.8〜1.3GB |
1. Docker を入れて、Immich を立てる
Docker は公式のインストーラーで入れます。
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER # 入り直すと sudo なしで docker が使える
Immich は、公式がリリースごとに docker-compose.yml と .env の雛形を配っています。
mkdir -p ~/immich-app && cd ~/immich-app
V=v3.2.2
curl -fsSL -o docker-compose.yml https://github.com/immich-app/immich/releases/download/$V/docker-compose.yml
curl -fsSL -o .env https://github.com/immich-app/immich/releases/download/$V/example.env
書き換えるのは 2 か所です。
1. ポートを 127.0.0.1 に束縛する。雛形は '2283:2283' で、これだと Docker が ufw を迂回して、インターネット側に 2283 番を開けてしまいます。
sed -i "s/ - .2283:2283./ - 127.0.0.1:2283:2283/" docker-compose.yml
2. .env の DB のパスワードとタイムゾーン。パスワードは雛形のままだと postgres です。
PW=$(openssl rand -hex 24)
sed -i "s/^DB_PASSWORD=postgres$/DB_PASSWORD=$PW/; s/^IMMICH_VERSION=v3$/IMMICH_VERSION=v3.2.2/; s/^# TZ=.*/TZ=Asia\/Tokyo/" .env
chmod 600 .env
IMMICH_VERSION は、雛形の v3 のままだと、docker compose pull のたびに v3 の最新に上がります。私は検証の再現のために v3.2.2 に固定しました。
まずは機械学習なしで起動する
compose には 4 つのサービスがあります。本体 (immich-server)、機械学習 (immich-machine-learning)、DB (database)、キャッシュ (redis) です。機械学習以外の 3 つだけを起動します。
docker compose up -d immich-server redis database
イメージの取得を含めて、90 秒で応答するようになりました。イメージの大きさは、本体 2.5GB、DB 1.0GB です。
| コンテナ | 起動直後 | 2 分後 |
|---|---|---|
| immich_server | 1.34GB | 868MB |
| immich_postgres | 540MB | 369MB |
| immich_redis | 13MB | 15MB |
Tailscale の中だけに HTTPS で出す
n8n の記事 と同じ方法です。ループバックの 2283 番を、tailnet の中だけに HTTPS つきで出します。インターネット側には出しません。
sudo tailscale serve --bg 2283
これで、Tailscale につないだ端末から https://<VPS の名前>.<tailnet 名>.ts.net で開けます。
2. 初期設定
最初に開くと、管理者の登録画面です。

メールアドレスは、ログインの ID に使われるだけです。メールサーバーを設定しない限り、Immich からメールが送られることはありません。私は crz33@immich.local という架空のアドレスにしました。パスワードを忘れても、VPS で docker exec -it immich_server immich-admin reset-admin-password を打てば戻せます。
ログインすると、v3 では初期設定の案内が 7 画面続きます。迷ったのは次の 3 つです。
- サーバープライバシー: 地図の画像 (
tiles.immich.cloud) と、新しい版の確認 (version.immich.cloud) の 2 つの外部通信を使うか。写真そのものは外に出ません。地図は便利なのでオンのままにしました - ユーザープライバシー (Google Cast): テレビに写真を映す機能です。オフのままにしました。Tailscale の中にしかない Immich には、Tailscale に入っていないテレビからは届かないので、オンにしても動かない可能性が高いです
- ストレージテンプレート: 写真ファイルを VPS のディスクにどう並べるか。オフだと Immich が決めた ID のフォルダに置かれ、オンだと
2026/2026-09-06/PXL_20260906_063437169.jpgのように「年 / 日付 / 元のファイル名」で置かれます

ストレージテンプレートは オン をおすすめします。Immich をやめたくなったときや、ディスクごと別の場所に写すときに、Immich なしでも写真が日付のフォルダに並んでいるからです。途中で切り替えると既存のファイルを移し直す処理が走るので、写真を入れる前に決めておくのが楽です。ただし、後で書くように、取り込み直後にちょっとした副作用がありました。
機械学習をオフにする
機械学習のコンテナを起動していないので、設定でもオフにします。オンのままだと、ログに「Machine learning server became unhealthy」が出続けます。
右上のアイコン →「管理」→「設定」→「機械学習設定」の、「機械学習の有効化」をオフにします。

3. Google フォトから移す (Takeout + immich-go)
Takeout で書き出す
Google Takeout で、Google フォトだけを書き出します。「選択をすべて解除」してから Google フォトにチェックを入れ、「すべてのフォト アルバムが含まれます」から書き出すアルバムを選びます。

「Photos from 2026」のような項目は、自分で作ったアルバムではなく、Takeout が撮影年ごとに分けたものです。「Archive」はアーカイブした写真、「Trash」はゴミ箱です。私は検証のために 2026 年の分だけにしました。
形式は .zip、サイズは 2GB のまま、「1 回のエクスポート」で作成します。画面には「数時間から数日かかることがある」と出ましたが、1.37GB は 10 分ほど で完了のメールが来ました。ダウンロードのリンクは 1 週間で切れます。
zip の中は、写真 71 枚 (JPEG)、動画 8 本、.MP という拡張子のファイル 24 本、それに写真ごとの JSON が 79 本でした。JSON には撮影日時・位置情報・アルバムなどが入っています。
zip を VPS に送る
Mac から Tailscale 経由で scp しました。1.37GB に 27 分 (毎秒 0.9MB) かかりました。経路は中継ではなく直結でしたが、送っている間は往復の遅延が 150ms まで膨らんでいました。自宅の回線の上りが詰まっていたのだと思います。全部の写真を移すなら、この転送が一番時間のかかる工程になります。
immich-go で取り込む
immich-go は、写真をまとめて Immich に入れるコマンドラインのツールです。Immich の開発元ではなく、個人の開発者が作っているオープンソースです。Takeout の zip を展開せずに読み、写真と JSON を突き合わせて、撮影日時・位置・アルバムを保ったまま入れてくれます。Immich の画面から写真だけを上げると、この JSON は使われません。
入れ方は、Linux 用のバイナリを置くだけです。
curl -fsSL -o /tmp/immich-go.tgz https://github.com/simulot/immich-go/releases/download/v0.32.0/immich-go_Linux_x86_64.tar.gz
tar xzf /tmp/immich-go.tgz -C /tmp immich-go && mv /tmp/immich-go ~/.local/bin/
immich-go が Immich に写真を入れるには、API キー が要ります。プログラムにパスワードを渡す代わりの、いつでも取り消せる専用の鍵です。Immich の画面で、右上のアイコン →「アカウント設定」→「API キー」→「新しい API キー」から作ります。

immich-go はアップロードのほかに、アルバムの作成や撮影日時の書き換えもするので、権限は「全て選択」にしました。移行が終わったら、このキーは消します。
まず --dry-run で、何が入るかを確かめます。
immich-go upload from-google-photos --server=http://127.0.0.1:2283 --api-key=<API キー> --dry-run --no-ui takeout-*.zip
Discovery (Assets):
discovered image : 71 (328.8 MB)
discovered video : 8 (990.7 MB)
Discovery (Non-Assets):
discovered sidecar : 79 (73.3 KB)
discovered unknown file : 24 (79.7 MB)
Processing Events:
associated metadata : 79
写真と動画の 79 本すべてに、JSON (sidecar) の対応が取れています。気になるのは、.MP の 24 本が「unknown file」として外れていることです。これは後で説明します。問題ありませんでした。
--dry-run を外して本番です。
Total Assets: 79 (1.3 GB)
Processed: 79 (1.3 GB)
Errors: 0 (0 B)
同じ VPS の中のアップロードなので、6 秒 で終わりました。そのあと、Immich がサムネイルを作り、動画を変換します。この 2 分ほどの間、本体のコンテナは CPU を 364% (4 コアのほぼすべて) 使い、メモリは 1.73GB まで膨らみ、スワップに 731MB はみ出しました。機械学習なしでも、動画の変換は重い処理です。
ディスクは、元の 1.37GB が、サムネイルと変換後の動画込みで 1.8GB になりました。公式の「10〜20% 増える」より多い 3 割増しで、動画が多いとその分増えるようです。
移行の結果
撮影日は 2026-04-26〜09-19 の範囲で正しく並び、79 枚すべてに位置情報が残って、市区町村まで表示されました。地図には旅行先の写真がそのまま並んでいます。

Pixel のモーションフォトも、動く写真のまま移せました。 さっき外れた .MP は、動画の部分だけを Takeout が別に書き出したものです。同じ名前の .MP.jpg の後ろにも、まったく同じ大きさ (私が調べた 1 枚では 2,426,786 バイト) の動画が埋め込まれていました。Pixel のモーションフォトは、JPEG の後ろに動画をつなげた形式です。Immich はこの JPEG から動画を取り出して、24 枚すべてを動く写真として表示しました。
4. Pixel から自動でバックアップする
Google Play で Immich のアプリを入れ、サーバーの URL に https://<VPS の名前>.<tailnet 名>.ts.net を入れてログインします。スマホにも Tailscale が入っていて、つながっている必要があります。
最初の起動で写真へのアクセスを「許可しない」にすると、バックアップの画面で「アルバムが見つかりません」と出ます。Android の「設定」→「アプリ」→「Immich」→「権限」→「写真と動画」を 「常にすべて許可」 にして、アプリを開き直してください。「選択した写真と動画のみ」にすると、選んだものしかバックアップされません。
アルバムの選択で「Camera」(Pixel で撮った写真) を選びます。

バックアップの画面を開くと、こう出ました。

Takeout で入れた 79 枚を、アプリが「バックアップ済み」と数えています。 同じ写真が、Google Takeout と Pixel という別の経路から来ても、二重には入りません。Immich は写真の中身から計算した値で同じものを見分けるからです。残りの 217 件だけが上がりました。
217 件 (5GB ほど) のバックアップには、1 時間ほどかかりました。途中で 20 分ほど止まっていた時間があり、アプリが画面の裏に回っていた間だと思います。アプリには「バッテリーの最適化を無効にすると、バックグラウンドのバックアップの信頼性が上がる」と案内が出ていました。私は最適化をオンのままにしていたので、そのせいで止まった可能性があります。
アップロードしている間は、ブラウザの Immich の動きもカクカクしました。このときサーバーの CPU は 98% が空いていたので、重かったのはサーバーではなく、自宅の回線の上りだと思います。最初のまとめてのバックアップは、使わない時間に流すのが良さそうです。
終わった時点で、タイムラインは 296 件 (写真 248、動画 48) になりました。元のファイルは 6.09GB、サムネイルと変換後の動画込みで 7.5GB (2 割強増し) です。
5. 機械学習を 4GB で動かす
ここからは、公式の最小 (6GB) を下回る領域です。機械学習のコンテナを起動し、設定を戻して有効にします。
docker compose up -d immich-machine-learning
イメージは 1.38GB、起動は 32 秒でした。標準で使われるモデルは 3 つです。
| 機能 | モデル |
|---|---|
| 言葉での検索 (スマート検索) | CLIP ViT-B-32__openai |
| 顔検出・顔認識 | buffalo_l |
| 写真の中の文字の読み取り (OCR) | PP-OCRv5_mobile |
管理画面の「待機中のジョブ」から、スマート検索・顔検出・OCR を実行します (私は API から実行しました)。モデルは初回だけ Hugging Face からダウンロードされるので、最初の 1 分ほどは何も進みません。
296 件の処理は 4 分半 (モデルのダウンロード込み) で終わりました。
| 項目 | 値 |
|---|---|
| VPS 全体の使用メモリの最大 | 3.2GB (3.8GB 中) |
| スワップの最大 | 816MB |
| 機械学習のコンテナの最大 | 1.1GB、CPU 318% |
| 強制終了・再起動 | なし |
顔は 18 人に分けられました。検索は、「sea」「cooking」では狙った写真が上に来ました。ところが「海」では当たりません。 標準の CLIP のモデルは、英語の文章と画像の組み合わせで学習されているからです。
処理が終わっても、機械学習のコンテナは 1GB 近くを持ったままでした。モデルは「300 秒使われなければメモリから外す」設定です。それでも 10 分以上たって 965MB を持っていた理由は、確かめていません。待機中でも VPS 全体で 2.7GB を使い、残りは 1.1GB です。
日本語で検索できるようにする
Immich は、多言語対応の CLIP のモデルに替えられます。公式のドキュメント には、日本語の精度つきで 3 つが載っていました。
| モデル | メモリ (公式の表) | 日本語の精度 (公式の表) |
|---|---|---|
XLM-Roberta-Large-ViT-H-14 |
4,014MiB | 83.95% |
nllb-clip-base-siglip__v1 |
4,675MiB | 78.72% |
XLM-Roberta-Base-ViT-B-32 |
3,030MiB | 75.93% |
4GB で試すなら、一番軽い XLM-Roberta-Base-ViT-B-32 です。管理 →「設定」→「機械学習設定」→「スマート検索」のモデル名を XLM-Roberta-Base-ViT-B-32__laion5b_s13b_b90k に替えて、スマート検索のジョブを「すべて」でやり直します (私は API で設定を変え、ジョブを実行しました)。
| 項目 | 英語のモデル | 多言語モデル |
|---|---|---|
| 296 件の処理時間 (ダウンロード込み) | 4 分半 (顔・OCR 込み) | 3 分 (検索だけ) |
| VPS 全体の使用メモリの最大 | 3.2GB | 3.5GB |
| スワップの最大 | 816MB | 1.48GB (2GB 中) |
| 機械学習のコンテナの最大 | 1.1GB | 1.9GB |
| 強制終了 | なし | なし |
「海」「花火」「料理」が、日本語で当たるようになりました。 ただし、スワップが 2GB のうち 1.5GB まで埋まりました。あと 500MB 足りなければ、どれかのプロセスが強制終了されていたはずです。処理が終わった後も、残りのメモリは 580MB、スワップは 1.3GB 使ったままでした。296 枚でこの状態なので、数千枚を流すと、この張り詰めた状態が長く続きます。
6. バックアップ
Immich には、DB を自動で書き出す機能が最初からオンになっています。設定を見ると、毎日 2:00 に書き出して 14 日分を残す、となっていました。保存先は library/backups です。
注意したいのは、写真も DB のバックアップも、同じ VPS のディスクの中にある ことです。VPS ごと失えば両方消えます。初期設定の案内でも、「3-2-1 バックアップ」(3 つ持つ、2 つは別々の機器、1 つは別の場所) が勧められていました。UPLOAD_LOCATION のフォルダ (この記事では ~/immich-app/library) を丸ごと、手元の PC や別のクラウドに定期的に写してください。
7. 止める・更新する
止めるとき (写真と DB はディスクに残ります):
cd ~/immich-app && docker compose stop
更新するときは、リリースノートで「breaking changes」を確かめてから、.env の IMMICH_VERSION を新しい版に書き換えて取り込み直します。
docker compose pull && docker compose up -d
つまずいた点
- 雛形の compose がインターネットに 2283 番を開ける。
'2283:2283'のままだと、Docker が ufw を迂回します。127.0.0.1:2283:2283に直して、公開は Tailscale の中だけにしました - 取り込み直後に、サムネイルが 42 件欠けた。写真は開けるのに、一覧では「画像の読み込みエラー」になりました。ログを見ると、ストレージテンプレートでファイルを「年/日付」のフォルダへ移す処理と、サムネイル作成が同時に走り、サムネイル側が移動前の場所を読みに行って「File not found」になっていました。モーションフォトの動画を取り出す処理でも「file already exists」の衝突が出ていました。サムネイル生成のジョブを「欠落分だけ」でもう一度走らせると、全部直りました (私は API から実行しました)
- Takeout の
.MPが「unknown file」で外れる。慌てましたが、中身はモーションフォトの動画の部分で、同じものが JPEG の中にも入っていました。Immich は JPEG から取り出して、動く写真として表示します - スマホのアプリで写真へのアクセスを拒否すると、アルバムが見つからない。Android の設定から「常にすべて許可」に直します
- 自宅からのアップロードが遅い。Mac からの zip の転送は毎秒 0.9MB、Pixel からのバックアップも毎秒 1〜2MB ほどでした。その間はブラウザの Immich の操作も重くなります
- 標準の検索は日本語が効かない。多言語モデルに替えると効きますが、メモリをさらに使います
- 機械学習のモデルは、初回にダウンロードされる。ジョブを始めても最初の 1 分ほど何も進まないのは、Hugging Face からモデルを取ってきているからです
Docker を入れてから、移行、スマホのバックアップ、機械学習と多言語モデルの計測まで、全部で 4〜5 時間でした。ほとんどは転送とバックアップの待ち時間 (zip の転送とスマホのバックアップ) で、それを除けば、手を動かしていたのは 30 分ほどです。
次にやること
libraryフォルダを、手元の Mac に定期的に写す仕組みを作る- 8GB のプランで、機械学習ありの常用と、大きい多言語モデルの精度を比べる
- 写真と動画が 1 万枚を超えたときの、初回の機械学習の処理時間を測る
まとめ
- Immich v3 は 4GB の VPS で動く。機械学習なしなら、待機中の使用は 2.1GB で余裕がある
- 機械学習 (顔・検索・OCR) も 4GB で動いたが、スワップを 800MB 使う。日本語で検索できる多言語モデルでは 1.5GB 使い、ぎりぎり
- Google フォトからは、Takeout + immich-go で、撮影日時・位置情報・モーションフォトを保ったまま移せる
- 同じ写真を Takeout とスマホの両方から入れても、重複しない
- 標準の検索は英語だけ。日本語で探したいなら
XLM-Roberta-Base-ViT-B-32などの多言語モデルに替える - 写真も DB も、VPS の同じディスクにある。VPS の外にも写すこと
- 数千枚以上を機械学習ありで常用するなら、8GB のプランが安全