Self-Hosting Photo Management: Immich on Debian Linux (Mobile Backup, CLIP Vector Search & HW Acceleration)
Executive Summary: Immich is the fastest-growing open-source self-hosted project for replacing Google Photos and Apple iCloud Photos. Built with a NestJS (TypeScript) backend, a dedicated Python Machine Learning (
ONNXRuntime) microservice, Redis/Valkey job queues, and PostgreSQL with vector similarity indexing (pgvecto.rs/VectorChord), Immich delivers instant timeline scrubbing, background iOS/Android camera-roll auto-upload, local facial recognition, and natural-language CLIP semantic search (e.g., searching "sunset over mountains with a dog" across 100,000 photos completely offline).
-
Native iOS & Android Auto-Backup
Back up Live Photos, ProRAW, and 4K60 videos automatically in the background whenever your phone connects to home Wi-Fi or WireGuard.
-
Offline CLIP Semantic Search
Run
ViT-B-32/XLM-Robertavision-language models locally viaimmich-machine-learningand query embeddings in PostgreSQL. -
Facial Clustering & Memories
Group family members automatically with local
InsightFacedetection, timeline "On This Day" memories, and shared partner albums. -
Hardware Video & ML Acceleration
Accelerate video transcoding (
QSV/VA-API/NVENC) and ONNX ML inference using/dev/driGPU device passthrough.
1. Immich Microservice Architecture
Immich separates interactive API requests from heavy asynchronous background tasks (thumbnail generation, video transcoding, and ONNX neural network inference) via Redis/Valkey queues:
%%{init: {'flowchart': {'wrappingWidth': 600}}}%%
flowchart TB
APP["📱 Immich iOS / Android App<br/>& Web Timeline UI<br/>(HTTPS via Reverse Proxy)"]
SRV["🚀 immich-server (NestJS)<br/>127.0.0.1:2283<br/>API + Background Workers"]
REDIS["⚡ Valkey / Redis 7<br/>BullMQ Job Queue<br/>(Thumbnails & Transcode)"]
ML["🧠 immich-machine-learning<br/>Python ONNX Runtime<br/>(CLIP + InsightFace)"]
PG["🗄️ PostgreSQL + Vector Index<br/>Metadata + 512-Dim Vectors"]
APP <--> SRV
SRV <--> REDIS
SRV <-->|"gRPC / HTTP Inference"| ML
SRV <-->|"Vector Cosine Search"| PG
2. Production compose.yaml & .env Configuration on Debian
Store high-capacity photo/video uploads (UPLOAD_LOCATION) on your redundant storage array (ZFS / RAID1), while keeping the PostgreSQL vector database (DB_DATA_LOCATION) strictly on local NVMe SSD for sub-millisecond timeline scrolling:
# File: /srv/containers/immich/.env
IMMICH_VERSION=release
TZ=Europe/Berlin
# Large media library storage (NAS / RAID pool)
UPLOAD_LOCATION=/srv/media/immich-library
# Fast local NVMe SSD path for PostgreSQL vector index!
DB_DATA_LOCATION=/srv/containers/immich/postgres
DB_USERNAME=postgres
DB_DATABASE_NAME=immich
DB_PASSWORD=Replace_With_Strong_Alphanumeric_Password_2026
# File: /srv/containers/immich/compose.yaml
services:
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
depends_on:
- redis
- database
restart: unless-stopped
ports:
- "127.0.0.1:2283:2283/tcp"
env_file:
- .env
devices:
- /dev/dri:/dev/dri
volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload:rw
- /etc/localtime:/etc/localtime:ro
immich-machine-learning:
container_name: immich_machine_learning
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
restart: unless-stopped
env_file:
- .env
volumes:
- /srv/containers/immich/model-cache:/cache:rw
redis:
container_name: immich_redis
image: docker.io/valkey/valkey:8-bookworm
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "valkey-cli ping || exit 1"]
database:
container_name: immich_postgres
image: docker.io/tensorchord/pgvecto-rs:pg16-v0.2.0
restart: unless-stopped
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
POSTGRES_INITDB_ARGS: "--data-checksums"
volumes:
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data:rw
3. Reverse Proxy Requirements (Large Video Upload Streaming!)
Mobile phones regularly upload 4K60 video files exceeding 2 GB–10 GB. If your reverse proxy (Nginx or Nginx Proxy Manager) enforces its default client_max_body_size 1m;, every video backup will fail with HTTP 413 Request Entity Too Large!
- In Caddy: Unlimited request body size and WebSocket streaming work out of the box with zero extra directives (
reverse_proxy 127.0.0.1:2283). - In Nginx / NPM: Explicitly configure:
# File: /etc/nginx/snippets/immich-proxy.conf
client_max_body_size 50000M;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
send_timeout 600s;
4. Storage Template & External Library Best Practices
- Enable Storage Template: In Administration → Settings → Storage Template, enable the template engine (
{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}) so uploaded photos are organized cleanly on disk by year and date (2026/2026-11-06/IMG_4021.HEIC) rather than opaque UUID folders. - External Libraries: If you also have an existing DSLR photo archive on disk, mount it into
immich-serverwith:ro(Read-Only) and register it under Administration → External Libraries so Immich indexes it without moving or modifying the original files.
Where to Go Next
Pair Immich with off-site encrypted backups, WireGuard remote access, and Nextcloud file sync:
-
PhotoPrism RAW Archive Manager
Compare Immich's mobile cloud focus with PhotoPrism's DSLR RAW and WebDAV archive workflow.
-
WireGuard VPN Server
Keep Immich completely private off the public internet while auto-backing up photos from your phone via On-Demand WireGuard VPN.
-
BorgBackup + Borgmatic
Automate daily deduplicated backups of
/srv/media/immich-libraryand PostgreSQL dumps.