Files
Main/2 Personal/Home Lab/NAS/immich_v1_setup.md
Obsidian-MBPM4 31e9ecf447 vault backup: 2026-03-31 12:52:27
Affected files:
2 Personal/Home Lab/NAS/immich_v1_setup.md
2026-03-31 12:52:27 +02:00

399 lines
12 KiB
Markdown

# Immich V1 setup on Proxmox + Synology NAS + Authentik + Pangolin
## Goal
Set up **Immich first**, on a **full Linux VM in Proxmox** (not Docker inside LXC), with:
- **media storage on a Synology NAS share**
- **database on local VM storage**
- **OIDC login via Authentik**
- **public access through Pangolin**
- **Synology snapshots enabled** for the media share
This is the right V1 shape because Immich recommends Linux, Docker Compose, and a **full VM** when virtualized. It also explicitly says the **Postgres database should ideally use local SSD storage and never a network share**. The reverse proxy must forward the right headers, allow large uploads, and Immich must be served at the root of a domain/subdomain rather than a sub-path.
Sources: Immich Requirements, Reverse Proxy, OAuth Authentication.
---
## Recommended architecture
```mermaid
flowchart LR
subgraph Internet
U[Users / Immich mobile app / browser]
end
subgraph Edge
P[Pangolin\nTLS + public entrypoint]
end
subgraph Prod[Proxmox production]
VM[Debian/Ubuntu VM\nDocker Compose\nImmich server + ML + Redis + Postgres]
DB[(Postgres data\nlocal VM disk)]
CFG[(Compose files/.env\nlocal VM disk)]
end
subgraph NAS[Synology NAS]
NFS[NFS share for Immich upload library]
SNAP[Synology snapshots]
HB[Hyper Backup / offsite replication later]
end
subgraph IdP[Identity]
AK[Authentik\nOIDC provider]
end
U --> P --> VM
VM --> AK
VM --> DB
VM --> CFG
VM --> NFS
NFS --> SNAP
SNAP --> HB
```
---
## Hard recommendations
### Do this
1. **Run Immich in a VM, not an LXC.**
2. Put **Postgres on local VM storage**.
3. Put **Immich upload/media storage on the NAS** using a **Unix-compatible mounted path**.
4. Use **OIDC with Authentik**, but **keep local password login enabled until OIDC works**.
5. Publish Immich on its own subdomain, for example `immich.example.com`.
6. Use a **dedicated Synology shared folder** for Immich media.
7. Turn on **Btrfs snapshots** on that shared folder.
### Do not do this
1. **Do not put `DB_DATA_LOCATION` on the NAS.**
2. **Do not serve Immich on a sub-path** like `https://example.com/immich`.
3. **Do not expose port 2283 directly to the internet**.
4. **Do not use the NAS share for everything**. Only media belongs there; DB does not.
---
## Best-practice V1 decision: primary upload storage vs external library
For a fresh setup, use the NAS-mounted path as **Immich's main `UPLOAD_LOCATION`**.
Use **External Libraries** only if you already have existing folders on the NAS that Immich should **index without owning**. External libraries need the directory mounted into the container too, and tcby adding additional volume mounts.
Source: Immich External Library guide.
So for V1:
- `UPLOAD_LOCATION` -> NAS share mounted in the VM
- Postgres data -> local VM disk
- Optional later: extra read-only external libraries from other NAS folders
---
## V1 implementation plan
### 1. Create a dedicated Proxmox VM
Use a **Debian 12** or **Ubuntu 24.04 LTS** VM.
Suggested starting size:
- 4 vCPU
- 8 GB RAM
- 40-80 GB local SSD/NVMe disk for OS + Docker + Postgres + cache
Immich's current requirements say:
- Linux or Unix-like 64-bit OS recommended
- minimum **6 GB RAM**, recommended **8 GB**
- minimum **2 cores**, recommended **4**
- in a virtualized environment, a **full VM** is recommended
- storage should support Unix ownership/permissions
- the **Postgres database should ideally use local SSD storage and never a network share**
Source: Immich Requirements.
### 2. Create a dedicated Synology shared folder for Immich
Create something like:
- Shared folder: `immich-prod`
Inside it, keep it simple. Let Immich create its own structure under `UPLOAD_LOCATION`.
Do **not** manually invent a lot of subdirectories unless you have a reason.
### 3. Export that Synology folder to the VM
Prefer **NFS** from Synology to the Linux VM.
Reason:
- cleaner Linux permissions model than SMB for this use case
- easier predictable mount behavior inside a Linux VM
Mount it in the VM, for example:
- NAS export -> VM mountpoint: `/srv/immich-upload`
Then point Immich `UPLOAD_LOCATION` there.
### 4. Keep local storage for DB and configs
Example local paths in the VM:
- `/opt/immich` -> compose files
- `/var/lib/immich-postgres` -> database data
- `/var/lib/immich-model-cache` -> model cache
The important part is that the Postgres path stays **local**, not on the NAS.
Source: Immich Requirements.
### 5. Install Docker Engine + Compose plugin in the VM
Immich requires Docker with the Compose plugin and explicitly requires the command `docker compose`; `docker-compose` is deprecated and no longer supported by Immich.
Source: Immich Requirements.
### 6. Deploy Immich with Docker Compose
Use the official compose example from Immich and modify only what matters:
- `UPLOAD_LOCATION=/srv/immich-upload`
- `DB_DATA_LOCATION=/var/lib/immich-postgres`
- model cache on local disk
- bind only to the VM internally; Pangolin handles public entry
### 7. Configure Pangolin
Publish Immich via Pangolin on its own subdomain.
Important reverse-proxy requirements from Immich:
- forward `Host`
- forward `X-Real-IP`
- forward `X-Forwarded-Proto`
- forward `X-Forwarded-For`
- allow **large uploads**
- Immich must be on the **root path of a domain/subdomain**
Source: Immich Reverse Proxy docs.
### 8. Configure Authentik OIDC for Immich
Immich supports OIDC and explicitly lists Authentik among supported identity providers.
Source: Immich OAuth Authentication.
Create an application/provider pair in Authentik using **OAuth2/OIDC**. Authentik recommends creating the application and provider together via **Applications -> Applications -> Create with provider**.
Source: Authentik Create an OAuth2 provider.
Use these redirect URIs in Authentik:
- `app.immich:///oauth-callback`
- `https://immich.example.com/auth/login`
- `https://immich.example.com/user-settings`
Immich requires the mobile redirect URI `app.immich:///oauth-callback` for iOS/Android app login to work properly.
Source: Immich OAuth Authentication.
Then in Immich Admin -> Settings -> OAuth:
- enable OAuth
- set issuer URL to the Authentik OIDC discovery URL
- set client ID / secret
- scope: `openid email profile`
- auto-register: on
- auto-launch: optional, keep off in V1
### 9. Keep password login enabled initially
Do not lock yourself out.
First:
- create the initial local Immich admin
- verify normal web login
- configure OIDC
- verify browser login
- verify mobile login
- only then decide whether to disable password login
Immich allows disabling password authentication instance-wide, but that can lock everyone out if OAuth is also broken.
Source: Immich System Settings.
### 10. Enable Synology snapshots
Because your Synology is Btrfs, this is a good fit.
Enable snapshots on the `immich-prod` shared folder.
Good V1 retention example:
- every hour for 24 hours
- every day for 14 days
- every week for 8 weeks
That gives you fast rollback for accidental deletion or a bad import.
Important caveat: snapshots help with rollback, but the full backup still also needs the Immich database and a true backup destination later.
---
## Concrete directory layout
### In the VM
```text
/opt/immich/ # compose + .env
/var/lib/immich-postgres/ # local postgres data
/var/lib/immich-model-cache/ # local ML cache
/srv/immich-upload/ # NFS mount from Synology
```
### On Synology
```text
Shared folder: immich-prod
\- mounted into VM as /srv/immich-upload
```
Immich will create and use directories under `UPLOAD_LOCATION`, including backups for automatic DB dumps. Immich stores automatic database backups in `UPLOAD_LOCATION/backups`, and those backups only contain metadata, not the photos/videos.
Source: Immich Backup and Restore.
---
## Example Compose shape
This is **not** a full copy of the official file. It is the shape that matters.
```yaml
services:
immich-server:
image: ghcr.io/immich-app/immich-server:release
env_file:
- .env
volumes:
- ${UPLOAD_LOCATION}:/data
ports:
- "2283:2283"
depends_on:
- redis
- database
immich-machine-learning:
image: ghcr.io/immich-app/immich-machine-learning:release
env_file:
- .env
volumes:
- /var/lib/immich-model-cache:/cache
redis:
image: redis:6.2-alpine
database:
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.0-pgvectors0.8.1
env_file:
- .env
volumes:
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
```
And the key bits in `.env`:
```env
UPLOAD_LOCATION=/srv/immich-upload
DB_DATA_LOCATION=/var/lib/immich-postgres
```
Use the exact current compose file and image tags from the Immich docs/release example when you deploy, not a random blog post. Immich has changed its Postgres/vector extension story over time and currently documents VectorChord-based setups and upgrade cautions.
Sources: Immich Requirements, Upgrading, Pre-existing Postgres.
---
## Pangolin-specific guidance
Pangolin is an identity-aware remote access platform combining reverse proxy and VPN-style connectivity. For this use case, the key point is: use Pangolin only as the **public entrypoint**, and keep Immich itself private behind it.
Source: Pangolin GitHub README.
For Immich specifically, make sure Pangolin is configured so that:
- the service is published on a **dedicated host/subdomain**
- uploads are allowed to be large enough
- timeouts are not too short for big videos
- forwarded headers match what Immich expects
Because Immich documents strict reverse-proxy expectations, do not rely on defaults you have not checked.
Source: Immich Reverse Proxy docs.
---
## Authentik-specific guidance
In Authentik:
1. Create an application/provider pair with **OAuth2/OIDC**.
2. Use **Authorization Code** flow.
3. Use a **confidential** web client.
4. Add all redirect URIs you will actually use.
Immich's OAuth docs say the redirect URIs should include:
- mobile callback
- web login callback
- user settings callback
and they should contain all domains used to access Immich.
Source: Immich OAuth Authentication.
---
## What to back up for Immich in this design
You need both:
1. **`UPLOAD_LOCATION`** on the NAS
2. **the database**
Immich says a comprehensive backup includes both uploaded photos/videos and the Immich database. It also says the automatic database backups are stored in `UPLOAD_LOCATION/backups`, but these backups contain only metadata, not photos/videos.
Source: Immich Backup and Restore.
In your design that means:
- NAS snapshots protect the media path and DB backup files stored under `UPLOAD_LOCATION/backups`
- local-VM backup later must also protect `/var/lib/immich-postgres` or you rely on Immich DB dumps inside `UPLOAD_LOCATION/backups`
For V1, I would still enable Immich automatic DB backups in the UI.
---
## Minimum test plan for today
1. VM boots and NFS mount is present at `/srv/immich-upload`
2. `docker compose up -d` starts all Immich services
3. local browser login works on `http://VM-IP:2283`
4. upload one test image and one test video
5. verify files appear on Synology share
6. configure Pangolin and verify public HTTPS access
7. configure Authentik OIDC and verify browser login
8. verify mobile app login using OIDC
9. create a manual DB backup in Immich and confirm it appears under `UPLOAD_LOCATION/backups`
10. create a Synology snapshot and verify the snapshot schedule is active
---
## Final recommendation
For your **V1 today**, the clean setup is:
- **Proxmox VM** for Immich
- **Docker Compose** inside the VM
- **local VM disk** for Postgres and local runtime state
- **Synology NFS share** for `UPLOAD_LOCATION`
- **Synology Btrfs snapshots** on that shared folder
- **Pangolin** for public HTTPS exposure
- **Authentik OIDC** for login
That is the right compromise between best practice and what you want to achieve right now.
## The one thing not to compromise on
Do **not** place the Immich Postgres data on the NAS share. That is the main thing Immich explicitly warns against.
Source: Immich Requirements.