DEV Community

Cover image for Running Immich on Proxmox With a Synology NAS: A Battle‑Tested Setup
Ibrahim
Ibrahim

Posted on

Running Immich on Proxmox With a Synology NAS: A Battle‑Tested Setup

Self‑hosting Immich is straightforward in theory: spin up a container, point it at storage, and let it index your photos. In practice, you can easily end up with:

  • Immich indexing its own thumbnails as photos
  • File‑system races at boot where the container starts before the NAS is ready
  • Confusing folder‑check errors about missing .immich files
  • GPU passthrough that silently breaks after a kernel update

This post documents a full setup that avoids those problems. It’s based on a real deployment using:

  • Proxmox VE 9 on a Minisforum MS‑12 mini‑PC
  • Synology DS218+ NAS (Btrfs, /volume1)
  • Immich running inside an LXC container on Proxmox

Goals and Architecture

The design aims to:

  • Keep Immich application & database on Proxmox local storage
  • Keep all media (uploads, thumbs, encoded video, backups) on the Synology NAS
  • Mount NAS storage into Proxmox via NFS, then into the Immich LXC via bind mounts
  • Allow Immich to index existing photo trees on the NAS as external libraries
  • Survive reboots cleanly (NAS → Proxmox → Immich), without manual intervention

High‑Level Layout

  • Proxmox host: pve.example.lan (Minisforum MS‑12, Proxmox VE 9)
  • NAS: nas.example.lan (Synology DS218+, /volume1)
  • Immich LXC:
    • CTID: 115
    • Hostname: immich
    • IP: 192.168.10.115 (example)
    • OS: Debian 13

On the NAS:

  • Dedicated Immich share: /volume1/Immich
  • Existing photos: /volume1/homes/user/Photos (Synology “homes” feature)

On Proxmox:

  • /mnt/immich-data → NFS mount of /volume1/Immich
  • /mnt/nas-homes → NFS mount of /volume1/homes

Inside the Immich LXC:

  • /opt/immich → Immich application
  • /opt/immich/upload → Immich media root (mapped to /volume1/Immich)
  • /mnt/nas-homes → read‑only view of /volume1/homes for external libraries

Step 1 – Prepare NFS Shares on Synology DS218+

On the Synology DSM UI:

  1. Create a shared folder called Immich:
    • Filesystem: Btrfs (or ext4)
    • Path: /volume1/Immich
  2. Ensure NFS is enabled in Control Panel → File Services → NFS.
  3. For Immich and homes shares, add NFS permissions:
    • Host: 192.168.10.7 (your Proxmox host IP, example)
    • Privilege: Read/Write
    • Squash: Map all users to admin or Map all users to admin group (depending on your UID mapping strategy)
    • Security: sys

From Proxmox you can verify exports:

showmount -e nas.example.lan
Enter fullscreen mode Exit fullscreen mode

You should see something like:

/volume1/Immich  192.168.10.7
/volume1/homes   192.168.10.7
/volume1/Proxmox 192.168.10.7
Enter fullscreen mode Exit fullscreen mode

On the NAS itself:

ssh admin@nas.example.lan
df -h /volume1/Immich /volume1/homes
ls -ld /volume1/Immich /volume1/homes /volume1/homes/user/Photos
Enter fullscreen mode Exit fullscreen mode

Make sure the Immich share is writable and the Photos tree exists.


Step 2 – Mount NFS Shares on Proxmox

On the Proxmox host (pve.example.lan), edit /etc/fstab:

# <file system>                         <mount point>     <type> <options>                                                                 <dump> <pass>
192.168.10.5:/volume1/homes            /mnt/nas-homes    nfs   defaults,_netdev,noatime,nofail,x-systemd.automount,x-systemd.after=network-online.target 0 0
192.168.10.5:/volume1/Immich           /mnt/immich-data  nfs   defaults,_netdev,noatime,nofail,x-systemd.automount,x-systemd.after=network-online.target 0 0
Enter fullscreen mode Exit fullscreen mode

Replace 192.168.10.5 with your DS218+ IP.

Key options:

  • _netdev, x-systemd.after=network-online.target – avoid racing the NIC at boot
  • x-systemd.automount – defer actual mounting until first access
  • nofail – boot even if the NAS is temporarily unavailable

Reload and validate:

systemctl daemon-reload
systemctl status mnt-nas\x2dhomes.mount mnt-immich\x2ddata.mount
df -h /mnt/nas-homes /mnt/immich-data
Enter fullscreen mode Exit fullscreen mode

You should see the NFS paths mounted.


Step 3 – Create and Configure the Immich LXC

Use your preferred Immich installer (e.g. the community Proxmox script) to create a Debian‑based LXC for Immich. Once created, adjust its config in /etc/pve/lxc/115.conf:

hostname: immich
unprivileged: 1
rootfs: local-lvm:vm-115-disk-0,size=40G

mp0: /mnt/immich-data,mp=/opt/immich/upload
mp1: /mnt/nas-homes,mp=/mnt/nas-homes,ro=1

# GPU passthrough (example)
dev0: /dev/dri/renderD128,gid=992
dev1: /dev/dri/card0,gid=44

onboot: 1
memory: 12288
cores: 8
swap: 2048
Enter fullscreen mode Exit fullscreen mode

Notes:

  • mp0 binds the NAS Immich share into the container as /opt/immich/upload.
  • mp1 exposes the entire homes tree read‑only for Immich external libraries.
  • GPU devices (/dev/dri/renderD128 and /dev/dri/card0) may differ on your system – always check:
  ls -l /dev/dri
Enter fullscreen mode Exit fullscreen mode

and adjust dev0/dev1 accordingly.

Ensure the Container Waits for NAS

Create a drop‑in to force CT 115 to wait for the homes mount:

mkdir -p /etc/systemd/system/pve-container@115.service.d
cat >/etc/systemd/system/pve-container@115.service.d/wait-nas.conf <<'EOF'
[Unit]
Requires=mnt-nas\x2dhomes.mount
After=mnt-nas\x2dhomes.mount
EOF

systemctl daemon-reload
Enter fullscreen mode Exit fullscreen mode

This avoids the “folder checks failed” situation where Immich starts before NFS is mounted.


Step 4 – Immich In‑Container Configuration

Exec into the container:

pct exec 115 -- bash
Enter fullscreen mode Exit fullscreen mode

Key paths:

  • Immich app root: /opt/immich
  • Env file: /opt/immich/.env

The installer should set:

IMMICH_MEDIA_LOCATION=/opt/immich/upload

DB_HOSTNAME=127.0.0.1
DB_USERNAME=immich
DB_PASSWORD=<your_password>
DB_DATABASE_NAME=immich
REDIS_HOSTNAME=127.0.0.1
Enter fullscreen mode Exit fullscreen mode

Required Folder Layout and .immich Sentinels

Immich performs folder checks on startup. It expects the following under IMMICH_MEDIA_LOCATION:

/opt/immich/upload
  .immich
  backups/.immich
  encoded-video/.immich
  library/.immich
  profile/.immich
  thumbs/.immich
  upload/.immich
Enter fullscreen mode Exit fullscreen mode

If these are missing or not readable/writable, Immich will refuse to start and you’ll see errors like:

Failed to read: "/encoded-video/.immich ..."

Fixing Folder Checks

Inside CT 115:

rm -rf /opt/immich/upload/*

# Create folders without relying on brace expansion
mkdir -p /opt/immich/upload/backups \
         /opt/immich/upload/encoded-video \
         /opt/immich/upload/library \
         /opt/immich/upload/profile \
         /opt/immich/upload/thumbs \
         /opt/immich/upload/upload

touch /opt/immich/upload/.immich
touch /opt/immich/upload/backups/.immich
touch /opt/immich/upload/encoded-video/.immich
touch /opt/immich/upload/library/.immich
touch /opt/immich/upload/profile/.immich
touch /opt/immich/upload/thumbs/.immich
touch /opt/immich/upload/upload/.immich

ls -R /opt/immich/upload
Enter fullscreen mode Exit fullscreen mode

Then restart Immich:

systemctl restart immich-web
systemctl restart immich-ml
Enter fullscreen mode Exit fullscreen mode

Check:

systemctl status immich-web immich-ml
ss -tulpn | grep 2283
curl -sS -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:2283/
Enter fullscreen mode Exit fullscreen mode

You should see immich-api listening on *:2283 and HTTP 200.


Step 5 – Clean‑Slate Reset (Optional but Useful)

If you’ve experimented and want to start over cleanly without recreating the container:

WARNING: This wipes all Immich state (users, albums, assets, ML data), but leaves your NAS photos intact.

Inside CT 115:

systemctl stop immich-web immich-ml

sudo -u postgres psql -c "DROP DATABASE IF EXISTS immich;"
sudo -u postgres psql -c "CREATE DATABASE immich OWNER immich;"
Enter fullscreen mode Exit fullscreen mode

Then rebuild the media root as shown above, restart services, and verify the DB is empty:

PGPASSWORD=<DB_PASSWORD> psql -h 127.0.0.1 -U immich -d immich \
  -c 'SELECT COUNT(*) AS assets FROM "asset";'
Enter fullscreen mode Exit fullscreen mode

You should get 0 assets – Immich will present the onboarding UI again.


Step 6 – External Libraries: Where People Go Wrong

This is where the biggest “face‑palm” bug came from.

The Anti‑Pattern (What NOT to Do)

  • Putting Immich’s media root inside your Photos tree, e.g.:
  /volume1/homes/user/Photos/immich
Enter fullscreen mode Exit fullscreen mode
  • Then adding /mnt/nas-homes/user/Photos as an external library.

Result:

  • Immich happily indexes:
    • Your real photos, and
    • Its own thumbs/ and encoded-video/ directories.
  • You start seeing lots of tiny 106×106 face crops as “photos”.
  • Indexing takes forever and you waste storage.

The Correct Pattern

  • Keep Immich’s internal data in its own NAS share:
  /volume1/Immich
Enter fullscreen mode Exit fullscreen mode
  • Keep your photo library under a separate tree:
  /volume1/homes/user/Photos
Enter fullscreen mode Exit fullscreen mode

Inside CT 115, these appear as:

/opt/immich/upload                # Immich internal data (uploads, thumbs, encoded, backups, etc.)
/mnt/nas-homes/user/Photos        # Real photos for external libraries
Enter fullscreen mode Exit fullscreen mode

Configuring External Libraries in the UI

In the Immich web UI:

  1. Go to Administration → Libraries.
  2. Click Create library (or similar).
  3. For the import path, use in‑container paths; for example:
   /mnt/nas-homes/user/Photos
Enter fullscreen mode Exit fullscreen mode

or per‑folder:

   /mnt/nas-homes/user/Photos/DJI
   /mnt/nas-homes/user/Photos/Moments
   /mnt/nas-homes/user/Photos/iPhone XS
Enter fullscreen mode Exit fullscreen mode
  1. Save the library.
  2. IMPORTANT: Click Scan / Scan Library.

If you forget step 5, the library will show zero assets even though the path is valid.

You can verify from inside CT 115:

sudo -u postgres psql -d immich -c 'SELECT * FROM "library";'
sudo -u postgres psql -d immich -c 'SELECT COUNT(*) AS assets FROM "asset";'
Enter fullscreen mode Exit fullscreen mode

You should see your library and an increasing asset count while scanning.


GPU Passthrough and VAAPI Gotchas

If your Minisforum box has an Intel iGPU, you can offload video transcoding via VAAPI.

On the Proxmox host:

ls -l /dev/dri
Enter fullscreen mode Exit fullscreen mode

You might see:

card0
renderD128
Enter fullscreen mode Exit fullscreen mode

Map these into the LXC via dev0/dev1 as shown earlier. After a kernel upgrade, the numbering can change (e.g. card1 appears instead of card0), so:

  • After updates, always re‑check /dev/dri on the host.
  • Adjust /etc/pve/lxc/115.conf so dev0/dev1 refer to devices that actually exist.

Inside CT 115 you can confirm VAAPI works by inspecting Immich logs and/or running a test ffmpeg command (if installed).


Operational Checklist

This is the condensed runbook I use to keep the setup healthy.

After Proxmox / NAS Reboot

On the Proxmox host:

systemctl status mnt-nas\x2dhomes.mount mnt-immich\x2ddata.mount
df -h /mnt/nas-homes /mnt/immich-data
Enter fullscreen mode Exit fullscreen mode

Check the Immich LXC:

pct list
pct start 115   # if not already running
Enter fullscreen mode Exit fullscreen mode

Inside CT 115:

df -h / /opt/immich/upload /mnt/nas-homes
systemctl status immich-web immich-ml
ss -tulpn | grep 2283
curl -sS -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:2283/
Enter fullscreen mode Exit fullscreen mode

You want:

  • /opt/immich/upload and /mnt/nas-homes mounted via NFS
  • immich-web and immich-ml active
  • immich-api listening on *:2283
  • HTTP 200 from the local curl

When Adding or Editing External Libraries

  • Use only paths under /mnt/nas-homes/.../Photos...
  • Never use /opt/immich/upload or anything under /mnt/immich-data
  • After saving a library, always click Scan in the Immich UI
  • Optionally monitor progress:
  sudo -u postgres psql -d immich -c 'SELECT COUNT(*) AS assets FROM "asset";'
Enter fullscreen mode Exit fullscreen mode

When Folder Checks Fail

If you see errors about .immich files in the logs:

  1. Confirm NFS is mounted (df -h /opt/immich/upload).
  2. Rebuild the directory structure and .immich sentinels as shown in Step 4.
  3. Restart immich-web and re‑check logs.

When You Want a Clean Reset

Follow the clean‑slate procedure:

  • Stop services
  • Drop & recreate the immich database
  • Rebuild /opt/immich/upload
  • Start services
  • Confirm asset count is 0
  • Recreate external libraries and scan

Conclusion

The key lessons from running Immich on Proxmox with a Synology NAS:

  • Separate Immich’s internal data from your photo library – use a dedicated NAS share for Immich (/volume1/Immich) and keep photos under homes or another share.
  • Never point an external library at Immich’s own data path – otherwise Immich indexes its own thumbnails and encoded videos.
  • Treat NFS and folder checks as first‑class citizens – make sure the container waits for mounts, and that the .immich sentinels are present.
  • Expect GPU device names to change – always verify /dev/dri after updates and keep LXC config in sync.
  • Remember to click Scan – creating a library alone does nothing until you trigger a scan.

With this layout, Immich becomes a robust, low‑maintenance part of your homelab: app and database on fast local storage, media safely on the NAS, and clean separation between internal Immich data and your actual photo library. Feel free to adapt the paths and resource sizes to your environment, but keep the structural ideas the same.***

Top comments (0)