← Back to Wiki
Self-Hosting

Replace iCloud / NAS Photos With Immich + Radicale

Two focused, best-in-class tools instead of one all-in-one suite. Immich for photos and video. Radicale for contacts and calendars. Here is the setup, and how to migrate years of existing data across without losing anything.

Share on X

Why two apps instead of one

An all-in-one platform like Nextcloud does photos, files, contacts and calendars at once. Splitting into two focused tools gets you a noticeably better experience for less overhead:

Immich User Management admin panel showing a table of accounts with name, email, and quota columns, redacted
Immich → account menu → Administration → Users. Each household member gets their own account and quota. Names and emails redacted here.

Storage architecture matters for backups

Some backup solutions only back up VM and container disk images, not arbitrary NFS-mounted paths. Proxmox Backup Server is one. On those, a simple NFS bind-mount for your photo library is never covered by your backup job. A real risk for genuinely irreplaceable photos.

Instead, provision a real virtual disk on your NAS-backed storage pool and let your hypervisor manage it as a normal disk image:

# Proxmox example
pct set <vmid> --mp0 nas-storage-pool:500,mp=/mnt/photo-library,backup=1

That gets you a real disk image on the NAS, formatted normally and mounted like local storage inside the container. No NFS UID-mapping headaches, and backup=1 makes it a genuine backup target. Keep the database's own data directory on the container's local storage, never on network storage. Postgres, in Immich's case. Database files over NFS risk locking issues and corruption.

BE WARNED: do not move an app's storage path after it has initialized without resetting its state. Some apps write internal marker files into their storage location on first boot and check for them on every start after. Immich included. Swap to a fresh disk after the fact and the app crash-loops, checking for markers that only exist in the old location. If no real user data has been imported yet, do a full reset. Wipe both the database and the new storage location, then let the app initialize them fresh together. On an instance with real data in it, follow the app's own documented storage-migration process instead.

Migrating photos off a vendor NAS app

Synology DSM Package Center showing pending package updates
Synology DSM → Package Center. The same screen where the old Photos, Calendar and Contacts apps get uninstalled once migration is confirmed working. It shows pending updates here, since none are due for removal in this shot.

The same setuid-rsync-over-SSH restriction from the password manager guide applies here. Use a tar stream over SSH instead:

ssh <nas> 'cd /path/to/photos && sudo tar --exclude=@eaDir --exclude=.DS_Store -cf - .' \
  | ssh <immich-host> 'cd /import/staging && tar xf -'

Exclude any vendor-internal thumbnail-cache directories, like Synology's @eaDir. They are pure noise, and your new tool regenerates its own thumbnails anyway.

To ingest the files rather than only copy them, use immich-go instead of a raw file copy. It reads EXIF and embedded dates and uploads through Immich's real API, so thumbnails and search indexing run normally:

immich-go upload from-folder \
  --server http://localhost:2283 --api-key <your-api-key> \
  --folder-as-album FOLDER --no-ui \
  /import/staging

Always run --dry-run first at any real scale. It is cheap insurance, and it catches permission issues before you touch anything. A non-admin API key cannot pause background jobs, for one, and immich-go attempts that by default.

Don't panic over asset-count changes after cleanup. If your video count drops after you delete auto-created albums, check whether it correlates with Live Photo linking before you assume data loss. That is iPhone photo and video pairs merging into a single timeline entry. Google Photos and Apple Photos do the same thing for the same feature.

Migrating contacts and calendars

Most vendor NAS calendar and contact apps expose standard CalDAV and CardDAV endpoints directly, even with no obvious "export" button in the UI. Check the app's underlying web server config for existing /caldav/ and /carddav/ routes. If they exist, use vdirsyncer, a standard two-way CalDAV and CardDAV sync tool, for a one-time pull from the old source into Radicale.

BE WARNED: some NAS vendors issue calendar and contact certificates from their own "Managed CA", not a self-signed cert. vdirsyncer's SSL verification option only accepts a real CA file, not a boolean to disable verification. If the standard public root for that vendor's cert type does not match, pin the exact certificate's fingerprint rather than chasing down the right CA chain:
echo | openssl s_client -connect <nas-ip>:5001 -servername <nas-ip> 2>/dev/null \
  | openssl x509 -noout -fingerprint -sha256

Verify the migration by comparing item counts on both sides directly. A "sync exited cleanly" check is not enough. Do that before you call it done.

Connecting devices

The cutover is per-device. Repoint each phone and computer's CalDAV and CardDAV account from the old server to Radicale. Most desktop operating systems have this under their native "Internet Accounts" or account settings, as a generic CalDAV and CardDAV option. Android has no built-in client and needs a third-party app like DAVx⁵.