diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json index c1937f9..cfcafff 100644 --- a/.obsidian/workspace.json +++ b/.obsidian/workspace.json @@ -97,12 +97,12 @@ "state": { "type": "markdown", "state": { - "file": "2 Personal/Home Lab/NAS/homelab_backup_architecture_first_draft.md", + "file": "2 Personal/Home Lab/NAS/immich_v1_setup.md", "mode": "source", "source": false }, "icon": "lucide-file", - "title": "homelab_backup_architecture_first_draft" + "title": "immich_v1_setup" } }, { @@ -491,8 +491,9 @@ }, "active": "f33efed5601c1085", "lastOpenFiles": [ - "2 Personal/Home Lab/NAS/Virtual Machine Hosting.md", "2 Personal/Home Lab/NAS/homelab_backup_architecture_first_draft.md", + "2 Personal/Home Lab/NAS/immich_v1_setup.md", + "2 Personal/Home Lab/NAS/Virtual Machine Hosting.md", "2 Personal/Home Lab/NAS/Maintenance Plan.md", "2 Personal/Home Lab/NAS/Photo Apps.md", "2 Personal/Home Lab/MAC/Software Management on MacOS.md", @@ -518,7 +519,6 @@ "2 Personal/Home Lab/Devices/Dell Studio 1558.md", "0 Journal/0 Daily/2026-02-04.md", "99 Work/Jobhunt/Interview Questions.md", - "Temporary/My Health Products.md", "Attachments/Pasted image 20260121121234.png", "Attachments/ESPSomfyRTS 2026-01-18T16_26_16.backup", "Attachments/Pasted image 20260118150817.png", diff --git a/2 Personal/Home Lab/NAS/immich_v1_setup.md b/2 Personal/Home Lab/NAS/immich_v1_setup.md new file mode 100644 index 0000000..e143e83 --- /dev/null +++ b/2 Personal/Home Lab/NAS/immich_v1_setup.md @@ -0,0 +1,398 @@ +# 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 the docs describe that by 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.