diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json index cfcafff..941ae82 100644 --- a/.obsidian/workspace.json +++ b/.obsidian/workspace.json @@ -97,12 +97,12 @@ "state": { "type": "markdown", "state": { - "file": "2 Personal/Home Lab/NAS/immich_v1_setup.md", + "file": "2 Personal/Home Lab/NAS/immich_v1.1_setup.md", "mode": "source", "source": false }, "icon": "lucide-file", - "title": "immich_v1_setup" + "title": "immich_v1.1_setup" } }, { @@ -491,8 +491,9 @@ }, "active": "f33efed5601c1085", "lastOpenFiles": [ - "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/immich_v1.1_setup.md", + "2 Personal/Home Lab/NAS/homelab_backup_architecture_first_draft.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", @@ -518,7 +519,6 @@ "99 Work/0 OneSec/OneSecNotes/Handover Planning.md", "2 Personal/Home Lab/Devices/Dell Studio 1558.md", "0 Journal/0 Daily/2026-02-04.md", - "99 Work/Jobhunt/Interview Questions.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.1_setup.md b/2 Personal/Home Lab/NAS/immich_v1.1_setup.md new file mode 100644 index 0000000..5fad300 --- /dev/null +++ b/2 Personal/Home Lab/NAS/immich_v1.1_setup.md @@ -0,0 +1,771 @@ +# Immich V1 setup on Proxmox + Synology NAS + Authentik + Pangolin + +## Status + +This document is the **ground truth** for the current Immich V1 deployment and the first troubleshooting reference. + +Current state: + +- **Platform:** Proxmox VM +- **Guest OS:** Debian 13 server, headless +- **Networking:** LAN IP via DHCP reservation, plus ZeroTier installed +- **Container runtime:** Docker + Docker Compose +- **Immich deployment:** official Immich `docker-compose.yml` +- **Storage model:** + - **media/library on Synology NAS via NFS** + - **Postgres on local VM storage** +- **Planned next steps:** Authentik OIDC login, Pangolin public reverse proxy, Synology snapshots verification + +--- + +## Why this architecture + +This is the correct V1 shape because: + +- Immich recommends a **full VM** in virtualized environments, not Docker in LXC. +- Immich recommends **Docker Compose** for normal deployment. +- Immich explicitly states that the **Postgres database should stay on local SSD storage and not on a network share**. +- Synology **Btrfs snapshots** are a good fit for the media share. +- NFS is a cleaner Linux-to-Linux storage mount than SMB for this use case. + +--- + +## Current implemented architecture + +```mermaid +flowchart LR + subgraph Users + U1[Browser users] + U2[Immich mobile app users] + U3[Admin via SSH] + end + + subgraph Edge + ZT[ZeroTier] + PG[Pangolin - planned] + end + + subgraph Proxmox + VM[Debian 13 VM\nimmich-vm] + DC[Docker Compose] + IS[Immich Server] + IML[Immich ML] + R[(Redis)] + DB[(Postgres\nlocal disk)] + CFG[/opt/immich-app\ncompose + .env/] + NFSM[/mnt/immich-prod\nNFS mount/] + end + + subgraph Synology + SHARE[Shared folder: immich-prod] + SNAP[Snapshots - to configure/verify] + end + + subgraph Identity + AK[Authentik - planned] + end + + U3 --> ZT --> VM + U1 --> PG --> IS + U2 --> PG --> IS + VM --> DC + DC --> IS + DC --> IML + DC --> R + DC --> DB + IS --> NFSM + IML --> NFSM + NFSM --> SHARE + SHARE --> SNAP + IS --> AK +``` + +--- + +## VM build decisions + +### Guest type + +- **Debian 13 server/headless** +- No desktop environment +- SSH server installed +- Standard system utilities installed + +### Proxmox VM settings used/recommended + +- **Machine type:** `q35` +- **BIOS:** `OVMF (UEFI)` +- **Graphics:** default / minimal, no desktop needed +- **CPU type:** ideally `host` + - acceptable fallback: `x86-64-v2-AES` +- **vCPU:** 4 +- **RAM:** 8 GB recommended +- **Disk:** local SSD-backed VM disk, enough for OS + Docker + Postgres + - good V1 default: **64 GB** +- **NIC model:** VirtIO + +### Why + +- `q35` + `OVMF` is the modern sane default. +- Debian headless keeps the VM simple and low-maintenance. +- Immich itself does not need a GUI on the host. +- Local disk is used for DB because the DB must **not** live on NFS. + +--- + +## Directory layout + +### On the VM + +```text +/opt/immich-app/ +├── docker-compose.yml +├── .env +└── postgres/ + +/mnt/immich-prod/ +├── library/ +└── model-cache/ # optional, if you keep ML cache here +``` + +### Why this layout + +- `/opt/immich-app` is for the **application deployment**, not user files. +- `/mnt/immich-prod` is the mounted NAS share. +- `postgres/` stays on **local VM storage**. +- Do **not** put the project under `/home/cef/...` for production-style operation. + +--- + +## Installed packages / components + +Installed on the VM: + +- `docker` +- `docker compose` +- `zerotier` +- `nfs-common` +- `sudo` + +Useful verification commands: + +```bash +docker --version +docker compose version +zerotier-cli info +showmount -e 192.168.1.34 +mount | grep immich +``` + +--- + +## Synology NFS setup + +### NAS + +- **Synology IP:** `192.168.1.34` +- **Shared folder / export:** `/volume1/immich-prod` +- **Allowed client:** `192.168.1.52` + +Verified export list: + +```bash +sudo showmount -e 192.168.1.34 +``` + +Expected output: + +```text +Export list for 192.168.1.34: +/volume1/Downloads 192.168.1.35/24 +/volume1/immich-prod 192.168.1.52 +``` + +### VM mountpoint + +```bash +sudo mkdir -p /mnt/immich-prod +``` + +### Manual mount command + +```bash +sudo mount -t nfs 192.168.1.34:/volume1/immich-prod /mnt/immich-prod +``` + +### Important typo that already happened once + +Wrong: + +```bash +sudo mount -t nfs 192.168.1.34:/volumel/immich-prod /mnt/immich-prod +``` + +Correct: + +```bash +sudo mount -t nfs 192.168.1.34:/volume1/immich-prod /mnt/immich-prod +``` + +The mistake was **`volumel`** with letter `l` instead of **`volume1`** with number `1`. + +### Recommended persistent mount in `/etc/fstab` + +Use this: + +```fstab +192.168.1.34:/volume1/immich-prod /mnt/immich-prod nfs rw,hard,_netdev,x-systemd.automount,noatime 0 0 +``` + +Then test it: + +```bash +sudo mount -a +mount | grep immich-prod +df -h | grep immich-prod +``` + +### Why these mount options + +- `rw` -> read/write +- `hard` -> keep retrying if the NAS drops briefly +- `_netdev` -> network-dependent mount +- `x-systemd.automount` -> avoids ugly boot timing issues +- `noatime` -> reduces metadata writes + +--- + +## Immich deployment files + +### Project directory + +```bash +cd /opt/immich-app +``` + +### Compose file + +Use the **official Immich release** `docker-compose.yml` unchanged unless there is a specific reason to change it. + +This is important because: + +- the official file stays aligned with the current release +- random blog versions drift +- hand-written compose files become future maintenance debt + +### Current `.env` + +Current deployment values: + +```dotenv +# You can find documentation for all the supported env variables at https://docs.immich.app/install/environment-variables + +# The location where your uploaded files are stored +UPLOAD_LOCATION=/mnt/immich-prod/library + +# The location where your database files are stored +# MUST stay on local VM storage, not on NFS +DB_DATA_LOCATION=/opt/immich-app/postgres + +# Set your timezone +TZ=Europe/Zurich + +# Immich Settings +IMMICH_ENV=production + +# Immich version +IMMICH_VERSION=v2 + +# Database credentials +# Use only A-Za-z0-9 for this value +DB_PASSWORD=my-secret-pw. # See Lastpass + +# Usually leave these as default unless you have a reason to change them +DB_USERNAME=postgres +DB_DATABASE_NAME=immich +``` + +### Why these values are correct + +- `UPLOAD_LOCATION=/mnt/immich-prod/library` + - correct because media belongs on the NAS share +- `DB_DATA_LOCATION=/opt/immich-app/postgres` + - correct because DB must stay local +- `TZ=Europe/Zurich` + - good operational default +- `IMMICH_ENV=production` + - correct for this VM +- `IMMICH_VERSION=v2` + - matches current official release convention + +--- + +## Useful Docker commands + +### Start / recreate stack + +```bash +cd /opt/immich-app +docker compose up -d +``` + +### Stop stack + +```bash +cd /opt/immich-app +docker compose down +``` + +### See running containers + +```bash +docker ps +``` + +### Follow logs + +```bash +cd /opt/immich-app +docker compose logs -f +``` + +### Follow a single service log + +```bash +docker compose logs -f immich-server +docker compose logs -f database +docker compose logs -f redis +docker compose logs -f immich-machine-learning +``` + +### Restart stack + +```bash +docker compose restart +``` + +### Pull updated images later + +```bash +cd /opt/immich-app +docker compose pull +docker compose up -d +``` + +--- + +## Current data model + +### Media + +Stored on NAS via: + +```text +/mnt/immich-prod/library +``` + +This means: + +- media is on Synology storage +- Synology snapshots can protect it +- the actual photos/videos do **not** live on the VM disk + +### Database + +Stored locally via: + +```text +/opt/immich-app/postgres +``` + +This means: + +- DB is not exposed to NFS consistency problems +- VM backup strategy must include this path +- DB and media are separate backup concerns + +### Automatic Immich DB backups + +Immich also stores automatic DB dumps under the upload location, typically in: + +```text +UPLOAD_LOCATION/backups +``` + +Those backups contain **metadata only**, not the photo/video files. + +So: + +- NAS snapshots help protect media and DB dump files +- but media + DB are still two separate pieces of the system + +--- + +## Synology snapshots + +### Goal + +The `immich-prod` shared folder should have Synology snapshots enabled. + +### Why + +This gives: + +- fast rollback after accidental deletion +- protection against bad imports or user mistakes +- short-term recovery without touching full backups + +### Good V1 retention suggestion + +- hourly snapshots for 24 hours +- daily snapshots for 14 days +- weekly snapshots for 8 weeks + +### Important truth + +Snapshots are **not enough by themselves**. +They are rollback protection, not the full backup strategy. + +The real backup picture later must include: + +- Synology media share backup offsite +- VM / Postgres backup +- restore testing + +--- + +## Authentik plan + +Planned next phase: + +- configure Immich login through **Authentik OIDC** +- keep local Immich login enabled until OIDC is proven working + +### Important future redirect URIs + +When creating the Immich OIDC application/provider in Authentik, include: + +```text +app.immich:///oauth-callback +https://immich./auth/login +https://immich./user-settings +``` + +The mobile callback is required for app login. + +### Safe rollout rule + +Do this in order: + +1. verify local Immich admin login works +2. configure Authentik OIDC +3. test browser login +4. test mobile login +5. only then consider disabling password login + +--- + +## Pangolin plan + +Planned next phase: + +- expose Immich publicly through **Pangolin** +- do **not** expose port `2283` directly to the internet + +### Reverse proxy requirements for Immich + +The reverse proxy must correctly pass: + +- `Host` +- `X-Real-IP` +- `X-Forwarded-Proto` +- `X-Forwarded-For` + +It also must: + +- allow **large uploads** +- serve Immich on the **root of a subdomain**, not a sub-path + +Correct: + +```text +https://immich.example.com +``` + +Wrong: + +```text +https://example.com/immich +``` + +--- + +## Networking notes + +### DHCP reservation issue already seen + +The VM originally still held the old IP lease after a router DHCP reservation change. + +Fastest fix was simply: + +```bash +su - +reboot +``` + +Reason: + +- DHCP reservation does not always force immediate address change +- the client often keeps the old lease until renew/reboot/expiry + +### Current relevant IPs + +- **Synology NAS:** `192.168.1.34` +- **Immich VM:** `192.168.1.52` + +--- + +## Troubleshooting logbook + +### Problem: `sudo: command not found` + +Cause: + +- user did not yet have sudo available / configured + +Fix: + +```bash +su - +apt update +apt install sudo +usermod -aG sudo cef +reboot +``` + +--- + +### Problem: `apt update` permission denied / lock file errors + +Cause: + +- command was run as non-root user without sudo + +Fix: + +```bash +su - +apt update +``` + +--- + +### Problem: `showmount: command not found` + +Cause: + +- NFS client tools not installed yet + +Fix: + +```bash +sudo apt update +sudo apt install -y nfs-common +``` + +Then: + +```bash +sudo showmount -e 192.168.1.34 +``` + +--- + +### Problem: `mkdir: cannot create directory '/mnt/immich-prod': Permission denied` + +Cause: + +- `/mnt` requires root privileges + +Fix: + +```bash +sudo mkdir -p /mnt/immich-prod +``` + +--- + +### Problem: `mount.nfs: access denied by server while mounting ...` + +Actual cause in this case: + +- typo in mount source path: used `volumel` instead of `volume1` + +Correct command: + +```bash +sudo mount -t nfs 192.168.1.34:/volume1/immich-prod /mnt/immich-prod +``` + +If it happens again with the correct path, then check: + +1. Synology NFS service enabled +2. Synology export path correct +3. Synology NFS permissions allow `192.168.1.52` +4. VM actually has IP `192.168.1.52` +5. export visible via `showmount -e 192.168.1.34` + +--- + +### Problem: changed router DHCP reservation but VM kept old IP + +Cause: + +- client kept existing lease + +Fix: + +```bash +su - +reboot +``` + +Alternative debugging commands: + +```bash +ip a +networkctl +systemctl status systemd-networkd +``` + +--- + +### Problem: hidden `.env` file does not show in normal `ls` + +Cause: + +- dotfiles are hidden by default + +Fix: + +```bash +ls -la /opt/immich-app +``` + +--- + +## Operational rules + +### Rules to keep + +1. **Never move Postgres onto the NAS share.** +2. **Keep using the official Immich compose file.** +3. **Do not improvise custom Dockerfiles for V1.** +4. **Do not expose raw Immich directly to the internet.** Use Pangolin. +5. **Do not disable local login until Authentik login is proven working.** +6. **Keep the Synology shared folder dedicated to Immich.** +7. **Treat snapshots as rollback, not as the only backup.** + +### Rules for changes later + +If changing `.env` or updating Immich: + +```bash +cd /opt/immich-app +docker compose pull +docker compose up -d +``` + +If something acts weird after env changes: + +```bash +docker compose up -d --force-recreate +``` + +--- + +## What still needs to be done + +### Must do next + +1. verify `/etc/fstab` persistent NFS mount works across reboot +2. verify Synology snapshots are enabled on `immich-prod` +3. configure Authentik OIDC +4. configure Pangolin public access +5. test large upload through the reverse proxy +6. test Immich mobile login through OIDC + +### Should do soon + +1. rotate the DB password because it was shared in chat +2. document exact Pangolin config once implemented +3. document exact Authentik provider/app config once implemented +4. create first restore notes for: + - Immich DB + - media share + - full VM restore + +--- + +## Fast command reference + +### Check mount + +```bash +mount | grep immich +df -h | grep immich +ls -la /mnt/immich-prod +``` + +### Check Docker + +```bash +docker ps +docker compose logs -f +``` + +### Restart Immich + +```bash +cd /opt/immich-app +docker compose restart +``` + +### Full stack recreate + +```bash +cd /opt/immich-app +docker compose down +docker compose up -d +``` + +### Reboot VM + +```bash +sudo reboot +``` + +--- + +## Final blunt summary + +The current setup is on the right track. + +The important good decisions already made are: + +- full VM instead of LXC +- Debian server instead of desktop bloat +- official Immich compose +- media on NAS via NFS +- Postgres on local storage +- clear deployment path under `/opt/immich-app` + +The main things that can still hurt later are: + +- forgetting to persist and verify the NFS mount properly +- forgetting to enable/test Synology snapshots +- breaking login while introducing Authentik +- exposing Immich badly when adding Pangolin +- leaving the documented DB password unchanged + +This document should be updated after every meaningful change.