写真をGoogle PhotosからImmichに移す
Googleフォトの全データを自前サーバー(Immich)に移行した時の記録。docker-composeでのImmich構築、immich-goの実際のコマンド、Takeoutの分割zipで踏んだ罠、本番実行の結果まで、同じ環境を再現できる粒度で書いた。
- 公開日:
- 2026-08-24
- 最終更新日:
- 2026-09-13
Google Photosの全データ(3万件超、約119GB)を自前サーバー上のImmichというソフトに移した記録。前回の版は「何をしたか」の日記だったが、今回は実際に打ったコマンドやファイルの中身まで含めて書き直した。この記事だけで、自分がやったのと同じ環境を一から再現できることを目指している。
前提: このガイドで想定している環境
以下がすでに用意できていることを前提にする。まだの場合は先に自分の「サーバー」を持つとはどういうことかを読んでほしい。
- 常時起動しているLinux環境(自分の場合はWindows機の中でWSL2〈Windows Subsystem for Linux 2、WindowsのなかでLinuxをそのまま動かす仕組み〉のUbuntu)
- Docker Engine(コンテナ、つまりソフトを隔離された箱に入れて動かす仕組み)と、そのおまけ機能である
docker compose(複数のコンテナ設定をまとめて起動・停止するコマンド)が使える状態 - ターミナル(文字でコマンドを打ち込む黒い画面)の基本操作に抵抗がないこと
GPU(グラフィック処理用の高性能な部品)は必須ではない。無くても写真の保管・閲覧は問題なくでき、違うのは顔認識やスマート検索(自然言語でのあいまい検索)の処理速度だけ。自分はたまたま手元にゲーミングPC(GeForce RTX 3070搭載)があったのでGPUを使う構成にした。GPUを使わない場合は、後述の「GPUを使う場合の追加設定」を丸ごと飛ばして進めて構わない。
Step 1: Immichをdocker-composeで動かす
まず作業用フォルダを作り、Immich公式が配布している設定ファイル一式をダウンロードする。
mkdir ~/immich && cd ~/immich
curl -fL -o docker-compose.yml https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
curl -fL -o .env https://github.com/immich-app/immich/releases/latest/download/example.env
curl -fL -o hwaccel.ml.yml https://github.com/immich-app/immich/releases/latest/download/hwaccel.ml.yml
ここで一度ハマった: curlに-L(リダイレクト追従、GitHubのようにURLが転送される先でファイルを配っているサイトでは必須)を付け忘れて、中身が0バイトのファイルができてしまったことがあった。-fL(-fはエラー時に空ファイルを作らず失敗させる、-Lはリダイレクト追従)の組み合わせで取り直して解決した。
次に.envファイルを編集する。最低限、以下の2点は必ず変更する。
DB_PASSWORD— デフォルトのままだと誰でも推測できるパスワードなので、自分だけの値に変更するUPLOAD_LOCATION— 写真の実ファイルをどこに保存するかの場所。デフォルトの./library(このフォルダの中のlibraryサブフォルダ)のままで問題ない
セットアップ中に出てくる「Storage Template」という機能(保存されるファイルの命名・フォルダ構造を人間が読みやすい形に変える機能)は、オフのままにすることを勧める。写真の閲覧はどのみちImmichの画面経由が前提になるので、生ファイルの構造を人が読みやすくする必要性が薄いことと、後から有効化すると全件の再整理ジョブが走って重くなることが理由。
準備ができたら起動する。
docker compose up -d
docker compose ps
immich_server / immich_machine_learning / database(PostgreSQL) / redisの4つのコンテナがhealthy(正常稼働)と表示されれば成功。ブラウザでhttp://localhost:2283(自宅サーバーの場合はサーバーのIPアドレスに読み替える)を開き、管理者アカウントを作成する。
GPUを使う場合の追加設定(任意)
顔認識・スマート検索をGPUで高速に処理したい場合は、上記のdocker compose up -dの前に以下を行う。
- WSL2からGPUが見えることを確認する:
nvidia-smi(GPUの状態を表示するNVIDIA公式コマンド)を実行し、GPU名やドライバのバージョンが表示されればOK - NVIDIA Container Toolkit(DockerコンテナからGPUを使えるようにする橋渡しソフト)を導入し、
nvidia-ctk runtime configure --runtime=dockerで設定を反映 docker run --rm --gpus all ubuntu nvidia-smiを実行し、コンテナの中からもGPUが見えることを確認するdocker-compose.ymlのimmich-machine-learningサービスを編集: イメージタグの末尾に-cudaを追加し、コメントアウトされているextends: file: hwaccel.ml.yml / service: cudaの行を有効化(元はservice: cpuになっている行をコメントアウトし、cuda側を使う)
この状態でdocker compose up -dすれば、ログにCUDA関連のエラーが出ていないことを確認して完了。GPUを使わない場合はこの節をまるごと無視してよく、Immichは自動的にCPUで処理する。
Step 2: 取り込みツールimmich-goを導入する
Immich公式のCLI(コマンドライン操作用ツール)であるimmich uploadは使わない。理由は、Google Takeout(Googleのデータ一括エクスポート機能)でダウンロードした写真には、撮影日時やアルバム情報が入った.jsonという付属ファイル(サイドカーファイルと呼ばれる)が一緒に入っているが、公式CLIはこの.jsonを読まないため、アルバムの中身や正確な撮影日時が失われてしまうため。
代わりに使うのが、有志が開発した**immich-go**(自分が使ったのはv0.32.0、開発者はsimulot氏)というツール。Takeoutの.jsonサイドカーをちゃんと読んでアルバム・撮影日時・GPS情報を復元し、しかもzipファイルを展開せずそのまま読み込める(119GB分を解凍する広い置き場所を用意しなくていい)、重複した写真も自動で名寄せしてくれる。
GitHubのリリースページから、自分のOS(今回はLinux/amd64)に合ったバイナリをダウンロードして展開し、実行権限を付ける。
curl -fL -o immich-go.tar.gz https://github.com/simulot/immich-go/releases/download/v0.32.0/immich-go_Linux_x86_64.tar.gz
tar -xzf immich-go.tar.gz
chmod +x immich-go
(バージョンによって配布ファイル名やコマンドのオプション名が変わることがあるので、実行前に./immich-go --helpで最新の使い方を確認するのを勧める。)
Immich側の管理画面(Account Settings → API Keys)でAPIキーを1つ発行しておく。このキーを使ってimmich-goがImmichサーバーに写真をアップロードする。
Step 3: Google Takeoutで写真データをエクスポートする
takeout.google.comにアクセスし、「Google フォト」だけを選択してエクスポートを作成する。ファイル形式はzip、分割サイズは自分で選べる(容量が大きいとGoogleが複数のzipファイルに自動分割してくれる)。準備ができるとメールで通知が来て、ダウンロードページから一つずつ落としていく。
ここでも一度ハマった: 自分の場合は全部で12個に分割された(takeout-...-001.zip〜-012.zip)。ダウンロードし終わったつもりで作業を始めたら、途中の2つ(-002と-003)が抜けていたことに後から気づいた。ダウンロードページに戻って抜けていた分だけ再取得し、連番が最後まで揃っていることを確認してから次に進んだ。件数が多いときは、連番が全部揃っているかを作業開始前に必ず確認するべき、という教訓。
Step 4: 長時間処理に備えてtmuxの中で作業する
数万件・100GB超のアップロードは何時間もかかる処理になる。ターミナルの画面(WindowsならPowerShellやWSLの窓)を誤って閉じてしまうと処理も一緒に止まってしまうので、tmux(ターミナルの中に「もう一つの独立したターミナル」を作れるツール)のセッションの中で実行する。
tmux new -s immich-import
これで新しいセッションに入る。ここから先の作業はこのセッションの中で行い、たとえ元のウィンドウを閉じても処理は裏側で動き続ける(再接続するにはtmux attach -t immich-import)。
Step 5: まず--dry-runで確認する
いきなり本番実行するのは怖いので、実際には何もアップロードせず結果だけ教えてくれる--dry-runオプションを付けて試す。
./immich-go upload from-google-photos \
--server=http://localhost:2283 \
--api-key=<Step2で発行したAPIキー> \
--dry-run \
~/Downloads/takeout-*.zip
自分の場合の出力はこうだった。
Total Assets: 32218
Associated metadata: 32211
Missing metadata: 7
Errors: 0
3万2千件のうち、日付やアルバム情報(メタデータ)が紐づかなかったのはわずか7件、エラーはゼロ。この結果を見て「時系列が全部壊れる」ような大事故にはならなさそうだと判断し、--include-unmatched(メタデータが無い写真も強引に取り込むオプション)は付けずに本番実行することにした。
Step 6: 本番実行
--dry-runを外すだけで、実際のアップロードが始まる。
./immich-go upload from-google-photos \
--server=http://localhost:2283 \
--api-key=<APIキー> \
~/Downloads/takeout-*.zip
結果はこうだった。
Uploaded successfully: 29408
Metadata updated: 30794
Discarded local duplicate: 1048
Errors: 2
Missing metadata: 7
3万件近くが無事アップロードされ、1,048件は重複と判定されてスキップされた(むしろ取り込み過ぎを防いでくれるので助かる動き)。エラーは2件だけ。ログファイル(~/immich-import.log)を見ると、写真本体が消えたわけではなく、「アルバムを作れなかった(failed to create album)」「タグを付けられなかった(failed to add assets to tag)」といった付随的な失敗だけだった。
Step 7: 取り込み直後に焦った話(バックグラウンドジョブの確認)
取り込み後、Immichの管理画面で最近の写真に「Error」のようなマークが出ていて、一瞬「本体が壊れたか」と焦った。よく見ると、管理画面(Administration → Jobs)にサムネイル生成(Generate Thumbnails)・顔認識(Facial Recognition)・文字認識(OCR)といった**後処理(バックグラウンドジョブ)**がまだ大量に残っている状態だった。つまり、アップロード自体は終わっていても、Immich側の後片付け処理がまだ終わっていなかっただけ。数時間待って、これらのジョブがすべて完了したのを確認してから見直したら、表示は正常に戻っていた。取り込み直後に何かエラーっぽい表示が出ても、すぐパニックにならず、まずバックグラウンドジョブが終わっているか確認する、というのが得た教訓。
Step 8: バックアップに追加する
写真ファイルだけをバックアップしても、アルバム構成・撮影日時の補正結果・顔認識結果はすべてPostgreSQL(Immichが使っているデータベース)の中に入っているため、データベースのバックアップも一緒に取らないと意味がない。自分は既存のバックアップスクリプト(~/backup-scripts/backup-to-b2.sh、Backblaze B2というオンラインストレージへrcloneで同期するもの)に以下の2つを追記した。
# データベースのダンプ
docker compose -f ~/immich/docker-compose.yml exec -T database \
pg_dumpall --clean --if-exists --username=postgres | gzip > /tmp/immich-db.sql.gz
# 写真本体の同期(サムネイルと変換済み動画はImmichが再生成できるので除外する)
sudo rclone --config /home/ito-t/.config/rclone/rclone.conf sync \
~/immich/library "$B2_REMOTE/immich/library" \
--exclude "thumbs/**" --exclude "encoded-video/**"
注意点が2つ。1つ目は、thumbs/とencoded-video/(Immichが自動生成する派生ファイル)を除外しないと、バックアップ容量が無駄に膨らむこと。2つ目は、119GBのような大容量を初回にいきなり日次の自動実行(cron)に任せると、家庭のインターネット回線の上り速度によっては半日〜丸1日かかってしまい、日中の回線を占有してしまうこと。初回だけは--bwlimit(転送速度の上限を指定するオプション)を付けて手動で実行し、完了を確認してから自動実行に組み込むことを勧める。
結果と現状の進捗
ブラウザでImmichを開いて確認したところ、昔の写真もちゃんと時系列順に並んでいた。「日付が全部壊れた」ような状態にはならず、実用上問題のない移行ができたと判断している。
2026-09-12時点の進捗として追記すると、Google Photosからの移行は完了しているが、実はiPhone側の「iCloud写真」はまだオンのままで、GoogleとImmich・iCloudの3箇所に同時保存されている状態が続いている。写真の管理元を完全にImmich一本にするには、(1)しばらくImmichと並行運用して安定を確認、(2)iPhoneの「iCloud写真」をオフにして以降はImmichアプリの自動バックアップだけに切り替え、(3)必要ならiCloudのストレージプランを見直す、という手順が残っている。Apple純正の「写真」アプリ自体をやめるつもりはなく、OS標準のビューア・共有機能としては使い続け、バックアップ・データの主管をImmichに置く役割分担にする方針。この手順は急がず進める予定で、実施したらここに追記する。
次は、同じ考え方でGoogle Driveのファイルを移した話。→ ファイルをGoogle DriveからNextcloudに移す
更新履歴 — 2026-08-24: 初版 / 2026-09-12: 「現状の進捗」を追記(iCloud写真トグルOFF化の計画) / 2026-09-13: docker-composeでのImmich構築・immich-goの実コマンド・バックアップスクリプトの追記まで、再現可能なレベルに全面書き直し