Google Photos free tier died in 2021 and the paid tiers keep creeping up. Immich is the self-hosted replacement that actually works — a mobile-first photo library with face recognition, semantic search, timeline scrubbing, and shared albums that matches Google Photos feature-for-feature. This guide covers a real production deploy on a Synology DSM 7.2 NAS with hardware transcoding, the ML container offloaded to a mini-PC, external Postgres, and Tailscale-only remote access.
Skip this guide if you're on a DS220+ or below — the Realtek and low-end Celeron units can't handle transcoding and the ML container will OOM. You want a Plus-series with an Intel CPU (DS923+, DS1522+, DS923+) or you're moving the whole thing to a mini-PC.
The high-level steps
Here's the full deploy path before we get into the weeds:
- Install Container Manager on DSM 7.2 and enable SSH for the admin user.
- Create a shared folder for Immich data and a separate one for the external Postgres volume.
- Deploy Postgres 16 with pgvecto.rs as its own compose stack so you can back it up independently.
- Deploy the Immich server, Redis, and machine-learning containers via Docker Compose over SSH.
- Split the ML container onto a mini-PC on the same LAN and point Immich at it over HTTP.
- Wire up hardware transcoding by mounting
/dev/driinto the immich-server container. - Import an existing Photos share as an external library, then install Tailscale for remote access.
What makes Synology's Docker package painful?
Container Manager (formerly Docker): Synology's rebranded Docker package on DSM 7.2, which ships an outdated Docker Engine (usually 20.10.x) and a UI that fights compose files.
The GUI mangles bind mounts, drops cap_add directives silently, and refuses to render compose files that use ${VAR} substitution. Deploy from SSH using docker compose up -d from a folder under /volume1/docker/immich/ and never touch the GUI for stack management again. You can still use it to view logs and CPU stats — just don't let it edit anything.
The second gotcha: Synology's Docker runs as root by default but bind-mounted folders inherit DSM's ACLs. Set the folder owner to a real user (create immich in DSM with UID 1027) and mount volumes with PUID=1027 in your .env. Without this, thumbnails silently fail to write and you'll waste an hour on a permissions rabbit hole.
The Docker Compose file
Start with the upstream Immich template but strip the bundled Postgres — you want it running in a separate stack for backup and upgrade independence. Here's the working docker-compose.yml:
services:
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:release
devices:
- /dev/dri:/dev/dri
volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload
- /volume1/photo:/mnt/media/photo-library:ro
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
ports:
- 2283:2283
depends_on:
- redis
restart: always
redis:
container_name: immich_redis
image: docker.io/redis:6.2-alpine
restart: always
networks:
default:
name: immich_default
Note there's no immich-machine-learning block — that runs on the mini-PC. Set MACHINE_LEARNING_URL=http://192.168.1.42:3003 in your .env to point at it.
Why split the ML container onto a mini-PC?
Machine learning workload: Immich's face detection, CLIP-based smart search, and OCR run in a separate container that pins ~2GB of RAM idle and spikes CPUs to 100% during a library scan.
A DS923+ with 8GB RAM can technically run it, but you'll starve every other Docker service on the NAS and the initial scan of a 40k-photo library will take three days. Offloading ML to a Beelink SER5 mini-PC with 32GB RAM cuts a full re-index to under six hours and leaves the NAS free for Plex, backups, and Immich itself.
On the mini-PC, run just this compose file:
services:
immich-machine-learning:
container_name: immich_ml
image: ghcr.io/immich-app/immich-machine-learning:release
volumes:
- model-cache:/cache
ports:
- 3003:3003
restart: always
volumes:
model-cache:
Firewall it to the NAS's IP only. Immich's ML endpoint has no authentication — anyone on your LAN can hit it and burn CPU.
How do you enable hardware transcoding on DSM 7.2?
Mount /dev/dri into the immich-server container and set HWACCEL_TRANSCODING=quicksync in the admin settings. That's it — Immich uses ffmpeg with VAAPI under the hood and Intel Quick Sync on any modern Synology Plus unit works out of the box.
To verify, SSH into the NAS and run ls /dev/dri. You should see card0 and renderD128. If they're missing, your model doesn't have an iGPU — you're stuck with software transcoding and need to lower the concurrent job limit to 2 to avoid melting the CPU. AMD Ryzen units (DS923+, DS1522+) also expose /dev/dri but use rkmpp or fall back to software depending on your ffmpeg build.
External Postgres with pgvecto.rs
Immich needs Postgres 14+ with the pgvecto.rs extension for vector search. Use the tensorchord image, not stock Postgres:
services:
postgres:
container_name: immich_postgres
image: tensorchord/pgvecto-rs:pg16-v0.2.0
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: immich
POSTGRES_DB: immich
volumes:
- /volume1/docker/postgres-immich:/var/lib/postgresql/data
ports:
- 5432:5432
restart: always
Snapshot the volume nightly with Backblaze B2 via Restic — pg_dumpall weekly for a portable logical backup as insurance against schema corruption. Don't skip this; Immich upgrades occasionally require destructive migrations and the rollback path is "restore from backup".
Importing an existing Photos share
Immich supports external libraries — read-only mounts that get indexed in place without moving files. Mount your DSM /volume1/photo share into the container as ro (see the compose above), then in the Immich admin UI go to External Libraries → Create Library and point it at /mnt/media/photo-library.
Trigger a scan and Immich hashes every file, generates thumbnails into the UPLOAD_LOCATION volume, and runs ML in the background. A 40k-photo library takes ~6 hours end-to-end with the ML split described above. The originals stay untouched in DSM Photos — you can run both apps in parallel during the transition period.
The gotcha: Immich does not deduplicate against files uploaded via the mobile app. If your phone was already backing up to DSM Photos and you now install the Immich app, you'll get double copies. Turn off DSM Photos auto-backup on the phone the same day you deploy Immich.
Remote access via Tailscale
Don't port-forward Immich. Install Tailscale on the NAS (there's an official DSM package) and on every phone that needs to sync. Add your tailnet IP as a valid host in Immich's config and you get end-to-end WireGuard access with zero public exposure. If you want a proper domain, use Tailscale's MagicDNS and a wildcard cert via Traefik 3 running as another compose stack.
If you insist on public access — for sharing albums with family who won't install Tailscale — put Immich behind a Pangolin or Cloudflare Tunnel rather than exposing port 2283. Immich has had auth CVEs and it's not audited software.
Verdict
Immich on a Synology Plus-series NAS is genuinely production-ready in 2026. The mobile apps sync reliably, the timeline UX beats Google Photos, and semantic search ("pictures of my dog at the beach") works out of the box. Split the ML container off, run Postgres separately, mount hardware transcoding, and stay off the public internet with Tailscale. That's the whole recipe.
FAQs
Can Immich replace Google Photos completely?
Yes, for the core use cases — mobile backup, timeline browsing, face grouping, shared albums, and search. It lacks Google's Memories/Highlights curation and the AI editing tools, but the daily-driver flows are on par or better.
What Synology NAS do I need to run Immich?
A Plus-series with an Intel or Ryzen CPU and at least 8GB RAM — DS923+, DS1522+, or DS1621+ are the sweet spot. Value-series units (DS220j, DS223j) don't have the CPU or RAM headroom, and their Realtek chips lack Quick Sync so video transcoding will crawl.
Is Immich safe to expose to the internet?
Not without a reverse proxy and something in front of it. The project ships regular security patches but is explicitly marked as beta for external exposure. Use Tailscale for personal access and a tunnel service like Cloudflare or Pangolin if you need to share albums publicly.
How much storage does Immich use vs the original photos?
Roughly 10-15% overhead for thumbnails, previews, and the database. A 500GB photo library will consume around 570GB total once thumbnails, ML embeddings, and Postgres indexes are generated.
Can I run Immich and DSM Photos on the same NAS?
Yes, and it's the recommended migration path — mount the DSM Photos share into Immich as a read-only external library so you can validate the switch before disabling DSM Photos. Just remember to turn off phone auto-backup to DSM Photos before enabling it in Immich, or you'll get duplicate uploads.