Skip to main content
iCloud

Escaping iCloud: Self-Hosting 4TB of Photos with Immich

Mustafa · · 4 min read

After years of paying for iCloud Photos storage, I moved my family photo library to a self-hosted setup using Immich, a Synology NAS, and a spare Linux box.

This is not a perfect “deploy in 5 minutes” guide. This is the real playbook: what worked, what broke, and what I would do differently.

The Goal

Move away from iCloud Keep the family photo library under my control.

Use existing NAS storage Store photos and videos on the Synology NAS I already own.

Run Immich properly Use a stronger Linux box for compute, ML, face detection, and smart search.

Start local first LAN access now, remote access later through Tailscale.

Architecture Overview

The winning design was simple: separate storage from compute.

Golden rule: Photos can live on NFS. Postgres should not. Keep the database on the Linux box’s local SSD.

Why Not Run Everything on the NAS?

The obvious first idea was to install Immich directly on the Synology. I almost did that, but the DS723+ only had 2GB of RAM.

OptionResultVerdict
Run Immich fully on NASLow RAM, ML crashes, slow importsAvoid
Upgrade NAS RAMPossible, but still limited computeOkay
Use Linux box for computeMore CPU, more RAM, better ML performanceBest

Why Not Put It in the Cloud?

I briefly considered using a cloud VPS. Then I thought about the data path.

Initial import could take weeks.

Cloud compute looks clean on paper, but for a huge home photo library it creates a slow and expensive architecture.

Step 1 — Reclaim NAS Space First

My NAS was already 81% full. Before importing 4TB of photos, I needed to clean it up.

I used Czkawka, an open-source duplicate finder. The regular Linux build failed because Synology DSM had an older glibc, so the fix was to use the musl build.

sudo ./linux_czkawka_cli_musl dup \
  -d /volume2/Backup \
  -d /volume2/homes \
  -d /volume2/Videos \
  -d /volume2/iMazing \
  -m 10485760 \
  -f /volume2/dup-report.txt

Lesson: Old backups are not always useful backups. Audit them before trusting them.

Step 2 — Export NAS Storage via NFS

On Synology, I created a dedicated shared folder called Immich, enabled NFS, and allowed access from the compute box IP only.

On the Linux box:

sudo apt install -y nfs-common
sudo mkdir -p /mnt/immich-nas
sudo mount -t nfs <nas-ip>:/volume2/Immich /mnt/immich-nas

Then I added it to /etc/fstab:

<nas-ip>:/volume2/Immich /mnt/immich-nas nfs defaults,_netdev,noatime 0 0

Make sure the container user can write to the NAS folders. Immich commonly runs as UID 1000.

Step 3 — Deploy Immich with Docker Compose

The compute box already had Docker installed, but I needed the Compose v2 plugin.

sudo apt install -y docker-compose-v2

sudo mkdir -p /opt/immich
cd /opt/immich

wget -O docker-compose.yml https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
wget -O example.env https://github.com/immich-app/immich/releases/latest/download/example.env

cp example.env .env

The important environment settings:

UPLOAD_LOCATION=/mnt/immich-nas/library
DB_DATA_LOCATION=/opt/immich/postgres
DB_PASSWORD=<random-32-char-string>
TZ=Asia/Dubai
docker compose up -d

Gotcha — OCR Failed Out of the Box

After uploading my first batch of photos, the machine learning container started returning HTTP 500 errors.

The logs pointed to a failed OCR model download:

DownloadFileException: Failed to download
https://www.modelscope.cn/models/RapidAI/RapidOCR/...

When OCR failed, the ML container became unstable. This affected more than OCR — face detection and smart search also suffered.

The fix was simple:

Disable OCR Administration → Settings → Machine Learning → OCR off.

Restart ML container Let face detection and CLIP search work normally.

Keep smart features Face recognition and smart search are more useful than OCR for most photo libraries.

Step 4 — Import Existing Photos

For importing photos, I used immich-go. It handles batch uploads, deduplication, and Google Takeout parsing.

immich-go upload from-folder \
  --server=http://<compute-ip>:2283 \
  --api-key=<key> \
  --on-errors=continue \
  --concurrent-tasks=4 \
  /mnt/nas-homes/mustafa/Photos

What I learned

LessonWhy It Matters
Use from-folder when neededIt was more reliable than old Google Takeout parsing.
Reduce concurrencyDefault concurrency can overwhelm a fresh Immich server.
Dedup is idempotentYou can safely rerun the import.
Use screen or tmuxLarge imports can run for hours or days.

Step 5 — Pull Photos from iCloud

There are two main ways to pull photos from iCloud.

Option A: Apple Privacy Export Request a copy of your iCloud Photos data from Apple. Slow but safe.

Option B: icloudpd Use the command line to download directly from iCloud. Faster, but requires interactive authentication.

sudo apt install -y pipx
pipx ensurepath
exec bash
pipx install icloudpd

Authenticate first:

icloudpd --username <apple-id> --auth-only

Then download into a staging folder:

screen -S icloud

icloudpd \
  --username <apple-id> \
  --directory /mnt/immich-nas/icloud-staging \
  --folder-structure "{:%Y/%Y-%m}" \
  --size original \
  --no-progress-bar \
  --until-found 100

What Comes Next

Install Immich mobile app Point family devices to the local LAN URL and enable auto-backup.

Add Tailscale Access the library remotely without exposing Immich publicly.

Downgrade iCloud Reduce or remove the subscription once trust is built.

Backups Protect both the Postgres database and the photo library.

Final Verdict

Immich is genuinely impressive. The web UI is fast, the mobile app is solid, and the machine learning features are surprisingly powerful for a free open-source project.

The hard part is not running Immich. The hard part is the migration: cleaning old backups, downloading from iCloud, importing safely, and verifying everything before deleting anything.

Once it is running, the library is yours. No subscription, no lock-in, no rate limits, and no dependency on someone else’s cloud.

Next Post

Connecting Tailscale, configuring automated NAS-to-cloud backups for the Immich library, and benchmarking machine learning jobs on different hardware.

Share this article