Google Photos has one killer feature — you type “beach 2022” or “grandma” and it just finds the photo. This guide shows you how to get exactly that on your own hardware, with zero monthly fees and full control over your data. 📸
Immich on Proxmox with ZFS is not used here as a photo storage replacement. Your photos already live in OneDrive and sync to local ZFS storage via rclone — that part is covered in the OneDrive + Proxmox LXC + ZFS sync guide. What Immich on Proxmox with ZFS adds is a powerful search and browsing layer on top: face recognition, location search, semantic search, and a clean timeline interface — all pointing at your existing photo library without touching or duplicating the originals.
If you haven’t set up Proxmox yet, start with the Proxmox VE install guide first.
🏗️ Architecture Overview
Phones / cameras
│
▼
OneDrive (Microsoft cloud)
│
▼ rclone sync (nightly)
ZFS Mirror on Proxmox (pool name e.g. mir16tb, tank, datastore)
└── /YOUR_POOL/onedrive/YOUR_ACCOUNT/Pictures ← your actual photos live here
└── /YOUR_POOL/immich ← thumbs, encoded-video, DB backups only
Immich LXC
├── indexes /mnt/onedrive (read-only External Library)
├── stores thumbnails + metadata on /mnt/immich (ZFS)
└── Web UI at :2283 — search by face, location, date, object
The originals never move. Immich reads them from the OneDrive sync folder and generates its own thumbnails and metadata on ZFS. If you ever remove Immich — your photos are untouched.
Prerequisites:
- ZFS mirror pool already set up on Proxmox (any pool name works —
mir16tb,tank,datastore, etc.)- OneDrive synced to a folder on that pool — see the OneDrive + Proxmox LXC + ZFS guide
🚀 Step 1: Install Immich via Community Scripts
Immich on Proxmox with ZFS is dramatically simpler to deploy with the Community Scripts helper than with Docker Compose. Run this command directly in the Proxmox shell — not inside any VM or container:
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/immich.sh)"
Always get the latest command from community-scripts.org/scripts/immich — it may change between releases.
Installation Options
Choose Advanced when prompted. Recommended settings:
| Option | Recommended value | Why |
|---|---|---|
| Container type | Unprivileged | More secure; default |
| Disk size | 32 GB | Photos are on ZFS, not here |
| CPU cores | 4 | ML processing needs headroom |
| RAM | 8192 MB | 4096 minimum; 8192 if using OpenVINO |
| IP | Static | Easier to bookmark and proxy |
| OpenVINO (HW-accelerated ML) | Yes if Intel iGPU | Speeds up face detection significantly |
The installer walks you through many additional prompts. Most can be left at their defaults — below are the ones where you should change the default value:
| Prompt | Default | Choose | Why |
|---|---|---|---|
| IPv4 Configuration | DHCP | Static | Fixed IP for a server — easier to bookmark and proxy |
| IPv6 Configuration | auto | none | Prevents curl from trying IPv6 during install and failing |
| SSH Key Source | — | found | Copies your Proxmox host SSH key into the container |
| Enable root SSH access | no | yes | Allows direct SSH into the container |
| FUSE Support | no | yes | Required for rclone bind mounts |
| GPU Passthrough | yes | no | Only useful with Intel/AMD iGPU — Xeon E5 has none |
| Container Protection | no | yes | Prevents accidental deletion of the container |
| Verbose Mode | no | yes | Shows full output — useful for diagnosing install issues |
⚠️ IPv6 note: if the installer fails with
curl: Failed to connect (network unreachable / host down)— this is almost always IPv6. Setting IPv6 tononeduring setup prevents this entirely.
GitHub Rate Limit — PAT Token
During installation the script fetches several packages from GitHub. If GitHub’s API rate limit is hit (HTTP 403), the installer will pause and ask:
Would you like to enter a GitHub Personal Access Token (PAT)? [y/N]:
Enter Y and provide a token. To generate one:
- Open https://github.com/settings/tokens
- Click Generate new token → Generate new token (classic)
- Give it any name (e.g.
immich-install) - Set expiration to 1 day — it’s only needed for this install
- Leave all scopes unchecked — no permissions needed, just rate limit bypass
- Click Generate token and copy it immediately
- Paste it into the installer prompt
The token is used only to authenticate API requests and bypass the rate limit — it doesn’t grant any access to your GitHub account.
⏱️ Installation takes 5–15 minutes. The script sets up Immich, PostgreSQL, Redis, and all system dependencies inside a fresh LXC — no Docker involved.
When done, open http://CONTAINER_IP:2283 and create your admin account before anything else. 🎉
🔗 Step 2: Mount ZFS Storage into the Immich LXC
The Immich LXC runs unprivileged — the immich user inside the container maps to a different UID on the Proxmox host. Getting this right is the difference between a working Immich on Proxmox with ZFS setup and a wall of permission errors.
Create the ZFS Dataset
Before setting permissions, make sure the Immich dataset actually exists:
# Check your pool name first
zpool list
# Check existing datasets
zfs list
If the dataset doesn’t exist yet, create it:
# Replace 'datastore' with your actual pool name (e.g. mir16tb, tank, etc.)
zfs create datastore/immich
# Verify
zfs list
The dataset will mount automatically at /datastore/immich (or /YOUR_POOL/immich).
Find the Immich User UID
Run on the Proxmox host (replace 201 with your LXC ID):
pct exec 201 -- id immich
Expected output looks something like: uid=999(immich) gid=991(immich). The exact GID may vary — 991, 996, or another value depending on what else was installed. What matters is the UID: with default unprivileged LXC mapping, uid=999 inside maps to uid=100999 on the host.
Fix Permissions on ZFS Datasets
On the Proxmox host:
# Immich working data (thumbs, encoded-video, DB backups)
chown -R 100999:100000 /datastore/immich
chmod -R 770 /datastore/immich
# OneDrive photos — read-only, so immich only needs execute + read
chown -R 100999:100000 /datastore/onedrive/personal
chmod -R 750 /datastore/onedrive/personal
⚠️ If
/datastore/onedrive/personalis owned by a different user (e.g. the rclone sync process user), you may need to add that user to a shared group instead. The key requirement is thatuid=100999on the host can read the directory.
Add Both Bind Mounts
⚠️ If you enabled Container Protection during install, you must disable it first before making any changes — otherwise
pct setwill fail with “protection mode enabled”:pct set 201 --protection 0Re-enable it after you’re done with the configuration changes.
pct stop 201
# Immich working data — read/write
pct set 201 -mp0 /datastore/immich,mp=/mnt/immich
# OneDrive photos — read-only
# Point to the specific subfolder that contains your photos, not the root
pct set 201 -mp1 /datastore/onedrive/YOUR_ACCOUNT/Pictures,mp=/mnt/onedrive,ro=1
# Re-enable protection
pct set 201 --protection 1
pct start 201
Verify from the host:
pct exec 201 -- ls -la /mnt/immich
pct exec 201 -- ls /mnt/onedrive
/mnt/immich should be owned by immich:root. /mnt/onedrive should show your photo folders and albums. ✅
💡 Which subfolder to mount? Don’t mount the entire OneDrive root — mount only the folder that contains photos. In a typical OneDrive structure this is
PicturesorPhotos. Check what’s inside your sync folder withls /YOUR_POOL/onedrive/YOUR_ACCOUNT/and pick the right subdirectory.
📦 Step 3: Move the Upload Location to ZFS
By default the installer puts Immich working data under /opt/immich/upload on the LXC disk. For a proper Immich on Proxmox with ZFS setup, we redirect this to the ZFS mount before Immich processes any photos.
Enter the container:
pct enter 201
Stop Immich Services
systemctl stop immich-web immich-ml
Create the Folder Structure on ZFS
Immich requires specific subdirectories with hidden .immich marker files:
for dir in library thumbs encoded-video profile backups upload; do
mkdir -p /mnt/immich/$dir
touch /mnt/immich/$dir/.immich
done
chown -R immich:immich /mnt/immich
Update the .env File
nano /opt/immich/.env
Set:
IMMICH_MEDIA_LOCATION=/mnt/immich
Recreate the Symlinks
rm /opt/immich/app/upload
rm /opt/immich/app/machine-learning/upload
ln -sf /mnt/immich /opt/immich/app/upload
ln -sf /mnt/immich /opt/immich/app/machine-learning/upload
Restore Ownership and Start
chown -R immich:immich /opt/immich
systemctl start immich-ml immich-web
tail -f /var/log/immich/web.log
Wait for the server to come up cleanly, then confirm the correct storage path in Administration → Storage. 🖥️
Official guide for upload location change: https://github.com/community-scripts/ProxmoxVE/discussions/5075
🖼️ Step 4: Add the OneDrive Folder as External Library
This is the core of the Immich on Proxmox with ZFS setup — connecting your existing photo archive to Immich’s search engine without moving a single file. 📚
In the Immich web UI:
- Go to Administration → Libraries
- Click Create Library → External Library
- Set the Import path to
/mnt/onedrive(the path inside the container) - Leave Delete assets after removal disabled — this is a read-only source
- Click Save
- Click Scan Library to start the initial import
Immich crawls /mnt/onedrive, generates thumbnails on ZFS, runs face detection, and adds everything to the timeline. For a large collection this takes several hours — progress is visible in Administration → Jobs. ⏳
Key things to know about External Libraries:
- 📝 Originals are never copied — Immich only stores thumbnails and metadata on ZFS
- 🔍 Face recognition and semantic search work fully on External Library photos
- 🔄 Set up periodic re-scan under Library settings so new OneDrive photos get picked up automatically
- ❌ You cannot upload to an External Library — it’s read-only by design
Official External Library docs: https://immich.app/docs/features/libraries
👥 Step 5: Create Family Member Accounts
Go to Administration → Users → Create User for each family member. Each person gets their own login and timeline view. 👨👩👧👦
A few things to note for this Immich on Proxmox with ZFS setup:
- The External Library (OneDrive photos) is associated with the admin account by default
- You can share albums from the External Library to other users
- If family members need access from outside the home network, WireGuard VPN on Proxmox is the cleanest approach — no open ports, works on every device 🔒
☁️ Step 6: Backup Immich-Generated Data
The photo originals are safe in OneDrive — no action needed there. But Immich generates its own data on ZFS that is worth backing up: thumbnails, encoded video previews, and most importantly the PostgreSQL database which contains all your face tags, albums, and search index.
The database is automatically backed up by Immich to /mnt/immich/backups on a schedule. Confirm this is enabled in Administration → Jobs → Database Backup.
To back up the Immich ZFS data offsite:
# Install rclone inside the container
curl https://rclone.org/install.sh | bash
# Configure your remote (OneDrive, Backblaze B2, etc.)
rclone config
Nightly backup script:
cat > /opt/backup-immich.sh << 'EOF'
#!/bin/bash
LOG="/var/log/immich-backup.log"
echo "$(date): Starting Immich data backup" >> $LOG
# We only backup Immich-generated data — originals are already in OneDrive
rclone sync /mnt/immich/backups onedrive:immich-db-backups \
--transfers 2 \
--log-file="$LOG" \
--log-level INFO
echo "$(date): Done" >> $LOG
EOF
chmod +x /opt/backup-immich.sh
crontab -e
# Add: 0 4 * * * /opt/backup-immich.sh
💡 The photo originals in
/datastore/onedrive/personalare already in Microsoft’s cloud — no need to rclone them anywhere else.
Rclone docs: https://rclone.org/onedrive/
🔄 Step 7: Keeping Immich Updated
Updating Immich on Proxmox with ZFS is a single command from inside the container shell:
pct enter 201
update
⚠️ Community Scripts pins Immich to a tested version — you may be a release or two behind upstream. The update script automatically recreates symlinks using
IMMICH_MEDIA_LOCATIONfrom your.env, so the ZFS mount stays intact. 🛡️
Check Immich releases to see what version is current.
⚡ Step 8: ZFS Tuning
A few tweaks make Immich on Proxmox with ZFS noticeably snappier — especially for thumbnail loading.
ARC Cache
ZFS caches frequently read data in RAM. With a generous ARC, repeated thumbnail loads feel instant. Check current ARC size:
cat /proc/spl/kstat/zfs/arcstats | grep -E "^size|^c_max"
Cap it if you need RAM for other VMs:
# Example: limit to 8GB
echo "options zfs zfs_arc_max=8589934592" > /etc/modprobe.d/zfs.conf
update-initramfs -u
Monthly Scrub
Proxmox schedules ZFS scrubs automatically. Verify:
cat /etc/cron.d/zfsutils-linux
Scrubs detect and correct silent bit rot. For a photo archive holding years of irreplaceable memories, this matters. ✅
🎯 Key Takeaways
Immich on Proxmox with ZFS used as a search layer on top of OneDrive gives you the best of both worlds:
- ✅ Photos stay in OneDrive — cloud redundancy, mobile sync, sharing all intact
- ✅ Face recognition and semantic search — find any photo in seconds
- ✅ Zero duplication — External Library indexes originals without copying them
- ✅ ZFS self-healing — thumbnail data protected against silent corruption
- ✅ One-command updates via Community Scripts
- ✅ Your data, your server — no subscription, no algorithmic timeline, no ads
The setup takes an afternoon. The result is a family photo archive that’s both safe and actually searchable. 💾
📚 Official Documentation
- Immich Documentation
- Community Scripts — Immich
- Community Scripts — Upload Location Guide
- Immich External Libraries
- Proxmox ZFS on Linux
- Proxmox LXC Documentation
- rclone OneDrive
Always get the latest install command from community-scripts.org/scripts/immich — it may change between releases.
