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.
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:
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.
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.
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.
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.
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⁵.