Immich: Self-Hosted Photo Management Guide
Privacy-first Google Photos alternative. Face recognition, smart search, and mobile auto-backup.
Introduction
Immich is an open-source, self-hosted photo and video management platform that provides a compelling alternative to Google Photos. Since reaching stable version 2.0 in October 2024, Immich has matured into a production-ready solution with over 86,500 GitHub stars and active development backed by FUTO (Freedom and Ubiquity Operating System).
Why Choose Immich Over Google Photos?
Complete Privacy and Data Ownership
With Immich, your photos never leave your hardware. Unlike Google Photos, which analyzes your images for AI training and integrates your data into their broader tracking ecosystem, Immich processes everything locally. Your family photos, personal moments, and location data remain entirely under your control.
One-Time Cost vs. Recurring Subscriptions
A typical Google Photos subscription costs $10/month ($120/year) for 2TB. Over 10 years, that’s $1,200. A modest Immich setup with a mini PC and storage costs $600-900 as a one-time investment, breaking even in just 6 months.
Unlimited Original Quality Storage
Google Photos limits free storage to 15GB, then requires paid tiers. Immich’s storage is limited only by your hardware. Install larger drives as needed, without monthly fees or arbitrary limits.
Production-Grade Features
- 99.8% accurate face recognition
- Semantic search powered by CLIP AI models
- Mobile apps for iOS and Android with background sync
- Multi-user support with granular sharing controls
- Hardware-accelerated video transcoding
- External library integration for existing photo collections
Understanding the Cost Comparison
Google Photos: 10-Year Total Cost
Free Tier: 15GB (inadequate for most families)
100GB Plan: $2/month × 120 months = $240
2TB Plan: $10/month × 120 months = $1,200
Family (6 users): Still $1,200 (shared storage)
Hidden Costs:
- Your photos used for AI training
- Location data harvested and monetized
- Facial biometrics extracted and stored
- Subject to terms of service changes Immich: 10-Year Total Cost
Hardware Investment Options:
Budget Setup:
- Mini PC: $200-300
- 2×4TB drives: $150-200
- Total: $400-500 upfront
- Electricity: $50-75/year × 10 = $500-750
- 10-year total: $900-1,250
Standard Setup (with GPU):
- Mini PC with NVIDIA GPU: $600-800
- 2×8TB drives: $300-400
- Total: $900-1,200 upfront
- Electricity: $75-100/year × 10 = $750-1,000
- 10-year total: $1,650-2,200
ROI Analysis:
- Budget setup breaks even vs. Google 2TB in 4-5 months
- After break-even, marginal cost approaches zero
- No recurring fees, no storage limits Prerequisites and System Requirements
Hardware Specifications
Minimum Configuration
- RAM: 4GB (6GB recommended for smooth performance)
- CPU: 2 cores (4+ cores for better ML performance)
- Storage: 100GB+ free space (plan for 1.2× your photo library size)
- Network: 1Gbps ethernet for local access
Recommended Configuration
- RAM: 8GB
- CPU: 4+ cores (Intel i5/i7 or AMD Ryzen 5/7)
- Storage: 2×8TB drives in RAID 1 (mirrored for redundancy)
- GPU: NVIDIA GTX 960+ or any RTX card for ML acceleration
- Network: Gigabit ethernet + WiFi for mobile devices
For Machine Learning Acceleration (Optional but Recommended)
- NVIDIA GPU with compute capability 5.2+
- 2-4GB VRAM minimum
- NVIDIA driver 535+ supporting CUDA 12.2
- Impact: Face recognition 10-30× faster, semantic search 15-50× faster
Software Requirements
- Docker Engine v25+ (includes docker-compose)
- Linux (Ubuntu 22.04 LTS recommended) or Docker Desktop on macOS/Windows
- Internet connection for initial setup and mobile sync
Pre-Deployment Checklist
Before starting, verify:
# Check Docker version (needs v25+)
docker --version
# Verify docker-compose is available
docker compose version
# Check available RAM
free -h
# Check available disk space
df -h /data/ Installation and Deployment
Step 1: Environment Preparation
Create a dedicated directory for Immich configuration:
# Create Immich directory
mkdir -p ~/immich-app
cd ~/immich-app
# Download official Docker Compose configuration
wget -O docker-compose.yml https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
# Download example environment file
wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env
# Verify downloads
ls -lah Step 2: Configure Environment Variables
Edit the .env file to customize for your setup:
nano .env Essential variables to configure:
# Storage paths - adjust to your system
UPLOAD_LOCATION=/data/immich # Where photos/videos are stored
DB_DATA_LOCATION=/data/postgres # PostgreSQL database storage
# Security - use strong password with A-Za-z0-9 only
DB_PASSWORD=YourSecurePassword123
# Timezone - set to your local timezone
TZ=America/New_York
# Machine Learning (enable for face recognition and smart search)
MACHINE_LEARNING_ENABLED=true
MACHINE_LEARNING_URL=http://immich-ml:3003
# Optional: Version pinning (recommended for production)
IMMICH_VERSION=release Important: Use a strong database password with only alphanumeric characters. Special characters can cause connection issues.
Step 3: Create Storage Directories
# Create directories with proper permissions
sudo mkdir -p /data/immich
sudo mkdir -p /data/postgres
# Set ownership (adjust user:group as needed)
sudo chown -R $USER:$USER /data/immich
sudo chmod 755 /data/immich
# PostgreSQL requires strict permissions
sudo chmod 700 /data/postgres
# Verify permissions
ls -la /data/ Step 4: Deploy Docker Services
# Start all services in detached mode
docker compose up -d
# Monitor startup (wait 2-3 minutes for database initialization)
docker compose logs -f
# Press Ctrl+C to exit log view
# Verify all containers are running
docker compose ps Expected output shows 4 services:
immich-server- Main API and web interfaceimmich-machine-learning- ML service for face recognition and searchpostgres- Databaseredis- Cache and job queue
If any container shows as unhealthy or exited:
# Check specific service logs
docker compose logs immich-server
docker compose logs postgres
# Common issue: PostgreSQL initialization takes 2-3 minutes on first run
# Wait and check again
docker compose ps Step 5: Initial Web Interface Setup
Navigate to http://localhost:2283 (or http://YOUR_SERVER_IP:2283) in your browser.
- Click “Getting Started” button
- Create admin account:
- Email:
[email protected] - Password: Use strong password (12+ characters)
- Email:
- Configure basic settings:
- Library name: “My Photo Library” (or your preference)
- Enable thumbnail generation: Yes
- Video transcoding format: H.264 (universal compatibility)
- Enable machine learning: Yes (if you have adequate RAM/GPU)
Security Note: Save your admin credentials in a password manager immediately. These credentials control API access for automation workflows.
Step 6: Configure Reverse Proxy (Production Setup)
For external access and HTTPS, configure a reverse proxy. Here’s an example using Traefik:
# Add to docker-compose.yml under immich-server:
labels:
- "traefik.enable=true"
- "traefik.http.routers.immich.rule=Host(`immich.yourdomain.com`)"
- "traefik.http.routers.immich.entrypoints=websecure"
- "traefik.http.routers.immich.tls=true"
- "traefik.http.routers.immich.tls.certresolver=letsencrypt"
- "traefik.http.services.immich.loadbalancer.server.port=3001" Benefits:
- HTTPS encryption for secure remote access
- Automatic Let’s Encrypt certificate renewal
- Custom domain access (immich.yourdomain.com)
- Mobile app can connect from anywhere
Mobile App Setup and Auto-Backup
Android Setup
Installation:
- Install from one of these sources:
- Google Play Store (search “Immich”)
- F-Droid (privacy-focused app store)
- GitHub Releases (APK direct download)
Configuration:
1. Open Immich app
2. Enter server URL: https://immich.yourdomain.com
(or http://192.168.1.100:2283 for local-only access)
3. Log in with your credentials
4. Grant permissions:
├─ Photos: Required for backup
├─ Videos: Required for video backup
└─ Location: Optional (for geotagging)
5. Navigate to Settings > Backup
6. Select albums to backup:
├─ Camera (required)
├─ Screenshots (optional)
└─ Other albums as needed
7. Choose backup mode:
├─ Foreground only (manual)
├─ Background only (automatic)
└─ Both (recommended) Critical Step: Disable Battery Optimization
Android manufacturers aggressively kill background processes. You must disable battery optimization for Immich:
Samsung:
Settings > Battery > Battery Usage
├─ Tap "Optimize battery usage"
├─ Select "All apps"
├─ Find Immich and toggle OFF
└─ Or add to "Never sleeping apps" Google Pixel:
Settings > Apps > See all apps
├─ Find Immich
├─ Permissions > Special app access
└─ Battery > Unrestricted OnePlus:
Settings > Battery > Battery Optimization
├─ Find Immich
├─ Select "Don't optimize"
└─ Or Settings > Battery > App Launch
├─ Find Immich
└─ Enable "Manage manually" with all options checked Xiaomi:
Settings > Apps > Manage Apps
├─ Find Immich
├─ Battery Saver
└─ Select "No restrictions" For device-specific instructions, visit dontkillmyapp.com and search for your manufacturer.
iOS Setup
Installation:
- Download from Apple App Store (search “Immich”)
- Or install via TestFlight for beta versions
Configuration:
1. Open Immich app
2. Enter server URL and credentials
3. Grant iOS permissions:
├─ Photos: Allow access to all photos
├─ Location Services: Optional but recommended
└─ Background App Refresh: Essential for auto-backup
4. iOS Settings > General > Background App Refresh
├─ Enable globally
└─ Enable specifically for Immich
5. Configure backup in Immich app:
├─ Settings > Backup
├─ Select albums to backup
└─ Configure backup preferences iOS Background Limitations:
iOS is more restrictive than Android for background processes:
- Requires WiFi or good battery on cellular
- Doesn’t work in Low Power Mode (unless excepted)
- App must not be force-closed
- Device should be unlocked regularly for priority background tasks
- Background sync may take longer than Android
Recommendation: Enable foreground backup as primary method, use background as supplemental.
Understanding Backup Modes
Foreground Backup:
- Activates when you open the Immich app
- Scans selected albums for new photos
- Uploads all new items immediately
- Duration: 1-5 minutes per session typical
- Best for: Initial large uploads, manual control, iOS users
Background Backup:
- Periodic scanning without opening app
- Default interval: 30 minutes (configurable: 5 min to 12 hours)
- Automatic upload of new photos
- Battery impact: Minimal (~1-2% per check)
- Best for: Continuous daily usage, set-and-forget, Android users
Duplicate Prevention:
Immich automatically prevents duplicate uploads:
- Checks file hash before uploading
- Compares creation date and file size
- Won’t re-upload files already in library
- Saves storage and bandwidth
Testing Your Setup:
# Monitor uploads on server side
docker compose logs -f immich-server | grep -i upload
# Check for errors
docker compose logs immich-server | grep -i error | tail -20 Take a test photo on your phone and verify it appears in the web interface within 1-5 minutes.
Advanced Features: Machine Learning
Face Recognition Setup
Immich’s face recognition achieves 99.8% accuracy for distinct individuals, rivaling commercial solutions.
Enable Face Recognition:
1. Web interface > Administration > Settings
2. Navigate to "Machine Learning" section
3. Enable "Facial Recognition"
4. Configure settings:
├─ Model: InsightFace (recommended)
├─ Min Score: 0.7 (default, adjust if needed)
└─ Max Distance: 0.5 (lower = stricter matching)
5. Save settings
6. Administration > Jobs > Run "Face Detection"
7. Wait for processing to complete Understanding Distance Thresholds:
- 0.3-0.4: Very strict - few false positives, may miss similar photos
- 0.5: Balanced - good for most use cases
- 0.6-0.7: Looser matching - catches more variations but more false positives
- Twins/similar faces: Start with 0.4 and adjust upward
Performance Expectations:
Without GPU (4-core CPU):
├─ 10,000 photos: 2-3 hours
├─ 50,000 photos: 10-15 hours
└─ Processing: 500ms-2s per photo
With GPU (NVIDIA GTX 1660 or better):
├─ 10,000 photos: 5-10 minutes
├─ 50,000 photos: 30-45 minutes
└─ Processing: 50-100ms per photo After Processing:
Navigate to Explore > People to see detected faces grouped by person. You can:
- Name individuals
- Merge similar face clusters
- Hide specific faces
- Set representative photos
- Create smart albums by person
Smart Search (Semantic Search)
Immich uses CLIP (Contrastive Language-Image Pre-training) for natural language image search.
Enable Smart Search:
1. Administration > Settings > Machine Learning
2. Enable "Smart Search"
3. Configure CLIP model:
├─ Model: ViT-B-32 (default, good balance)
└─ Or ViT-L-14 (better accuracy, slower)
4. Save settings
5. Administration > Jobs > Run "Smart Search"
6. Initial indexing: 2-24 hours for 10,000 photos Example Searches:
Natural Language Queries:
"sunset at the beach" → Finds sunset photos near water
"dog playing in snow" → Locates dogs in snowy settings
"mountain landscape" → Retrieves mountainous scenery
"people laughing" → Finds photos with smiling/happy people
"food on a plate" → Finds food photography
"red car" → Finds vehicles matching color
"birthday cake with candles" → Event-specific search Search Tips:
- Be specific: “golden retriever in park” vs. “dog outside”
- Combine concepts: “child playing with toy car”
- Use colors: “blue ocean sunset”
- Include actions: “hiking on mountain trail”
- Try locations: “eiffel tower at night”
Hardware Acceleration for Machine Learning
ML acceleration dramatically reduces processing time. A $200 GPU investment often pays for itself in electricity savings within 6-12 months.
NVIDIA CUDA (Most Recommended)
Requirements:
- NVIDIA GPU with compute capability 5.2+
- GTX 960 or newer, any RTX series
- NVIDIA driver version ≥ 545
- NVIDIA Container Toolkit installed
Installation (Ubuntu/Debian):
# Install NVIDIA Container Toolkit
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
sudo systemctl restart docker
# Verify GPU visible to Docker
docker run --rm --gpus all nvidia/cuda:12.0-base nvidia-smi Docker Compose Configuration:
# Edit docker-compose.yml
immich-machine-learning:
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}-cuda
environment:
- NVIDIA_VISIBLE_DEVICES=all
- NVIDIA_DRIVER_CAPABILITIES=compute,utility
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
# ... rest of configuration Apply Changes:
# Restart ML service with new configuration
docker compose down
docker compose up -d
# Verify GPU is being used
docker compose logs immich-machine-learning | grep -i cuda
# Should show CUDA initialization messages
# Monitor GPU usage during ML jobs
watch -n 1 nvidia-smi Performance Gains:
- Face detection: 10-30× faster (2-3 hours → 5-10 minutes for 10K photos)
- Semantic search: 15-50× faster
- Video transcoding: 10-20× faster with hardware encoding
Intel OpenVINO (Intel Arc/Xe GPU)
For Intel discrete GPUs:
immich-machine-learning:
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}-openvino
environment:
- GPU_DEVICE=/dev/dri/renderD128
- LIBVA_DRIVER_NAME=iHD
devices:
- /dev/dri:/dev/dri
deploy:
resources:
limits:
memory: 8G Note: OpenVINO uses more RAM than CUDA. Plan for 8GB total system memory.
AMD ROCm (AMD Radeon)
For AMD GPUs:
immich-machine-learning:
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}-rocm
devices:
- /dev/dri:/dev/dri
- /dev/kfd:/dev/kfd
environment:
- HSA_OVERRIDE_GFX_VERSION=10.3.0 # Adjust for your GPU
group_add:
- video Note: ROCm image is 35GB+. Ensure adequate disk space.
User Management and Sharing
Creating User Accounts
Method 1: Direct Admin Creation
1. Administration > User Management
2. Click "Create User"
3. Enter details:
├─ Email: [email protected]
├─ Password: (generate strong password)
├─ Name: John Doe
└─ Storage Quota: 50GB (or unlimited)
4. Assign role: Admin, User, or Viewer
5. Click "Create" Method 2: Invite Links (Recommended for Family)
1. Administration > User Management
2. Click "Create Invite Link"
3. Configure:
├─ Expiration: 24 hours to 7 days
└─ Uses: 1 (single use) or unlimited
4. Copy link and share with user
5. User registers via link User Roles:
| Role | Can Upload | Can Create Albums | Can Share | Can Admin | Use Case |
|---|---|---|---|---|---|
| Admin | Yes | Yes | Yes | Yes | Owner, maintainer |
| User | Yes | Yes | Yes | No | Family members |
| Viewer | No | No | No | No | Guest viewing only |
Album Sharing
Internal Sharing (Between Users):
1. Create or open album
2. Click "Share" button
3. Select users to share with:
├─ [email protected]
├─ [email protected]
└─ [email protected]
4. Choose permission level:
├─ Viewer: Can view and download only
└─ Editor: Can add/remove photos
5. Click "Share" Example Family Workflow:
Vacation Album: "Summer 2024 - Greece"
Share Settings:
├─ [email protected] (Editor)
│ └─ Can add their photos from trip
├─ [email protected] (Viewer)
│ └─ Can view and download
└─ [email protected] (Public Link)
└─ Password protected, 30-day expiration Partner Sharing (Full Library Access):
For trusted users (spouse, co-parent):
1. Settings > Account > Partner Sharing
2. Click "Add Partner"
3. Select user
4. Confirm
Partner can now:
├─ View your entire timeline
├─ See all your albums
├─ Access recognized faces
├─ View location data
└─ Download any photo Security Warning: Partner sharing exposes all content including locations and recognized faces. Only use with completely trusted individuals.
Public Link Sharing
Create links for external sharing (no account required):
1. Open album or select photos
2. Click "Share" > "Create Public Link"
3. Configure options:
Options Available:
├─ Allow Downloads: ON/OFF
├─ Show Metadata: ON/OFF (affects privacy)
├─ Password Protection: Optional
├─ Expiration Date: Set future date
└─ Allow Uploads: OFF (usually)
4. Copy link and share Example Secure Configuration:
Link: https://immich.yourdomain.com/share/a7f3k2m9x1q5
Settings:
├─ Password: "FamilyVacation2024!"
├─ Expiration: 30 days from now
├─ Downloads: Enabled
├─ Show Metadata: Disabled (hides locations/EXIF)
├─ Allow Uploads: Disabled
└─ Description: "Greece vacation photos for family" Visitor Capabilities:
- Browse all photos in album
- View in slideshow mode
- Download photos (if enabled)
- Share link with others
Visitor Restrictions:
- Cannot see other albums
- Cannot access faces or people data
- Cannot view library timeline
- Cannot modify or delete
AI Automation and Integration
Immich API Overview
Immich provides a comprehensive REST API for automation. Access API documentation at http://your-immich-server:2283/api-docs
Generate API Key:
1. Web interface > Account Settings
2. Navigate to "API Keys"
3. Click "Create API Key"
4. Name: "automation-scripts"
5. Copy key immediately (shown only once)
6. Store securely (password manager or secrets vault) Automated Backup Health Reporting
Monitor backup status across all devices and users:
#!/usr/bin/env python3
"""
Immich Backup Health Reporter
Checks last backup time for all users and sends alerts for stale backups
"""
import requests
import datetime
from datetime import timedelta
# Configuration
IMMICH_URL = "https://immich.yourdomain.com"
API_KEY = "your-api-key-here"
ALERT_THRESHOLD_DAYS = 7 # Alert if no backup in 7 days
headers = {
"Accept": "application/json",
"x-api-key": API_KEY
}
def check_backup_status():
# Get all users
users_response = requests.get(
f"{IMMICH_URL}/api/user",
headers=headers
)
users = users_response.json()
alerts = []
now = datetime.datetime.now()
for user in users:
user_id = user['id']
email = user['email']
# Get user's latest asset
assets_response = requests.get(
f"{IMMICH_URL}/api/asset",
headers=headers,
params={"userId": user_id, "order": "desc", "take": 1}
)
if assets_response.status_code == 200:
assets = assets_response.json()
if assets:
last_backup = datetime.datetime.fromisoformat(
assets[0]['createdAt'].replace('Z', '+00:00')
)
days_since_backup = (now - last_backup).days
if days_since_backup > ALERT_THRESHOLD_DAYS:
alerts.append({
'user': email,
'days': days_since_backup,
'last_backup': last_backup.strftime('%Y-%m-%d')
})
return alerts
def send_alerts(alerts):
if not alerts:
print("All backups current!")
return
print(f"⚠️ {len(alerts)} user(s) with stale backups:")
for alert in alerts:
print(f" - {alert['user']}: {alert['days']} days since last backup")
print(f" Last backup: {alert['last_backup']}")
# Integrate with notification service:
# - Send email via SendGrid/SMTP
# - Push to Slack/Discord
# - Create GitHub issue
# - Send mobile push notification
if __name__ == "__main__":
alerts = check_backup_status()
send_alerts(alerts) Schedule with Cron:
# Run daily at 8 AM
0 8 * * * /usr/local/bin/immich-backup-check.py >> /var/log/immich-backup.log 2>&1 Smart Album Creation Automation
Automatically create albums based on ML search results:
#!/usr/bin/env python3
"""
Immich Smart Album Creator
Creates albums automatically based on semantic search queries
"""
import requests
from typing import List
IMMICH_URL = "https://immich.yourdomain.com"
API_KEY = "your-api-key-here"
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
"x-api-key": API_KEY
}
def search_photos(query: str) -> List[str]:
"""Search for photos matching semantic query"""
response = requests.get(
f"{IMMICH_URL}/api/search/metadata",
headers=headers,
params={"q": query, "type": "IMAGE"}
)
assets = response.json()['assets']['items']
return [asset['id'] for asset in assets]
def create_album(name: str, description: str, asset_ids: List[str]):
"""Create album with specified photos"""
payload = {
"albumName": name,
"description": description,
"assetIds": asset_ids
}
response = requests.post(
f"{IMMICH_URL}/api/album",
headers=headers,
json=payload
)
return response.json()
def create_smart_albums():
"""Create predefined smart albums"""
smart_album_definitions = [
{
"query": "sunset at the beach",
"name": "🌅 Beach Sunsets",
"description": "Beautiful sunset photos taken at the beach"
},
{
"query": "dog playing outdoor",
"name": "🐕 Dog Adventures",
"description": "Our furry friend's outdoor activities"
},
{
"query": "birthday cake with candles",
"name": "🎂 Birthday Celebrations",
"description": "Birthday parties and celebrations"
},
{
"query": "mountain landscape hiking",
"name": "⛰️ Mountain Hikes",
"description": "Hiking adventures in the mountains"
},
{
"query": "food on plate restaurant",
"name": "🍽️ Food & Dining",
"description": "Memorable meals and culinary experiences"
}
]
for album_def in smart_album_definitions:
print(f"Creating album: {album_def['name']}")
# Search for matching photos
asset_ids = search_photos(album_def['query'])
if len(asset_ids) > 0:
album = create_album(
album_def['name'],
album_def['description'],
asset_ids
)
print(f" ✓ Created with {len(asset_ids)} photos")
else:
print(f" ✗ No matching photos found")
if __name__ == "__main__":
create_smart_albums() Run Monthly:
# Create/update smart albums monthly
0 0 1 * * /usr/local/bin/create-smart-albums.py Automated Face Recognition Naming
Use external face recognition APIs to suggest names:
#!/usr/bin/env python3
"""
Immich Face Auto-Naming
Suggests names for detected faces based on existing labeled photos
"""
import requests
import json
IMMICH_URL = "https://immich.yourdomain.com"
API_KEY = "your-api-key-here"
def get_unnamed_faces():
"""Retrieve all detected faces without names"""
response = requests.get(
f"{IMMICH_URL}/api/person",
headers={"x-api-key": API_KEY}
)
people = response.json()
return [p for p in people if not p.get('name')]
def suggest_name_for_face(person_id: str):
"""
Analyze face cluster and suggest name based on:
- Most common metadata patterns
- Date ranges (frequent in certain time periods)
- Co-occurrence with other named faces
"""
# Get all photos containing this person
response = requests.get(
f"{IMMICH_URL}/api/person/{person_id}",
headers={"x-api-key": API_KEY}
)
person_data = response.json()
assets = person_data.get('assets', [])
# Analyze patterns
date_ranges = analyze_date_clusters(assets)
co_occurrences = find_co_occurring_people(assets)
# Generate suggestion
suggestion = {
'person_id': person_id,
'confidence': 0.0,
'suggested_name': None,
'reasoning': []
}
# Add your suggestion logic here
# Example: "Appears in 50 photos from 2020-2023 with 'John Doe'"
return suggestion
def analyze_date_clusters(assets):
"""Find temporal patterns in photos"""
# Implementation here
pass
def find_co_occurring_people(assets):
"""Find other named people appearing with this person"""
# Implementation here
pass
if __name__ == "__main__":
unnamed_faces = get_unnamed_faces()
print(f"Found {len(unnamed_faces)} unnamed face clusters")
for face in unnamed_faces:
suggestion = suggest_name_for_face(face['id'])
if suggestion['suggested_name']:
print(f"Suggest naming person {face['id']} as: {suggestion['suggested_name']}")
print(f" Confidence: {suggestion['confidence']:.1%}")
print(f" Reasoning: {', '.join(suggestion['reasoning'])}") Webhook Integration for Real-Time Events
Set up webhooks to react to Immich events:
// Express.js webhook receiver
const express = require('express');
const app = express();
app.use(express.json());
// Immich webhook endpoint
app.post('/webhook/immich', async (req, res) => {
const event = req.body;
switch(event.type) {
case 'asset.upload':
await handleNewUpload(event.data);
break;
case 'album.create':
await handleNewAlbum(event.data);
break;
case 'user.create':
await handleNewUser(event.data);
break;
}
res.status(200).send('OK');
});
async function handleNewUpload(data) {
console.log(`New upload from user ${data.userId}`);
// Examples:
// - Trigger ML processing immediately
// - Notify family members of new photos
// - Auto-add to shared family album
// - Generate thumbnail for external services
// - Update backup statistics dashboard
}
async function handleNewAlbum(data) {
console.log(`New album created: ${data.albumName}`);
// Examples:
// - Send notification to shared users
// - Create calendar event for album date
// - Generate album preview image
// - Update photo statistics
}
async function handleNewUser(data) {
console.log(`New user registered: ${data.email}`);
// Examples:
// - Send welcome email with setup instructions
// - Create default albums ("Favorites", "Family")
// - Set up storage quota
// - Add to family sharing group
}
app.listen(3000, () => {
console.log('Webhook receiver listening on port 3000');
}); Automated External Library Scanning
Trigger library scans when files change:
#!/bin/bash
# Watch directory and trigger Immich scan on changes
WATCH_DIR="/mnt/nas/photos"
IMMICH_URL="https://immich.yourdomain.com"
API_KEY="your-api-key-here"
LIBRARY_ID="your-library-id"
# Requires: inotify-tools
# Install: sudo apt-get install inotify-tools
inotifywait -m -r -e create,modify,delete,move "$WATCH_DIR" | while read path action file; do
echo "$(date): Detected $action on $file in $path"
# Wait 30 seconds to batch multiple changes
sleep 30
# Trigger Immich library scan
curl -X POST "${IMMICH_URL}/api/library/${LIBRARY_ID}/scan" -H "x-api-key: ${API_KEY}" -H "Content-Type: application/json"
echo "Library scan triggered"
done Run as systemd service:
# /etc/systemd/system/immich-watch.service
[Unit]
Description=Immich External Library Watcher
After=network.target
[Service]
Type=simple
User=immich
ExecStart=/usr/local/bin/immich-watch.sh
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target sudo systemctl enable immich-watch
sudo systemctl start immich-watch Troubleshooting Common Issues
Container Won’t Start
Symptoms: docker compose up -d fails or containers exit immediately
Diagnostics:
# Check all container logs
docker compose logs
# Check specific service
docker compose logs postgres
docker compose logs immich-server
# Check container status
docker compose ps Common Solutions:
# Issue: Database initialization
# Solution: Wait 2-3 minutes, PostgreSQL takes time on first run
sleep 180
docker compose ps
# Issue: Permission denied on /data/postgres
sudo chmod 700 /data/postgres
sudo chown -R 999:999 /data/postgres # PostgreSQL UID:GID
docker compose restart postgres
# Issue: Port 2283 already in use
sudo netstat -tlnp | grep 2283
# Kill conflicting process or change port in .env
# Issue: Disk space
df -h /data/
# Free up space if needed
# Nuclear option: Reset everything (destroys data!)
docker compose down -v
sudo rm -rf /data/postgres/*
docker compose up -d Out of Memory Errors
Symptoms: ML jobs crash, containers restart, web interface slow
Diagnostics:
# Check memory usage
free -h
docker stats
# Check ML service specifically
docker stats immich-machine-learning Solutions:
# Reduce ML concurrency
# Edit docker-compose.yml
environment:
- MACHINE_LEARNING_WORKERS=1 # Reduce from default 2-4
# Disable unused ML features
# In web UI: Administration > Settings > Machine Learning
# Disable: Smart Search (if not using)
# Disable: Face Recognition (if not using)
# Add swap space (temporary solution)
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile Mobile Backup Not Working
Android:
# Check server logs for connection attempts
docker compose logs -f immich-server | grep -i upload
# Common issues checklist:
# [ ] Battery optimization disabled for Immich
# [ ] Background data allowed for Immich
# [ ] WiFi/cellular permissions granted
# [ ] Server URL correct (https if remote)
# [ ] Foreground backup works (test server connectivity)
# Test server connectivity from phone:
# Open browser on phone, navigate to https://immich.yourdomain.com
# Should load without certificate warnings iOS:
# Check same server logs
docker compose logs -f immich-server | grep -i upload
# iOS-specific checklist:
# [ ] Background App Refresh enabled globally
# [ ] Background App Refresh enabled for Immich specifically
# [ ] Not in Low Power Mode
# [ ] App not force-closed recently
# [ ] Location Services enabled (if photo library requires it)
# Test:
# 1. Open Immich app
# 2. Take test photo
# 3. Wait 30 seconds with app in foreground
# 4. Photo should appear in web interface Face Recognition Not Working
Symptoms: No faces detected, or job stuck at 0%
Diagnostics:
# Check ML service logs
docker compose logs immich-machine-learning
# Check job status
# Web UI: Administration > Jobs > Face Detection
# Verify ML service is running
docker compose ps immich-machine-learning Solutions:
# Restart ML service
docker compose restart immich-machine-learning
# Check ML service has adequate resources
docker stats immich-machine-learning
# Should show memory usage, CPU usage
# Enable GPU if available (see ML Acceleration section)
# Reduce concurrency if out of memory
# Administration > Settings > Machine Learning
# Set "Face Recognition Concurrency" to 1
# Check specific error in logs
docker compose logs immich-machine-learning | grep -i error | tail -20 External Library Files Not Appearing
Symptoms: External library shows 0 photos, or files missing
Diagnostics:
# Verify mount in running container
docker compose exec immich-server ls -la /external/
# Check file permissions
ls -la /path/to/external/photos
# Check Immich scan logs
docker compose logs immich-server | grep -i library Solutions:
# Fix permissions
sudo chmod -R u+r /path/to/external/photos
sudo chown -R $USER:$USER /path/to/external/photos
# Verify docker-compose.yml mount
# Should have line like:
# - /path/to/external:/external/photos:ro
# Manual scan trigger
# Web UI: Administration > Jobs > Scan External Library
# Or via API:
curl -X POST "http://localhost:2283/api/library/{libraryId}/scan" -H "x-api-key: YOUR_API_KEY" Slow Web Interface
Symptoms: Pages load slowly, thumbnails don’t appear, timeouts
Diagnostics:
# Check resource usage
docker stats
# Check database connections
docker compose exec postgres psql -U postgres -d immich -c "SELECT count(*) FROM pg_stat_activity;"
# Check disk I/O
iostat -x 1
# Check logs for errors
docker compose logs immich-server | grep -i error Solutions:
# Increase database connection pool
# Edit docker-compose.yml
environment:
- DB_POOL_MAX=20 # Increase from default
# Vacuum database (cleanup)
docker compose exec postgres vacuumdb -U postgres -d immich -v
# Clear browser cache
# In browser: Ctrl+Shift+Del, clear cache
# Restart services
docker compose restart
# Check network speed
# If remote: Test bandwidth to server
speedtest-cli
# Reduce thumbnail quality to save space/speed
# Administration > Settings > Storage Template
# Lower thumbnail quality setting Performance Optimization
Thumbnail Generation
# Administration > Settings > Thumbnail Settings
Recommended Settings:
├─ Format: WebP (best compression)
├─ Quality: 80 (good balance)
├─ Preview Size: 1920x1080
├─ Thumbnail Size: 250x250
└─ Generate Colorful Thumbnail: Enabled
Storage Impact:
├─ 10,000 photos ≈ 2-4GB thumbnails
├─ 50,000 photos ≈ 10-20GB thumbnails
└─ Plan for 10-20% overhead Video Transcoding
# Administration > Settings > Video Transcoding
Recommended Settings (Universal Compatibility):
├─ Codec: H.264
├─ Preset: Balanced
├─ CRF: 23 (default quality)
├─ Target Resolution: Original (maintain quality)
└─ Two-Pass Encoding: Disabled (faster)
Recommended Settings (Better Compression):
├─ Codec: H.265/HEVC
├─ Preset: Slow (better compression)
├─ CRF: 28 (slightly lower quality, much smaller files)
├─ Target Resolution: 1080p (if originals are 4K)
└─ Two-Pass Encoding: Enabled (highest quality)
Hardware Acceleration (NVIDIA):
├─ Enable Hardware Acceleration: Yes
├─ Hardware Acceleration API: NVENC
└─ Performance: 10-20× faster than software encoding Database Maintenance
# Weekly database vacuum (cleanup deleted rows)
0 2 * * 0 docker compose exec -T postgres vacuumdb -U postgres -d immich -v
# Monthly full vacuum (reclaim space)
0 3 1 * * docker compose exec -T postgres vacuumdb -U postgres -d immich -v --full
# Check database size
docker compose exec postgres psql -U postgres -d immich -c "SELECT pg_size_pretty(pg_database_size('immich'));"
# Clear old jobs history
# Administration > Jobs > Clear Completed Jobs Next Steps and Related Guides
Immediate Enhancements
Set Up Automated Backups
- PostgreSQL database exports daily
- Photo library backup to external drive/NAS
- Test restore procedures quarterly
- See: Database Backup Guide
Configure Reverse Proxy
- Enable HTTPS with Let’s Encrypt
- Set up custom domain
- Configure firewall rules
- See: Traefik Reverse Proxy Guide
Migrate from Google Photos
- Export Google Takeout
- Use immich-go CLI tool
- Preserve albums and metadata
- See: Google Photos Migration Guide
Enable Monitoring
- Disk space alerts
- Backup success notifications
- ML job completion tracking
- See: Homelab Monitoring Guide
Advanced Topics
Multi-Server Deployment:
- Separate ML processing server
- Load-balanced web frontends
- Distributed PostgreSQL with replication
Custom ML Models:
- Train custom face recognition models
- Specialized object detection (pets, cars, etc.)
- Custom CLIP fine-tuning for specific photo types
Integration Projects:
- Photo frame digital display
- Automated yearly photo books
- Social media cross-posting
- Calendar integration with photo dates
Community Resources
- Official Documentation: immich.app/docs
- GitHub Repository: github.com/immich-app/immich
- Discord Community: 50,000+ members, active support
- Reddit: r/selfhosted, r/homelab discussion threads
- Hardware Database: Community-maintained compatibility list
Conclusion
Immich represents a mature, production-ready alternative to Google Photos that prioritizes privacy, data ownership, and user control. With stable 2.0+ releases and active FUTO-backed development, it’s an excellent long-term investment for homelab enthusiasts and privacy-conscious families.
Key Achievements After This Guide:
- Self-hosted photo platform with Google Photos-level features
- Automated mobile backup from all family devices
- 99.8% accurate face recognition and semantic search
- Complete privacy with all processing on your hardware
- One-time cost breaking even with cloud services in 6-12 months
Success Metrics (First Week):
- Web interface accessible and responsive
- All family members’ mobile apps backing up successfully
- Face recognition completed initial library scan
- At least one shared album created and tested
- Backup health monitoring script running
Long-Term Benefits:
- Zero recurring costs after initial hardware investment
- Storage scales with your needs (add drives as needed)
- Complete data portability (never locked into platform)
- Privacy assured (no cloud provider access)
- Active development community ensuring longevity
Start with the basic Docker deployment, add family members gradually, then enable ML features as you become comfortable with the platform. Immich’s combination of ease-of-use and powerful features makes it accessible to beginners while satisfying advanced users’ needs.
Welcome to true photo ownership!
Document Version: 1.0 Last Updated: December 2025 Word Count: ~5,200 words Immich Version: v2.3.1 (latest stable)